summaryrefslogtreecommitdiffstats
path: root/aai-core/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'aai-core/src/main/java')
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/audit/ListEndpoints.java302
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/db/props/AAIProperties.java38
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/db/schema/AuditDoc.java89
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/db/schema/AuditOXM.java248
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/db/schema/AuditTitan.java127
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/db/schema/Auditor.java54
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/db/schema/AuditorFactory.java47
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/db/schema/CompareByName.java36
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/db/schema/DBIndex.java105
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/db/schema/DBProperty.java85
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/db/schema/EdgeProperty.java69
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/db/schema/ManageTitanSchema.java329
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/db/schema/Named.java31
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/db/schema/ScriptDriver.java95
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/dbgen/DataGrooming.java2223
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/dbgen/DbMeth.java3643
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/dbgen/GenTester.java123
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/dbgen/PropertyLimitDesc.java27
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/dbgen/SchemaGenerator.java168
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/dbgraphgen/DbSearchWithTags.java366
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/dbmap/AAIGraph.java187
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/dbmap/DBConnectionType.java26
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/dbmodel/DbEdgeRules.java472
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/dbmodel/v8/gen/DbEdgeRules.java300
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/dbmodel/v9/gen/DbEdgeRules.java459
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResource.java675
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResourceKey.java103
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResourceKeys.java40
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResources.java86
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/notificationEvent/NotificationEvent.java564
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/notificationEvent/ObjectFactory.java77
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessage.java125
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessageData.java78
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessageDatum.java81
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessages.java118
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/package-info.java32
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/Fault.java382
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/ObjectFactory.java95
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/PolicyException.java134
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/RESTResponse.java86
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/RequestError.java87
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/restResponseInfo/Info.java385
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/restResponseInfo/ObjectFactory.java95
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/Fault.java382
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/ObjectFactory.java95
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/RESTResponse.java86
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/RequestError.java86
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/ServiceException.java134
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/translog/TransactionLogEntries.java131
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/domain/translog/TransactionLogEntry.java438
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/exceptions/AAIException.java146
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/exceptions/AAIExceptionWithInfo.java134
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/ingestModel/ConvertXmlToJsonMoxyOxm.java105
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/ingestModel/CreateWidgetModels.java168
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/ingestModel/DbMaps.java64
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/ingestModel/IngestModelListener.java83
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/ingestModel/IngestModelMoxyOxm.java862
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/Introspector.java616
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/IntrospectorFactory.java65
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/IntrospectorWalker.java193
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/JSONStrategy.java360
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/Loader.java112
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/LoaderFactory.java44
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/MarshallerProperties.java139
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/ModelInjestor.java176
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/ModelType.java25
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/MoxyLoader.java190
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/MoxyStrategy.java394
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/PojoInjestor.java69
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/PojoLoader.java136
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/PojoStrategy.java389
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/PropertyPredicate.java28
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/PropertyPredicates.java77
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/Version.java27
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/Visibility.java29
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/Wanderer.java83
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/exceptions/AAIUnknownObjectException.java42
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/exceptions/AAIUnmarshallingException.java42
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/generator/CreateExample.java170
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataCopy.java91
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataLinkReader.java97
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataLinkWriter.java111
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffect.java133
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffectRunner.java99
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffectRunnerHelper.java85
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/exceptions/AAIMissingRequiredPropertyException.java45
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/exceptions/AAIMultiplePropertiesException.java44
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/tools/CreateUUID.java49
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/tools/DefaultFields.java48
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/tools/InjectKeysFromURI.java69
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/tools/IntrospectorValidator.java314
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/tools/Issue.java144
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/tools/IssueResolver.java33
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/tools/IssueType.java25
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/tools/RemoveNonVisibleProperty.java36
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/introspection/tools/Severity.java27
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/CNName.java93
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/CustomLogPatternLayout.java28
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/CustomLogPatternLayoutEncoder.java40
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/DME2RestFlag.java55
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/EcompElapsedTime.java66
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/EcompEncoder.java38
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/EcompPatternLayout.java31
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/EcompStartTime.java38
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/EelfClassOfCaller.java43
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/ErrorLogHelper.java587
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/ErrorObject.java308
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/ErrorObjectFormatException.java30
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/ErrorObjectNotFoundException.java51
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/LogFormatTools.java45
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/LoggingContext.java299
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/LoggingContextNotExistsException.java26
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/StopWatch.java41
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/logging/StopWatchNotStartedException.java42
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/exceptions/AAIIdentityMapParseException.java41
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/exceptions/AmbiguousMapAAIException.java41
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/query/LegacyQueryParser.java233
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/query/ObjectNameQueryParser.java36
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/query/QueryParser.java145
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/query/QueryParserStrategy.java92
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/query/RelationshipQueryParser.java70
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/query/TraversalStrategy.java83
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueRelationshipQueryParser.java57
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueStrategy.java82
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueURIQueryParser.java171
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/relationship/RelationshipToURI.java284
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/uri/Parsable.java72
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIParser.java249
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToDBKey.java127
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToExtensionInformation.java169
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToObject.java229
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToRelationshipObject.java171
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIValidate.java62
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/query/builder/GraphTraversalBuilder.java491
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinPipelineBuilder.java214
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinPipelineTraversal.java76
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinQueryBuilder.java416
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinTraversal.java137
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinUnique.java137
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/query/builder/QueryBuilder.java293
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/query/builder/TraversalQuery.java150
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/restcore/CustomJacksonJaxBJsonProvider.java71
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/restcore/HttpMethod.java33
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/restcore/JettyObfuscationConversionCommandLineUtil.java97
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/restcore/MediaType.java66
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/restcore/RESTAPI.java343
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/restcore/search/GremlinGroovyShellSingleton.java88
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/restcore/util/GenerateEdgeRules.java154
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/restcore/util/URITools.java113
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/db/DBSerializer.java1484
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/db/DeleteSemantic.java40
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRule.java202
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRules.java379
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeType.java26
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/db/GetAllPool.java46
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/db/GraphSingleton.java69
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/db/LegacyDBSerializer.java35
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/db/MultiplicityRule.java28
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/db/TitanGraphSingleton.java38
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/db/exceptions/NoEdgeRuleFoundException.java40
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/engines/QueryStyle.java25
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/engines/TitanDBEngine.java103
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/engines/TransactionalGraphEngine.java234
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/GraphTraversalQueryEngine.java170
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/GremlinPipelineQueryEngine.java185
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/QueryEngine.java92
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Console.java42
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Format.java29
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/FormatFactory.java72
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/FormatMapper.java31
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Formatter.java75
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/GraphSON.java63
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/IdURL.java71
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/PathedURL.java70
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Resource.java142
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/SimpleFormat.java114
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/SubGraphStyle.java27
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/exceptions/AAIFormatVertexException.java40
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/utils/UrlBuilder.java74
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/tinkerpop/TreeBackedEdge.java80
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/serialization/tinkerpop/TreeBackedVertex.java166
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/tasks/ScheduledTasks.java90
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/AAIApiServerURLBase.java80
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/AAIApiVersion.java74
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/AAICSVWriter.java167
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/AAIConfig.java265
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/AAIConfigCommandLinePropGetter.java66
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/AAIConstants.java153
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/AAIMechIdConfig.java129
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/AAIRSyncUtility.java197
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/AAITxnLog.java501
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/AAIUtils.java54
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/Entity.java196
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/EntityList.java112
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/FileWatcher.java59
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/GenerateXsd.java1672
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/HbaseSaltPrefixer.java60
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/KeyValueList.java138
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/MapperUtil.java115
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/PojoUtils.java738
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/Request.java160
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/RestObject.java46
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/RestURLEncoder.java41
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/util/UniquePropertyCheck.java264
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/workarounds/LegacyURITransformer.java93
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/workarounds/NamingExceptions.java79
-rw-r--r--aai-core/src/main/java/org/openecomp/aai/workarounds/RemoveDME2QueryParams.java65
207 files changed, 37722 insertions, 0 deletions
diff --git a/aai-core/src/main/java/org/openecomp/aai/audit/ListEndpoints.java b/aai-core/src/main/java/org/openecomp/aai/audit/ListEndpoints.java
new file mode 100644
index 00000000..acf2be1a
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/audit/ListEndpoints.java
@@ -0,0 +1,302 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.audit;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang.StringUtils;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.LoaderFactory;
+import org.openecomp.aai.introspection.ModelType;
+import org.openecomp.aai.introspection.Version;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.base.CaseFormat;
+
+/**
+ * The Class ListEndpoints.
+ */
+public class ListEndpoints {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ListEndpoints.class);
+
+ private final String start = "inventory";
+ private final String[] blacklist = { "search", "aai-internal" };
+
+ private List<String> endpoints = new ArrayList<>();
+ private Map<String, String> endpointToLogicalName = new HashMap<String, String>();
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+ ListEndpoints endPoints = new ListEndpoints(AAIProperties.LATEST);
+
+ System.out.println(endPoints.toString("relationship-list"));
+
+ }
+
+ /**
+ * Instantiates a new list endpoints.
+ *
+ * @param version the version
+ */
+ public ListEndpoints(Version version) {
+
+ Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, version);
+
+ try {
+ final Introspector start = loader.introspectorFromName(this.start);
+ Set<String> startMap = new HashSet<>();
+ beginAudit(start, "/aai/" + version, startMap);
+ } catch (AAIUnknownObjectException e) {
+ throw new RuntimeException("Failed to find object " + this.start + ", cannot run ListEndpoints audit");
+ }
+ }
+
+ /**
+ * Begin audit.
+ *
+ * @param obj the obj
+ * @param uri the uri
+ */
+ private void beginAudit(Introspector obj, String uri, Set<String> visited) {
+
+ String currentUri = "";
+
+ if (!obj.getDbName().equals("inventory")) {
+ currentUri = uri + obj.getGenericURI();
+ } else {
+ currentUri = uri;
+ }
+ if (obj.getName().equals("relationship-data") || obj.getName().equals("related-to-property")) {
+ return;
+ }
+ if (!obj.isContainer()) {
+ endpoints.add(currentUri);
+ }
+
+ String dbName = obj.getDbName();
+
+ populateLogicalName(obj, uri, currentUri);
+
+ Set<String> properties = obj.getProperties();
+ Set<String> props = new LinkedHashSet<>(properties);
+ if (obj.isContainer()) {
+ for (String key : visited) {
+ if (props.remove(key)) {
+ try {
+ endpoints.add(currentUri + obj.getLoader().introspectorFromName(key).getGenericURI());
+ } catch (AAIUnknownObjectException e) {
+ LOGGER.warn("Skipping endpoint for " + key + " (Unknown object)", e);
+ }
+ }
+ }
+ }
+
+ outer: for (String propName : props) {
+
+ for (String item : blacklist) {
+ if (propName.equals(item)) {
+ continue outer;
+ }
+ }
+ if (obj.isListType(propName)) {
+ if (obj.isComplexGenericType(propName)) {
+ try {
+ final Introspector nestedObj = obj.newIntrospectorInstanceOfNestedProperty(propName);
+ Set<String> newVisited = new HashSet<>();
+ newVisited.addAll(visited);
+ newVisited.add(nestedObj.getDbName());
+ beginAudit(
+ nestedObj,
+ currentUri,
+ newVisited
+ );
+ } catch (AAIUnknownObjectException e) {
+ LOGGER.warn("Skipping nested endpoint for " + propName + " (Unknown Object)", e);
+ }
+ }
+ } else if (obj.isComplexType(propName)) {
+ try {
+ final Introspector nestedObj = obj.newIntrospectorInstanceOfProperty(propName);
+ Set<String> newVisited = new HashSet<>();
+ newVisited.addAll(visited);
+ newVisited.add(nestedObj.getDbName());
+ beginAudit(nestedObj,
+ currentUri,
+ visited
+ );
+ } catch (AAIUnknownObjectException e) {
+ LOGGER.warn("Skipping nested enpoint for " + propName + " (Unknown Object)", e);
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Populate logical name.
+ *
+ * @param obj the obj
+ * @param uri the uri
+ * @param currentUri the current uri
+ */
+ private void populateLogicalName(Introspector obj, String uri, String currentUri) {
+
+ if (obj.getDbName().equals("inventory") || currentUri.split("/").length <= 4 || currentUri.endsWith("relationship-list")) {
+ return;
+ }
+
+ if (uri.endsWith("/relationship-list")) {
+ uri = uri.substring(0, uri.lastIndexOf("/"));
+ }
+
+ String logicalName = "";
+ String keys = "";
+
+
+ if (!obj.getAllKeys().isEmpty()) {
+
+ Pattern p = Pattern.compile("/\\{[\\w\\d\\-]+\\}/\\{[\\w\\d\\-]+\\}+$");
+ Matcher m = p.matcher(currentUri);
+
+ if (m.find()) {
+ keys = StringUtils.join(obj.getAllKeys(), "-and-");
+ } else {
+ keys = StringUtils.join(obj.getAllKeys(), "-or-");
+ }
+ keys = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, keys);
+ if (!keys.isEmpty()) {
+ keys = "With" + keys;
+ }
+ }
+
+ logicalName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, obj.getDbName()) + keys;
+
+ if (endpointToLogicalName.containsKey(uri) && uri.endsWith("}")) {
+ logicalName = logicalName + "From" + endpointToLogicalName.get(uri);
+ } else if (endpointToLogicalName.containsKey(uri.substring(0, uri.lastIndexOf("/")))) {
+ logicalName = logicalName + "From" + endpointToLogicalName.get(uri.substring(0, uri.lastIndexOf("/")));
+ }
+
+ endpointToLogicalName.put(currentUri, logicalName);
+
+ }
+
+ /**
+ * Gets the logical names.
+ *
+ * @return the logical names
+ */
+ public Map<String, String> getLogicalNames() {
+
+ return endpointToLogicalName;
+
+ }
+
+ /**
+ * Gets the endpoints.
+ *
+ * @return the endpoints
+ */
+ public List<String> getEndpoints() {
+
+ return this.getEndpoints("");
+
+ }
+
+ /**
+ * Gets the endpoints.
+ *
+ * @param filterOut the filter out
+ * @return the endpoints
+ */
+ public List<String> getEndpoints(String filterOut) {
+ List<String> result = new ArrayList<>();
+ Pattern p = null;
+ Matcher m = null;
+ if (!filterOut.equals("")) {
+ p = Pattern.compile(filterOut);
+ m = null;
+ }
+ for (String s : endpoints) {
+ if (p != null) {
+ m = p.matcher(s);
+ if (m.find()) {
+ continue;
+ }
+ }
+
+ result.add(s);
+ }
+
+ return result;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (String s : endpoints) {
+ sb.append(s + "\n");
+ }
+ return sb.toString();
+
+ }
+
+ /**
+ * To string.
+ *
+ * @param filterOut the filter out
+ * @return the string
+ */
+ public String toString(String filterOut) {
+ StringBuilder sb = new StringBuilder();
+ Pattern p = Pattern.compile(filterOut);
+ Matcher m = null;
+ for (String s : endpoints) {
+ m = p.matcher(s);
+ if (!m.find()) {
+ sb.append(s + "\n");
+ }
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/db/props/AAIProperties.java b/aai-core/src/main/java/org/openecomp/aai/db/props/AAIProperties.java
new file mode 100644
index 00000000..17f1fef0
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/db/props/AAIProperties.java
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.db.props;
+
+import org.openecomp.aai.introspection.Version;
+
+public class AAIProperties {
+ public static final String NODE_TYPE = "aai-node-type";
+ public static final String LAST_MOD_SOURCE_OF_TRUTH = "last-mod-source-of-truth";
+ public static final String SOURCE_OF_TRUTH = "source-of-truth";
+ public static final String LAST_MOD_TS = "aai-last-mod-ts";
+ public static final String UNIQUE_KEY = "aai-unique-key";
+ public static final String CREATED_TS = "aai-created-ts";
+ public static final String RESOURCE_VERSION = "resource-version";
+ public static final String AAI_URI = "aai-uri";
+ public static final Version LATEST = Version.v10;
+ public static final Integer MAXIMUM_DEPTH = 10000;
+ public static final String LINKED = "linked";
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditDoc.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditDoc.java
new file mode 100644
index 00000000..02606334
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditDoc.java
@@ -0,0 +1,89 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.db.schema;
+
+import java.util.List;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+public class AuditDoc {
+
+ private List<DBProperty> properties;
+ private List<DBIndex> indexes;
+ private List<EdgeProperty> edgeLabels;
+
+ /**
+ * Gets the properties.
+ *
+ * @return the properties
+ */
+ public List<DBProperty> getProperties() {
+ return properties;
+ }
+
+ /**
+ * Sets the properties.
+ *
+ * @param properties the new properties
+ */
+ public void setProperties(List<DBProperty> properties) {
+ this.properties = properties;
+ }
+
+ /**
+ * Gets the indexes.
+ *
+ * @return the indexes
+ */
+ public List<DBIndex> getIndexes() {
+ return indexes;
+ }
+
+ /**
+ * Sets the indexes.
+ *
+ * @param indexes the new indexes
+ */
+ public void setIndexes(List<DBIndex> indexes) {
+ this.indexes = indexes;
+ }
+
+ /**
+ * Gets the edge labels.
+ *
+ * @return the edge labels
+ */
+ @JsonProperty("edge-labels")
+ public List<EdgeProperty> getEdgeLabels() {
+ return edgeLabels;
+ }
+
+ /**
+ * Sets the edge labels.
+ *
+ * @param edgeLabels the new edge labels
+ */
+ public void setEdgeLabels(List<EdgeProperty> edgeLabels) {
+ this.edgeLabels = edgeLabels;
+ }
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditOXM.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditOXM.java
new file mode 100644
index 00000000..2da74d86
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditOXM.java
@@ -0,0 +1,248 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.db.schema;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.dbmodel.DbEdgeRules;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.LoaderFactory;
+import org.openecomp.aai.introspection.ModelType;
+import org.openecomp.aai.introspection.Version;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.schema.enums.ObjectMetadata;
+import org.openecomp.aai.util.AAIConstants;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.collect.Multimap;
+import com.thinkaurelius.titan.core.Cardinality;
+import com.thinkaurelius.titan.core.Multiplicity;
+import com.thinkaurelius.titan.core.schema.SchemaStatus;
+
+public class AuditOXM extends Auditor {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AuditOXM.class);
+
+ private Set<Introspector> allObjects;
+
+ /**
+ * Instantiates a new audit OXM.
+ *
+ * @param version the version
+ */
+ public AuditOXM(Version version) {
+ Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, version);
+ Set<String> objectNames = getAllObjects(version);
+ allObjects = new HashSet<>();
+ for (String key : objectNames) {
+ try {
+ final Introspector temp = loader.introspectorFromName(key);
+ allObjects.add(temp);
+ this.createDBProperties(temp);
+ } catch (AAIUnknownObjectException e) {
+ LOGGER.warn("Skipping audit for object " + key + " (Unknown Object)", e);
+ }
+ }
+ for (Introspector temp : allObjects) {
+ this.createDBIndexes(temp);
+ }
+ createEdgeLabels();
+
+ }
+
+ /**
+ * Gets the all objects.
+ *
+ * @param version the version
+ * @return the all objects
+ */
+ private Set<String> getAllObjects(Version version) {
+ String fileName = AAIConstants.AAI_HOME_ETC_OXM + "aai_oxm_" + version.toString() + ".xml";
+ Set<String> result = new HashSet<>();
+ DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+ try {
+ docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
+ Document doc = docBuilder.parse(fileName);
+ NodeList list = doc.getElementsByTagName("java-type");
+ for (int i = 0; i < list.getLength(); i++) {
+ result.add(list.item(i).getAttributes().getNamedItem("name").getNodeValue());
+ }
+ } catch (ParserConfigurationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (SAXException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ result.remove("EdgePropNames");
+ return result;
+
+ }
+
+ /**
+ * Creates the DB properties.
+ *
+ * @param temp the temp
+ */
+ private void createDBProperties(Introspector temp) {
+ Set<String> objectProperties = temp.getProperties();
+
+ for (String prop : objectProperties) {
+ if (!properties.containsKey(prop)) {
+ DBProperty dbProperty = new DBProperty();
+ dbProperty.setName(prop);
+ if (temp.isListType(prop)) {
+ dbProperty.setCardinality(Cardinality.SET);
+ if (temp.isSimpleGenericType(prop)) {
+ Class<?> clazz = null;
+ try {
+ clazz = Class.forName(temp.getGenericType(prop));
+ } catch (ClassNotFoundException e) {
+ clazz = Object.class;
+ }
+ dbProperty.setTypeClass(clazz);
+ properties.put(prop, dbProperty);
+ }
+ } else {
+ dbProperty.setCardinality(Cardinality.SINGLE);
+ if (temp.isSimpleType(prop)) {
+ Class<?> clazz = null;
+ try {
+ clazz = Class.forName(temp.getType(prop));
+ } catch (ClassNotFoundException e) {
+ clazz = Object.class;
+ }
+ dbProperty.setTypeClass(clazz);
+ properties.put(prop, dbProperty);
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Creates the DB indexes.
+ *
+ * @param temp the temp
+ */
+ private void createDBIndexes(Introspector temp) {
+ String uniqueProps = temp.getMetadata(ObjectMetadata.UNIQUE_PROPS);
+ String namespace = temp.getMetadata(ObjectMetadata.NAMESPACE);
+ if (uniqueProps == null) {
+ uniqueProps = "";
+ }
+ if (namespace == null) {
+ namespace = "";
+ }
+ boolean isTopLevel = namespace != "";
+ List<String> unique = Arrays.asList(uniqueProps.split(","));
+ Set<String> indexed = temp.getIndexedProperties();
+ Set<String> keys = temp.getKeys();
+
+ for (String prop : indexed) {
+ DBIndex dbIndex = new DBIndex();
+ LinkedHashSet<DBProperty> properties = new LinkedHashSet<>();
+ if (!this.indexes.containsKey(prop)) {
+ dbIndex.setName(prop);
+ dbIndex.setUnique(unique.contains(prop));
+ properties.add(this.properties.get(prop));
+ dbIndex.setProperties(properties);
+ dbIndex.setStatus(SchemaStatus.ENABLED);
+ this.indexes.put(prop, dbIndex);
+ }
+ }
+ if (keys.size() > 1 || isTopLevel) {
+ DBIndex dbIndex = new DBIndex();
+ LinkedHashSet<DBProperty> properties = new LinkedHashSet<>();
+ dbIndex.setName("key-for-" + temp.getDbName());
+ if (!this.indexes.containsKey(dbIndex.getName())) {
+ boolean isUnique = false;
+ if (isTopLevel) {
+ properties.add(this.properties.get(AAIProperties.NODE_TYPE));
+ }
+ for (String key : keys) {
+ properties.add(this.properties.get(key));
+
+ if (unique.contains(key) && !isUnique) {
+ isUnique = true;
+ }
+ }
+ dbIndex.setUnique(isUnique);
+ dbIndex.setProperties(properties);
+ dbIndex.setStatus(SchemaStatus.ENABLED);
+ this.indexes.put(dbIndex.getName(), dbIndex);
+ }
+ }
+
+ }
+
+ /**
+ * Creates the edge labels.
+ */
+ private void createEdgeLabels() {
+ Multimap<String, String> edgeRules = DbEdgeRules.EdgeRules;
+ for (String key : edgeRules.keySet()) {
+ Collection<String> collection = edgeRules.get(key);
+ EdgeProperty prop = new EdgeProperty();
+ //there is only ever one, they used the wrong type for EdgeRules
+ String label = "";
+ for (String item : collection) {
+ label = item.split(",")[0];
+ }
+ prop.setName(label);
+ prop.setMultiplicity(Multiplicity.MULTI);
+ this.edgeLabels.put(label, prop);
+ }
+ }
+
+ /**
+ * Gets the all introspectors.
+ *
+ * @return the all introspectors
+ */
+ public Set<Introspector> getAllIntrospectors() {
+ return this.allObjects;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditTitan.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditTitan.java
new file mode 100644
index 00000000..743e683e
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditTitan.java
@@ -0,0 +1,127 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.db.schema;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import com.thinkaurelius.titan.core.EdgeLabel;
+import com.thinkaurelius.titan.core.PropertyKey;
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.thinkaurelius.titan.core.schema.TitanGraphIndex;
+import com.thinkaurelius.titan.core.schema.TitanManagement;
+
+public class AuditTitan extends Auditor {
+
+ private final TitanGraph graph;
+
+ /**
+ * Instantiates a new audit titan.
+ *
+ * @param g the g
+ */
+ public AuditTitan (TitanGraph g) {
+ this.graph = g;
+ buildSchema();
+ }
+
+ /**
+ * Builds the schema.
+ */
+ private void buildSchema() {
+ populateProperties();
+ populateIndexes();
+ populateEdgeLabels();
+ }
+
+ /**
+ * Populate properties.
+ */
+ private void populateProperties() {
+ TitanManagement mgmt = graph.openManagement();
+ Iterable<PropertyKey> iterable = mgmt.getRelationTypes(PropertyKey.class);
+ Iterator<PropertyKey> titanProperties = iterable.iterator();
+ PropertyKey propKey = null;
+ while (titanProperties.hasNext()) {
+ propKey = titanProperties.next();
+ DBProperty prop = new DBProperty();
+
+ prop.setName(propKey.name());
+ prop.setCardinality(propKey.cardinality());
+ prop.setTypeClass(propKey.dataType());
+
+ this.properties.put(prop.getName(), prop);
+ }
+ }
+
+ /**
+ * Populate indexes.
+ */
+ private void populateIndexes() {
+ TitanManagement mgmt = graph.openManagement();
+ Iterable<TitanGraphIndex> iterable = mgmt.getGraphIndexes(Vertex.class);
+ Iterator<TitanGraphIndex> titanIndexes = iterable.iterator();
+ TitanGraphIndex titanIndex = null;
+ while (titanIndexes.hasNext()) {
+ titanIndex = titanIndexes.next();
+ if (titanIndex.isCompositeIndex()) {
+ DBIndex index = new DBIndex();
+ LinkedHashSet<DBProperty> dbProperties = new LinkedHashSet<>();
+ index.setName(titanIndex.name());
+ index.setUnique(titanIndex.isUnique());
+ PropertyKey[] keys = titanIndex.getFieldKeys();
+ for (PropertyKey key : keys) {
+ dbProperties.add(this.properties.get(key.name()));
+ }
+ index.setProperties(dbProperties);
+ index.setStatus(titanIndex.getIndexStatus(keys[0]));
+ this.indexes.put(index.getName(), index);
+ }
+ }
+ }
+
+ /**
+ * Populate edge labels.
+ */
+ private void populateEdgeLabels() {
+ TitanManagement mgmt = graph.openManagement();
+ Iterable<EdgeLabel> iterable = mgmt.getRelationTypes(EdgeLabel.class);
+ Iterator<EdgeLabel> titanEdgeLabels = iterable.iterator();
+ EdgeLabel edgeLabel = null;
+ while (titanEdgeLabels.hasNext()) {
+ edgeLabel = titanEdgeLabels.next();
+ EdgeProperty edgeProperty = new EdgeProperty();
+
+ edgeProperty.setName(edgeLabel.name());
+ edgeProperty.setMultiplicity(edgeLabel.multiplicity());
+
+ this.edgeLabels.put(edgeProperty.getName(), edgeProperty);
+ }
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/Auditor.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/Auditor.java
new file mode 100644
index 00000000..91897f43
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/Auditor.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.db.schema;
+
+import java.util.*;
+
+public abstract class Auditor {
+
+ protected Map<String, DBProperty> properties = new HashMap<>();
+ protected Map<String, DBIndex> indexes = new HashMap<>();
+ protected Map<String, EdgeProperty> edgeLabels = new HashMap<>();
+
+ /**
+ * Gets the audit doc.
+ *
+ * @return the audit doc
+ */
+ public AuditDoc getAuditDoc() {
+ AuditDoc doc = new AuditDoc();
+ List<DBProperty> propertyList = new ArrayList<>();
+ List<DBIndex> indexList = new ArrayList<>();
+ List<EdgeProperty> edgeLabelList = new ArrayList<>();
+ propertyList.addAll(this.properties.values());
+ indexList.addAll(this.indexes.values());
+ edgeLabelList.addAll(this.edgeLabels.values());
+ Collections.sort(propertyList, new CompareByName());
+ Collections.sort(indexList, new CompareByName());
+ Collections.sort(edgeLabelList, new CompareByName());
+
+ doc.setProperties(propertyList);
+ doc.setIndexes(indexList);
+ doc.setEdgeLabels(edgeLabelList);
+
+ return doc;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditorFactory.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditorFactory.java
new file mode 100644
index 00000000..7adc587c
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/AuditorFactory.java
@@ -0,0 +1,47 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.db.schema;
+
+import org.openecomp.aai.introspection.Version;
+import com.thinkaurelius.titan.core.TitanGraph;
+
+public class AuditorFactory {
+
+ /**
+ * Gets the OXM auditor.
+ *
+ * @param v the v
+ * @return the OXM auditor
+ */
+ public static Auditor getOXMAuditor (Version v) {
+ return new AuditOXM(v);
+ }
+
+ /**
+ * Gets the graph auditor.
+ *
+ * @param g the g
+ * @return the graph auditor
+ */
+ public static Auditor getGraphAuditor (TitanGraph g) {
+ return new AuditTitan(g);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/CompareByName.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/CompareByName.java
new file mode 100644
index 00000000..3a979b35
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/CompareByName.java
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.db.schema;
+
+import java.util.Comparator;
+
+public class CompareByName implements Comparator<Named>{
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compare(Named o1, Named o2) {
+ return o1.getName().compareTo(o2.getName());
+ }
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/DBIndex.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/DBIndex.java
new file mode 100644
index 00000000..98aab19a
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/DBIndex.java
@@ -0,0 +1,105 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.db.schema;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import com.thinkaurelius.titan.core.schema.SchemaStatus;
+
+public class DBIndex implements Named {
+
+ private String name = null;
+ private boolean unique = false;
+ private LinkedHashSet<DBProperty> properties = new LinkedHashSet<>();
+ private SchemaStatus status = null;
+
+ /**
+ * Gets the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name.
+ *
+ * @param name the new name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Checks if is unique.
+ *
+ * @return true, if is unique
+ */
+ public boolean isUnique() {
+ return unique;
+ }
+
+ /**
+ * Sets the unique.
+ *
+ * @param unique the new unique
+ */
+ public void setUnique(boolean unique) {
+ this.unique = unique;
+ }
+
+ /**
+ * Gets the properties.
+ *
+ * @return the properties
+ */
+ public Set<DBProperty> getProperties() {
+ return properties;
+ }
+
+ /**
+ * Sets the properties.
+ *
+ * @param properties the new properties
+ */
+ public void setProperties(LinkedHashSet<DBProperty> properties) {
+ this.properties = properties;
+ }
+
+ /**
+ * Gets the status.
+ *
+ * @return the status
+ */
+ public SchemaStatus getStatus() {
+ return status;
+ }
+
+ /**
+ * Sets the status.
+ *
+ * @param status the new status
+ */
+ public void setStatus(SchemaStatus status) {
+ this.status = status;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/DBProperty.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/DBProperty.java
new file mode 100644
index 00000000..2c314d1f
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/DBProperty.java
@@ -0,0 +1,85 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.db.schema;
+
+import org.openecomp.aai.introspection.Introspector;
+import com.thinkaurelius.titan.core.Cardinality;
+
+public class DBProperty implements Named {
+
+
+ private String name = null;
+ private Cardinality cardinality = null;
+ private Class<?> typeClass = null;
+
+ /**
+ * Gets the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name.
+ *
+ * @param name the new name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Gets the cardinality.
+ *
+ * @return the cardinality
+ */
+ public Cardinality getCardinality() {
+ return cardinality;
+ }
+
+ /**
+ * Sets the cardinality.
+ *
+ * @param cardinality the new cardinality
+ */
+ public void setCardinality(Cardinality cardinality) {
+ this.cardinality = cardinality;
+ }
+
+ /**
+ * Gets the type class.
+ *
+ * @return the type class
+ */
+ public Class<?> getTypeClass() {
+ return typeClass;
+ }
+
+ /**
+ * Sets the type class.
+ *
+ * @param type the new type class
+ */
+ public void setTypeClass(Class<?> type) {
+ this.typeClass = type;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/EdgeProperty.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/EdgeProperty.java
new file mode 100644
index 00000000..0a63dad9
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/EdgeProperty.java
@@ -0,0 +1,69 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.db.schema;
+
+import com.thinkaurelius.titan.core.Multiplicity;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.annotate.JsonPropertyOrder;
+
+@JsonPropertyOrder({ "label", "multiplicity" })
+public class EdgeProperty implements Named {
+
+ private String name = null;
+ private Multiplicity multiplicity = null;
+
+ /**
+ * Gets the name
+ */
+ @JsonProperty("label")
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name.
+ *
+ * @param name the new name
+ */
+ @JsonProperty("label")
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Gets the multiplicity.
+ *
+ * @return the multiplicity
+ */
+ public Multiplicity getMultiplicity() {
+ return multiplicity;
+ }
+
+ /**
+ * Sets the multiplicity.
+ *
+ * @param multiplicity the new multiplicity
+ */
+ public void setMultiplicity(Multiplicity multiplicity) {
+ this.multiplicity = multiplicity;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/ManageTitanSchema.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/ManageTitanSchema.java
new file mode 100644
index 00000000..940bee38
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/ManageTitanSchema.java
@@ -0,0 +1,329 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.db.schema;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.introspection.Version;
+import com.thinkaurelius.titan.core.PropertyKey;
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.thinkaurelius.titan.core.schema.SchemaStatus;
+import com.thinkaurelius.titan.core.schema.TitanGraphIndex;
+import com.thinkaurelius.titan.core.schema.TitanManagement;
+import com.thinkaurelius.titan.core.schema.TitanManagement.IndexBuilder;
+
+public class ManageTitanSchema {
+
+
+ private TitanManagement graphMgmt;
+ private TitanGraph graph;
+ private List<DBProperty> aaiProperties;
+ private List<DBIndex> aaiIndexes;
+ private List<EdgeProperty> aaiEdgeProperties;
+ private Auditor oxmInfo = null;
+ private Auditor graphInfo = null;
+
+ /**
+ * Instantiates a new manage titan schema.
+ *
+ * @param graph the graph
+ */
+ public ManageTitanSchema(final TitanGraph graph) {
+ this.graph = graph;
+ oxmInfo = AuditorFactory.getOXMAuditor(Version.v8);
+ graphInfo = AuditorFactory.getGraphAuditor(graph);
+ }
+
+
+ /**
+ * Builds the schema.
+ */
+ public void buildSchema() {
+
+ this.graphMgmt = graph.openManagement();
+ aaiProperties = new ArrayList<>();
+ aaiEdgeProperties = new ArrayList<>();
+ aaiIndexes = new ArrayList<>();
+ aaiProperties.addAll(oxmInfo.getAuditDoc().getProperties());
+ aaiIndexes.addAll(oxmInfo.getAuditDoc().getIndexes());
+ aaiEdgeProperties.addAll(oxmInfo.getAuditDoc().getEdgeLabels());
+ try {
+ createPropertyKeys();
+ createIndexes();
+ createEdgeLabels();
+ } catch (Exception e) {
+ e.printStackTrace();
+ graphMgmt.rollback();
+ }
+ graphMgmt.commit();
+ }
+
+ /**
+ * Creates the property keys.
+ */
+ private void createPropertyKeys() {
+
+
+ for (DBProperty prop : aaiProperties) {
+
+ if (graphMgmt.containsPropertyKey(prop.getName())) {
+ PropertyKey key = graphMgmt.getPropertyKey(prop.getName());
+ boolean isChanged = false;
+ if (!prop.getCardinality().equals(key.cardinality())) {
+ isChanged = true;
+ }
+ if (!prop.getTypeClass().equals(key.dataType())) {
+ isChanged = true;
+ }
+ if (isChanged) {
+ //must modify!
+ this.replaceProperty(prop);
+ }
+ } else {
+ //create a new property key
+ System.out.println("Key: " + prop.getName() + " not found - adding");
+ graphMgmt.makePropertyKey(prop.getName()).dataType(prop.getTypeClass()).cardinality(prop.getCardinality()).make();
+ }
+ }
+
+ }
+
+ /**
+ * Creates the indexes.
+ */
+ private void createIndexes() {
+
+ for (DBIndex index : aaiIndexes) {
+ Set<DBProperty> props = index.getProperties();
+ boolean isChanged = false;
+ boolean isNew = false;
+ List<PropertyKey> keyList = new ArrayList<>();
+ for (DBProperty prop : props) {
+ keyList.add(graphMgmt.getPropertyKey(prop.getName()));
+ }
+ if (graphMgmt.containsGraphIndex(index.getName())) {
+ TitanGraphIndex titanIndex = graphMgmt.getGraphIndex(index.getName());
+ PropertyKey[] dbKeys = titanIndex.getFieldKeys();
+ if (dbKeys.length != keyList.size()) {
+ isChanged = true;
+ } else {
+ int i = 0;
+ for (PropertyKey key : keyList) {
+ if (!dbKeys[i].equals(key)) {
+ isChanged = true;
+ break;
+ }
+ i++;
+ }
+ }
+ } else {
+ isNew = true;
+ }
+ if (keyList.size() > 0) {
+ this.createIndex(graphMgmt, index.getName(), keyList, index.isUnique(), isNew, isChanged);
+ }
+ }
+ }
+
+ // Use EdgeRules to make sure edgeLabels are defined in the db. NOTE: the multiplicty used here is
+ // always "MULTI". This is not the same as our internal "Many2Many", "One2One", "One2Many" or "Many2One"
+ // We use the same edge-label for edges between many different types of nodes and our internal
+ // multiplicty definitions depends on which two types of nodes are being connected.
+ /**
+ * Creates the edge labels.
+ */
+ private void createEdgeLabels() {
+
+
+ for (EdgeProperty prop : aaiEdgeProperties) {
+
+ if (graphMgmt.containsEdgeLabel(prop.getName())) {
+ // see what changed
+ } else {
+ graphMgmt.makeEdgeLabel(prop.getName()).multiplicity(prop.getMultiplicity()).make();
+ }
+
+ }
+
+
+ }
+
+ /**
+ * Creates the property.
+ *
+ * @param mgmt the mgmt
+ * @param prop the prop
+ */
+ private void createProperty(TitanManagement mgmt, DBProperty prop) {
+ if (mgmt.containsPropertyKey(prop.getName())) {
+ PropertyKey key = mgmt.getPropertyKey(prop.getName());
+ boolean isChanged = false;
+ if (!prop.getCardinality().equals(key.cardinality())) {
+ isChanged = true;
+ }
+ if (!prop.getTypeClass().equals(key.dataType())) {
+ isChanged = true;
+ }
+ if (isChanged) {
+ //must modify!
+ this.replaceProperty(prop);
+ }
+ } else {
+ //create a new property key
+ System.out.println("Key: " + prop.getName() + " not found - adding");
+ mgmt.makePropertyKey(prop.getName()).dataType(prop.getTypeClass()).cardinality(prop.getCardinality()).make();
+ }
+ }
+
+ /**
+ * Creates the index.
+ *
+ * @param mgmt the mgmt
+ * @param indexName the index name
+ * @param keys the keys
+ * @param isUnique the is unique
+ * @param isNew the is new
+ * @param isChanged the is changed
+ */
+ private void createIndex(TitanManagement mgmt, String indexName, List<PropertyKey> keys, boolean isUnique, boolean isNew, boolean isChanged) {
+
+ /*if (isChanged) {
+ System.out.println("Changing index: " + indexName);
+ TitanGraphIndex oldIndex = mgmt.getGraphIndex(indexName);
+ mgmt.updateIndex(oldIndex, SchemaAction.DISABLE_INDEX);
+ mgmt.commit();
+ //cannot remove indexes
+ //graphMgmt.updateIndex(oldIndex, SchemaAction.REMOVE_INDEX);
+ }*/
+ if (isNew || isChanged) {
+
+ if (isNew) {
+ IndexBuilder builder = mgmt.buildIndex(indexName,Vertex.class);
+ for (PropertyKey k : keys) {
+ builder.addKey(k);
+ }
+ if (isUnique) {
+ builder.unique();
+ }
+ builder.buildCompositeIndex();
+ System.out.println("Built index for " + indexName + " with keys: " + keys);
+
+ //mgmt.commit();
+ }
+
+ //mgmt = graph.asAdmin().getManagementSystem();
+ //mgmt.updateIndex(mgmt.getGraphIndex(indexName), SchemaAction.REGISTER_INDEX);
+ //mgmt.commit();
+
+ try {
+ //waitForCompletion(indexName);
+ //TitanIndexRepair.hbaseRepair(AAIConstants.AAI_CONFIG_FILENAME, indexName, "");
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ graph.tx().rollback();
+ graph.close();
+ e.printStackTrace();
+ }
+
+ //mgmt = graph.asAdmin().getManagementSystem();
+ //mgmt.updateIndex(mgmt.getGraphIndex(indexName), SchemaAction.REINDEX);
+
+ //mgmt.updateIndex(mgmt.getGraphIndex(indexName), SchemaAction.ENABLE_INDEX);
+
+ //mgmt.commit();
+
+ }
+ }
+
+ /**
+ * Wait for completion.
+ *
+ * @param name the name
+ * @throws InterruptedException the interrupted exception
+ */
+ private void waitForCompletion(String name) throws InterruptedException {
+
+ boolean registered = false;
+ long before = System.currentTimeMillis();
+ while (!registered) {
+ Thread.sleep(500L);
+ TitanManagement mgmt = graph.openManagement();
+ TitanGraphIndex idx = mgmt.getGraphIndex(name);
+ registered = true;
+ for (PropertyKey k : idx.getFieldKeys()) {
+ SchemaStatus s = idx.getIndexStatus(k);
+ registered &= s.equals(SchemaStatus.REGISTERED);
+ }
+ mgmt.rollback();
+ }
+ System.out.println("Index REGISTERED in " + (System.currentTimeMillis() - before) + " ms");
+ }
+
+ /**
+ * Replace property.
+ *
+ * @param key the key
+ */
+ private void replaceProperty(DBProperty key) {
+
+
+
+
+ }
+
+ /**
+ * Update index.
+ *
+ * @param index the index
+ */
+ public void updateIndex(DBIndex index) {
+
+ TitanManagement mgmt = graph.openManagement();
+ List<PropertyKey> keys = new ArrayList<>();
+ boolean isNew = false;
+ boolean isChanged = false;
+ for (DBProperty prop : index.getProperties()) {
+ createProperty(mgmt, prop);
+ keys.add(mgmt.getPropertyKey(prop.getName()));
+ }
+ if (mgmt.containsGraphIndex(index.getName())) {
+ System.out.println("index already exists");
+ isNew = false;
+ isChanged = true;
+ } else {
+ isNew = true;
+ isChanged = false;
+ }
+ this.createIndex(mgmt, index.getName(), keys, index.isUnique(), isNew, isChanged);
+
+ mgmt.commit();
+
+ }
+
+
+
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/Named.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/Named.java
new file mode 100644
index 00000000..9b0bbe37
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/Named.java
@@ -0,0 +1,31 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.db.schema;
+
+public interface Named {
+
+ /**
+ * Gets the name.
+ *
+ * @return the name
+ */
+ public String getName();
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/db/schema/ScriptDriver.java b/aai-core/src/main/java/org/openecomp/aai/db/schema/ScriptDriver.java
new file mode 100644
index 00000000..fe55af68
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/db/schema/ScriptDriver.java
@@ -0,0 +1,95 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.db.schema;
+
+import java.io.IOException;
+
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Version;
+import org.openecomp.aai.util.AAIConfig;
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.Parameter;
+import com.thinkaurelius.titan.core.TitanFactory;
+import com.thinkaurelius.titan.core.TitanGraph;
+
+public class ScriptDriver {
+
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ * @throws AAIException the AAI exception
+ * @throws JsonGenerationException the json generation exception
+ * @throws JsonMappingException the json mapping exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static void main (String[] args) throws AAIException, JsonGenerationException, JsonMappingException, IOException {
+ CommandLineArgs cArgs = new CommandLineArgs();
+
+ new JCommander(cArgs, args);
+
+ if (cArgs.help) {
+ System.out.println("-c [path to graph configuration] -type [what you want to audit - oxm or graph]");
+ }
+ String config = cArgs.config;
+ AAIConfig.init();
+ TitanGraph graph = TitanFactory.open(config);
+ if (!(cArgs.type.equals("oxm") || cArgs.type.equals("graph"))) {
+ System.out.println("type: " + cArgs.type + " not recognized.");
+ System.exit(1);
+ }
+
+ Auditor a = null;
+ if (cArgs.type.equals("oxm")) {
+ a = AuditorFactory.getOXMAuditor(Version.v8);
+ } else if (cArgs.type.equals("graph")) {
+ a = AuditorFactory.getGraphAuditor(graph);
+ }
+
+ AuditDoc doc = a.getAuditDoc();
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(doc);
+ System.out.println(json);
+
+ }
+
+}
+
+class CommandLineArgs {
+
+ @Parameter(names = "--help", description = "Help")
+ public boolean help = false;
+
+ @Parameter(names = "-c", description = "Configuration", required=true)
+ public String config;
+
+ @Parameter(names = "-type", description = "Type", required=true)
+ public String type = "graph";
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/dbgen/DataGrooming.java b/aai-core/src/main/java/org/openecomp/aai/dbgen/DataGrooming.java
new file mode 100644
index 00000000..aa5084b9
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/dbgen/DataGrooming.java
@@ -0,0 +1,2223 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.dbgen;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.UUID;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+
+import org.openecomp.aai.dbmap.AAIGraph;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.ingestModel.DbMaps;
+import org.openecomp.aai.ingestModel.IngestModelMoxyOxm;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+import com.att.eelf.configuration.Configuration;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.thinkaurelius.titan.core.TitanEdge;
+import com.thinkaurelius.titan.core.TitanFactory;
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.thinkaurelius.titan.core.TitanTransaction;
+import com.thinkaurelius.titan.core.TitanVertex;
+
+
+public class DataGrooming {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DataGrooming.class);
+ private static final String FROMAPPID = "AAI-DB";
+ private static final String TRANSID = UUID.randomUUID().toString();
+ private static int dupeGrpsDeleted = 0;
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+
+ // Set the logging file properties to be used by EELFManager
+ Properties props = System.getProperties();
+ props.setProperty(Configuration.PROPERTY_LOGGING_FILE_NAME, AAIConstants.AAI_DATA_GROOMING_LOGBACK_PROPS);
+ props.setProperty(Configuration.PROPERTY_LOGGING_FILE_PATH, AAIConstants.AAI_HOME_ETC_APP_PROPERTIES);
+
+ String ver = "version"; // Placeholder
+ Boolean doAutoFix = false;
+ Boolean edgesOnlyFlag = false;
+ Boolean dontFixOrphansFlag = false;
+ Boolean singleCommits = false;
+ Boolean dupeCheckOff = false;
+ Boolean dupeFixOn = false;
+ Boolean ghost2CheckOff = false;
+ Boolean ghost2FixOn = false;
+ Boolean neverUseCache = false;
+
+ int maxRecordsToFix = AAIConstants.AAI_GROOMING_DEFAULT_MAX_FIX;
+ int sleepMinutes = AAIConstants.AAI_GROOMING_DEFAULT_SLEEP_MINUTES;
+ try {
+ String maxFixStr = AAIConfig.get("aai.grooming.default.max.fix");
+ if( maxFixStr != null && !maxFixStr.equals("") ){
+ maxRecordsToFix = Integer.parseInt(maxFixStr);
+ }
+ String sleepStr = AAIConfig.get("aai.grooming.default.sleep.minutes");
+ if( sleepStr != null && !sleepStr.equals("") ){
+ sleepMinutes = Integer.parseInt(sleepStr);
+ }
+ }
+ catch ( Exception e ){
+ // Don't worry, we'll just use the defaults that we got from AAIConstants
+ LOGGER.warn("WARNING - could not pick up aai.grooming values from aaiconfig.properties file. ");
+ }
+
+ String prevFileName = "";
+ dupeGrpsDeleted = 0;
+ SimpleDateFormat d = new SimpleDateFormat("yyyyMMddHHmm");
+ d.setTimeZone(TimeZone.getTimeZone("GMT"));
+ String dteStr = d.format(new Date()).toString();
+ String groomOutFileName = "dataGrooming." + dteStr + ".out";
+
+ if (args.length > 0) {
+ // They passed some arguments in that will affect processing
+ for (int i = 0; i < args.length; i++) {
+ String thisArg = args[i];
+ if (thisArg.equals("-edgesOnly")) {
+ edgesOnlyFlag = true;
+ } else if (thisArg.equals("-autoFix")) {
+ doAutoFix = true;
+ } else if (thisArg.equals("-dontFixOrphans")) {
+ dontFixOrphansFlag = true;
+ } else if (thisArg.equals("-singleCommits")) {
+ singleCommits = true;
+ } else if (thisArg.equals("-dupeCheckOff")) {
+ dupeCheckOff = true;
+ } else if (thisArg.equals("-dupeFixOn")) {
+ dupeFixOn = true;
+ } else if (thisArg.equals("-ghost2CheckOff")) {
+ ghost2CheckOff = true;
+ } else if (thisArg.equals("-neverUseCache")) {
+ neverUseCache = true;
+ } else if (thisArg.equals("-ghost2FixOn")) {
+ ghost2FixOn = true;
+ } else if (thisArg.equals("-maxFix")) {
+ i++;
+ if (i >= args.length) {
+ LOGGER.error(" No value passed with -maxFix option. ");
+ System.exit(0);
+ }
+ String nextArg = args[i];
+ try {
+ maxRecordsToFix = Integer.parseInt(nextArg);
+ } catch (Exception e) {
+ LOGGER.error("Bad value passed with -maxFix option: ["
+ + nextArg + "]");
+ System.exit(0);
+ }
+ } else if (thisArg.equals("-sleepMinutes")) {
+ i++;
+ if (i >= args.length) {
+ LOGGER.error("No value passed with -sleepMinutes option.");
+ System.exit(0);
+ }
+ String nextArg = args[i];
+ try {
+ sleepMinutes = Integer.parseInt(nextArg);
+ } catch (Exception e) {
+ LOGGER.error("Bad value passed with -sleepMinutes option: ["
+ + nextArg + "]");
+ System.exit(0);
+ }
+ } else if (thisArg.equals("-f")) {
+ i++;
+ if (i >= args.length) {
+ LOGGER.error(" No value passed with -f option. ");
+ System.exit(0);
+ }
+ prevFileName = args[i];
+ } else {
+ LOGGER.error(" Unrecognized argument passed to DataGrooming: ["
+ + thisArg + "]. ");
+ LOGGER.error(" Valid values are: -f -autoFix -maxFix -edgesOnly -dupeFixOn -donFixOrphans -sleepMinutes -neverUseCache");
+ System.exit(0);
+ }
+ }
+ }
+
+
+ IngestModelMoxyOxm moxyMod = new IngestModelMoxyOxm();
+ try {
+ ArrayList <String> defaultVerLst = new ArrayList <> ();
+ defaultVerLst.add( AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP) );
+ moxyMod.init( defaultVerLst, false);
+ }
+ catch (Exception ex){
+ LOGGER.error("ERROR - Could not do the moxyMod.init()", ex);
+ System.exit(1);
+ }
+
+ try {
+ if (!prevFileName.equals("")) {
+ // They are trying to fix some data based on a data in a
+ // previous file.
+ LOGGER.info(" Call doTheGrooming() with a previous fileName ["
+ + prevFileName + "] for cleanup. ");
+ Boolean finalShutdownFlag = true;
+ Boolean cacheDbOkFlag = false;
+ doTheGrooming(prevFileName, edgesOnlyFlag, dontFixOrphansFlag,
+ maxRecordsToFix, groomOutFileName, ver, singleCommits,
+ dupeCheckOff, dupeFixOn, ghost2CheckOff, ghost2FixOn,
+ finalShutdownFlag, cacheDbOkFlag);
+ } else if (doAutoFix) {
+ // They want us to run the processing twice -- first to look for
+ // delete candidates, then after
+ // napping for a while, run it again and delete any candidates
+ // that were found by the first run.
+ // Note: we will produce a separate output file for each of the
+ // two runs.
+ LOGGER.info(" Doing an auto-fix call to Grooming. ");
+ LOGGER.info(" First, Call doTheGrooming() to look at what's out there. ");
+ Boolean finalShutdownFlag = false;
+ Boolean cacheDbOkFlag = true;
+ int fixCandCount = doTheGrooming("", edgesOnlyFlag,
+ dontFixOrphansFlag, maxRecordsToFix, groomOutFileName,
+ ver, singleCommits, dupeCheckOff, dupeFixOn, ghost2CheckOff, ghost2FixOn,
+ finalShutdownFlag, cacheDbOkFlag);
+ if (fixCandCount == 0) {
+ LOGGER.info(" No fix-Candidates were found by the first pass, so no second/fix-pass is needed. ");
+ } else {
+ // We'll sleep a little and then run a fix-pass based on the
+ // first-run's output file.
+ try {
+ LOGGER.info("About to sleep for " + sleepMinutes
+ + " minutes.");
+ int sleepMsec = sleepMinutes * 60 * 1000;
+ Thread.sleep(sleepMsec);
+ } catch (InterruptedException ie) {
+ LOGGER.info("\n >>> Sleep Thread has been Interrupted <<< ");
+ System.exit(0);
+ }
+
+ d = new SimpleDateFormat("yyyyMMddHHmm");
+ d.setTimeZone(TimeZone.getTimeZone("GMT"));
+ dteStr = d.format(new Date()).toString();
+ String secondGroomOutFileName = "dataGrooming." + dteStr
+ + ".out";
+ LOGGER.info(" Now, call doTheGrooming() a second time and pass in the name of the file "
+ + "generated by the first pass for fixing: ["
+ + groomOutFileName + "]");
+ finalShutdownFlag = true;
+ cacheDbOkFlag = false;
+ doTheGrooming(groomOutFileName, edgesOnlyFlag,
+ dontFixOrphansFlag, maxRecordsToFix,
+ secondGroomOutFileName, ver, singleCommits,
+ dupeCheckOff, dupeFixOn, ghost2CheckOff, ghost2FixOn,
+ finalShutdownFlag, cacheDbOkFlag);
+ }
+ } else {
+ // Do the grooming - plain vanilla (no fix-it-file, no
+ // auto-fixing)
+ Boolean finalShutdownFlag = true;
+ LOGGER.info(" Call doTheGrooming() ");
+ Boolean cacheDbOkFlag = true;
+ if( neverUseCache ){
+ // They have forbidden us from using a cached db connection.
+ cacheDbOkFlag = false;
+ }
+ doTheGrooming("", edgesOnlyFlag, dontFixOrphansFlag,
+ maxRecordsToFix, groomOutFileName, ver, singleCommits,
+ dupeCheckOff, dupeFixOn, ghost2CheckOff, ghost2FixOn,
+ finalShutdownFlag, cacheDbOkFlag);
+ }
+ } catch (Exception ex) {
+ LOGGER.error("Exception while grooming data", ex);
+ }
+
+ LOGGER.info(" Done! ");
+ System.exit(0);
+
+ }// End of main()
+
+ /**
+ * Do the grooming.
+ *
+ * @param fileNameForFixing the file name for fixing
+ * @param edgesOnlyFlag the edges only flag
+ * @param dontFixOrphansFlag the dont fix orphans flag
+ * @param maxRecordsToFix the max records to fix
+ * @param groomOutFileName the groom out file name
+ * @param version the version
+ * @param singleCommits the single commits
+ * @param dupeCheckOff the dupe check off
+ * @param dupeFixOn the dupe fix on
+ * @param ghost2CheckOff the ghost 2 check off
+ * @param ghost2FixOn the ghost 2 fix on
+ * @param finalShutdownFlag the final shutdown flag
+ * @param cacheDbOkFlag the cacheDbOk flag
+ * @return the int
+ */
+ private static int doTheGrooming(String fileNameForFixing,
+ Boolean edgesOnlyFlag, Boolean dontFixOrphansFlag,
+ int maxRecordsToFix, String groomOutFileName, String version,
+ Boolean singleCommits,
+ Boolean dupeCheckOff, Boolean dupeFixOn,
+ Boolean ghost2CheckOff, Boolean ghost2FixOn,
+ Boolean finalShutdownFlag, Boolean cacheDbOkFlag) {
+
+ LOGGER.debug(" Entering doTheGrooming \n");
+
+ int cleanupCandidateCount = 0;
+ BufferedWriter bw = null;
+ TitanGraph graph = null;
+ TitanGraph graph2 = null;
+ int deleteCount = 0;
+ boolean executeFinalCommit = false;
+ Set<String> deleteCandidateList = new LinkedHashSet<>();
+ Set<String> processedVertices = new LinkedHashSet<>();
+ TitanTransaction g = null;
+ TitanTransaction g2 = null;
+ try {
+ AAIConfig.init();
+ String targetDir = AAIConstants.AAI_HOME + AAIConstants.AAI_FILESEP
+ + "logs" + AAIConstants.AAI_FILESEP + "data"
+ + AAIConstants.AAI_FILESEP + "dataGrooming";
+
+ // Make sure the target directory exists
+ new File(targetDir).mkdirs();
+
+ if (!fileNameForFixing.equals("")) {
+ deleteCandidateList = getDeleteList(targetDir,
+ fileNameForFixing, edgesOnlyFlag, dontFixOrphansFlag,
+ dupeFixOn);
+ }
+
+ if (deleteCandidateList.size() > maxRecordsToFix) {
+ LOGGER.warn(" >> WARNING >> Delete candidate list size ("
+ + deleteCandidateList.size()
+ + ") is too big. The maxFix we are using is: "
+ + maxRecordsToFix
+ + ". No candidates will be deleted. ");
+ // Clear out the list so it won't be processed below.
+ deleteCandidateList = new LinkedHashSet<>();
+ }
+
+ SimpleDateFormat d = new SimpleDateFormat("yyyyMMddHHmm");
+ d.setTimeZone(TimeZone.getTimeZone("GMT"));
+
+ String fullOutputFileName = targetDir + AAIConstants.AAI_FILESEP
+ + groomOutFileName;
+ File groomOutFile = new File(fullOutputFileName);
+ try {
+ groomOutFile.createNewFile();
+ } catch (IOException e) {
+ String emsg = " Problem creating output file ["
+ + fullOutputFileName + "], exception=" + e.getMessage();
+ throw new AAIException("AAI_6124", emsg);
+ }
+
+ LOGGER.info(" Will write to " + fullOutputFileName );
+ FileWriter fw = new FileWriter(groomOutFile.getAbsoluteFile());
+ bw = new BufferedWriter(fw);
+ ErrorLogHelper.loadProperties();
+
+ LOGGER.info(" ---- NOTE --- about to open graph (takes a little while)--------\n");
+
+ if( cacheDbOkFlag ){
+ // Since we're just reading (not deleting/fixing anything), we can use
+ // a cached connection to the DB
+ graph = TitanFactory.open(AAIConstants.CACHED_DB_CONFIG);
+ }
+ else {
+ graph = TitanFactory.open(AAIConstants.REALTIME_DB_CONFIG);
+ }
+ if (graph == null) {
+ String emsg = "null graph object in DataGrooming\n";
+ throw new AAIException("AAI_6101", emsg);
+ }
+
+ LOGGER.debug(" Got the graph object. ");
+
+ g = graph.newTransaction();
+ if (g == null) {
+ String emsg = "null graphTransaction object in DataGrooming\n";
+ throw new AAIException("AAI_6101", emsg);
+ }
+
+
+ ArrayList<String> errArr = new ArrayList<>();
+ int totalNodeCount = 0;
+ HashMap<String, String> misMatchedHash = new HashMap<String, String>();
+ HashMap<String, TitanVertex> orphanNodeHash = new HashMap<String, TitanVertex>();
+ HashMap<String, TitanVertex> missingDepNodeHash = new HashMap<String, TitanVertex>();
+ HashMap<String, Edge> oneArmedEdgeHash = new HashMap<String, Edge>();
+ HashMap<String, String> emptyVertexHash = new HashMap<String, String>();
+ HashMap<String, TitanVertex> ghostNodeHash = new HashMap<String, TitanVertex>();
+ ArrayList<String> dupeGroups = new ArrayList<>();
+
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ Iterator<String> nodeMapKPropsIterator = dbMaps.NodeKeyProps.keySet().iterator();
+ String ntList = "";
+
+ LOGGER.info(" Starting DataGrooming Processing ");
+
+ if (edgesOnlyFlag) {
+ LOGGER.info(" NOTE >> Skipping Node processing as requested. Will only process Edges. << ");
+ }
+ else {
+ while (nodeMapKPropsIterator.hasNext()) {
+ String nType = nodeMapKPropsIterator.next();
+ int thisNtCount = 0;
+ int thisNtDeleteCount = 0;
+ LOGGER.debug(" > Look at : [" + nType + "] ...");
+ ntList = ntList + "," + nType;
+
+ // Get a collection of the names of the key properties for this nodeType to use later
+ // Determine what the key fields are for this nodeType
+ Collection <String> keyProps = new ArrayList <>();
+ if( dbMaps.NodeKeyProps.containsKey(nType) ){
+ keyProps = dbMaps.NodeKeyProps.get(nType);
+ }
+ else {
+ throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nType + ")");
+ }
+
+ // Get the types of nodes that this nodetype depends on for uniqueness (if any)
+ Collection <String> depNodeTypes = new ArrayList <>();
+ if( dbMaps.NodeDependencies.containsKey(nType) ){
+ depNodeTypes = dbMaps.NodeDependencies.get(nType);
+ }
+
+ // Loop through all the nodes of this Node type
+ int lastShownForNt = 0;
+ ArrayList <TitanVertex> tmpList = new ArrayList <> ();
+ Iterable <?> verts = g.query().has("aai-node-type",nType).vertices();
+ Iterator<?> iterv = verts.iterator();
+ while (iterv.hasNext()) {
+ // We put the nodes into an ArrayList because the graph.query iterator can time out
+ tmpList.add((TitanVertex)iterv.next());
+ }
+
+ Iterator <?> iter = tmpList.iterator();
+ while (iter.hasNext()) {
+ try {
+ thisNtCount++;
+ if( thisNtCount == lastShownForNt + 250 ){
+ lastShownForNt = thisNtCount;
+ LOGGER.debug("count for " + nType + " so far = " + thisNtCount );
+ }
+ TitanVertex thisVtx = (TitanVertex) iter.next();
+ String thisVid = thisVtx.id().toString();
+ if (processedVertices.contains(thisVid)) {
+ LOGGER.debug("skipping already processed vertex: " + thisVid);
+ continue;
+ }
+ totalNodeCount++;
+ List <TitanVertex> secondGetList = new ArrayList <> ();
+ // -----------------------------------------------------------------------
+ // For each vertex of this nodeType, we want to:
+ // a) make sure that it can be retrieved using it's AAI defined key
+ // b) make sure that it is not a duplicate
+ // -----------------------------------------------------------------------
+
+ // For this instance of this nodeType, get the key properties
+ HashMap<String, Object> propHashWithKeys = new HashMap<>();
+ Iterator<String> keyPropI = keyProps.iterator();
+ while (keyPropI.hasNext()) {
+ String propName = keyPropI.next();
+ String propVal = "";
+ //delete an already deleted vertex
+ Object obj = thisVtx.<Object>property(propName).orElse(null);
+ if (obj != null) {
+ propVal = obj.toString();
+ }
+ propHashWithKeys.put(propName, propVal);
+ }
+ try {
+ // If this node is dependent on another for uniqueness, then do the query from that parent node
+ // Note - all of our nodes that are dependent on others for uniqueness are
+ // "children" of that node.
+ boolean depNodeOk = true;
+ if( depNodeTypes.isEmpty() ){
+ // This kind of node is not dependent on any other.
+ // Make sure we can get it back using it's key properties and that we only get one.
+ secondGetList = getNodeJustUsingKeyParams( TRANSID, FROMAPPID, g, nType,
+ propHashWithKeys, version );
+ }
+ else {
+ // This kind of node is dependent on another for uniqueness.
+ // Start at it's parent (the dependent vertex) and make sure we can get it
+ // back using it's key properties and that we only get one.
+ Iterable <?> verts2 = thisVtx.query().direction(Direction.IN).has("isParent",true).vertices();
+ Iterator <?> vertI2 = verts2.iterator();
+ TitanVertex parentVtx = null;
+ int pCount = 0;
+ while( vertI2 != null && vertI2.hasNext() ){
+ parentVtx = (TitanVertex) vertI2.next();
+ pCount++;
+ }
+ if( pCount <= 0 ){
+
+
+ //List<Vertex> vertI2 = g.traversal().V(thisVtx).union(__.outE().has("isParent-REV",true).outV(),__.inE().has("isParent",true).inV()).toList();
+ //if( vertI2.isEmpty()){
+
+ // It's Missing it's dependent/parent node
+ depNodeOk = false;
+ boolean zeroEdges = false;
+ try {
+ Iterator<Edge> tmpEdgeIter = thisVtx.edges(Direction.BOTH);
+ int edgeCount = 0;
+ while( tmpEdgeIter.hasNext() ){
+ edgeCount++;
+ tmpEdgeIter.next();
+ }
+ if( edgeCount == 0 ){
+ zeroEdges = true;
+ }
+ } catch (Exception ex) {
+ LOGGER.warn("WARNING from inside the for-each-vid-loop orphan-edges-check ", ex);
+ }
+
+ if (deleteCandidateList.contains(thisVid)) {
+ boolean okFlag = true;
+ try {
+ processedVertices.add(thisVtx.id().toString());
+ thisVtx.remove();
+ deleteCount++;
+ thisNtDeleteCount++;
+ } catch (Exception e) {
+ okFlag = false;
+ LOGGER.error("ERROR trying to delete missing-dep-node VID = " + thisVid, e);
+ }
+ if (okFlag) {
+ LOGGER.info(" DELETED missing-dep-node VID = " + thisVid);
+ }
+ } else {
+ // We count nodes missing their depNodes two ways - the first if it has
+ // at least some edges, and the second if it has zero edges. Either
+ // way, they are effectively orphaned.
+ // NOTE - Only nodes that have dependent nodes are ever considered "orphaned".
+ if( zeroEdges ){
+ missingDepNodeHash.put(thisVid, thisVtx);
+ }
+ else {
+ orphanNodeHash.put(thisVid, thisVtx);
+ }
+ }
+ }
+ else if ( pCount > 1 ){
+ // Not sure how this could happen? Should we do something here?
+ depNodeOk = false;
+ }
+ else {
+ // We found the parent - so use it to do the second-look.
+ // NOTE --- We're just going to do the same check from the other direction - because
+ // there could be duplicates or the pointer going the other way could be broken
+ ArrayList <TitanVertex> tmpListSec = new ArrayList <> ();
+ tmpListSec = getConnectedChildren( g, parentVtx ) ;
+ Iterator<TitanVertex> vIter = tmpListSec.iterator();
+ while (vIter.hasNext()) {
+ TitanVertex tmpV = vIter.next();
+ if( vertexHasTheseKeys(tmpV, propHashWithKeys) ){
+ secondGetList.add(tmpV);
+ }
+ }
+ }
+ }
+
+ if( depNodeOk && (secondGetList == null || secondGetList.size() == 0) ){
+ // We could not get the node back using it's own key info.
+ // So, it's a PHANTOM
+ if (deleteCandidateList.contains(thisVid)) {
+ boolean okFlag = true;
+ try {
+ thisVtx.remove();
+ deleteCount++;
+ thisNtDeleteCount++;
+ } catch (Exception e) {
+ okFlag = false;
+ LOGGER.error("ERROR trying to delete phantom VID = " + thisVid, e);
+ }
+ if (okFlag) {
+ LOGGER.info(" DELETED VID = " + thisVid);
+ }
+ } else {
+ ghostNodeHash.put(thisVid, thisVtx);
+ }
+ }
+ else if( (secondGetList.size() > 1) && depNodeOk && !dupeCheckOff ){
+ // Found some DUPLICATES - need to process them
+ LOGGER.info(" - now check Dupes for this guy - ");
+ List<String> tmpDupeGroups = checkAndProcessDupes(
+ TRANSID, FROMAPPID, g, version,
+ nType, secondGetList, dupeFixOn,
+ deleteCandidateList, singleCommits, dupeGroups, dbMaps);
+ Iterator<String> dIter = tmpDupeGroups.iterator();
+ while (dIter.hasNext()) {
+ // Add in any newly found dupes to our running list
+ String tmpGrp = dIter.next();
+ LOGGER.info("Found set of dupes: [" + tmpGrp + "]");
+ dupeGroups.add(tmpGrp);
+ }
+ }
+ }
+ catch (AAIException e1) {
+ LOGGER.warn(" For nodeType = " + nType + " Caught exception", e1);
+ errArr.add(e1.getErrorObject().toString());
+ }
+ catch (Exception e2) {
+ LOGGER.warn(" For nodeType = " + nType
+ + " Caught exception", e2);
+ errArr.add(e2.getMessage());
+ }
+ }// try block to enclose looping of a single vertex
+ catch (Exception exx) {
+ LOGGER.warn("WARNING from inside the while-verts-loop ", exx);
+ }
+
+ } // while loop for each record of a nodeType
+
+ if ( (thisNtDeleteCount > 0) && singleCommits ) {
+ // NOTE - the singleCommits option is not used in normal processing
+ g.commit();
+ g = AAIGraph.getInstance().getGraph().newTransaction();
+
+ }
+ thisNtDeleteCount = 0;
+ LOGGER.info( " Processed " + thisNtCount + " records for [" + nType + "], " + totalNodeCount + " total overall. " );
+
+ }// While-loop for each node type
+ }// end of check to make sure we weren't only supposed to do edges
+
+
+ // --------------------------------------------------------------------------------------
+ // Now, we're going to look for one-armed-edges. Ie. an edge that
+ // should have
+ // been deleted (because a vertex on one side was deleted) but
+ // somehow was not deleted.
+ // So the one end of it points to a vertexId -- but that vertex is
+ // empty.
+ // --------------------------------------------------------------------------------------
+
+ // To do some strange checking - we need a second graph object
+ LOGGER.debug(" ---- DEBUG --- about to open a SECOND graph (takes a little while)--------\n");
+ // Note - graph2 just reads - but we want it to use a fresh connection to
+ // the database, so we are NOT using the CACHED DB CONFIG here.
+ graph2 = TitanFactory.open(AAIConstants.REALTIME_DB_CONFIG);
+ if (graph2 == null) {
+ String emsg = "null graph2 object in DataGrooming\n";
+ throw new AAIException("AAI_6101", emsg);
+ } else {
+ LOGGER.debug("Got the graph2 object... \n");
+ }
+ g2 = graph2.newTransaction();
+ if (g2 == null) {
+ String emsg = "null graphTransaction2 object in DataGrooming\n";
+ throw new AAIException("AAI_6101", emsg);
+ }
+
+ ArrayList<Vertex> vertList = new ArrayList<>();
+ Iterable<? extends Vertex> vIt3 = g.query().vertices();
+ Iterator<? extends Vertex> vItor3 = vIt3.iterator();
+ // Gotta hold these in a List - or else HBase times out as you cycle
+ // through these
+ while (vItor3.hasNext()) {
+ Vertex v = vItor3.next();
+ vertList.add(v);
+ }
+ int counter = 0;
+ int lastShown = 0;
+ Iterator<Vertex> vItor2 = vertList.iterator();
+ LOGGER.info(" Checking for bad edges --- ");
+
+ while (vItor2.hasNext()) {
+ Vertex v = null;
+ try {
+ try {
+ v = vItor2.next();
+ } catch (Exception vex) {
+ LOGGER.warn(">>> WARNING trying to get next vertex on the vItor2 ");
+ continue;
+ }
+
+ counter++;
+ String thisVertId = "";
+ try {
+ thisVertId = v.id().toString();
+ } catch (Exception ev) {
+ LOGGER.warn("WARNING when doing getId() on a vertex from our vertex list. ");
+ continue;
+ }
+ if (ghostNodeHash.containsKey(thisVertId)) {
+ // This is a phantom node, so don't try to use it
+ LOGGER.info(" >> Skipping edge check for edges from vertexId = "
+ + thisVertId
+ + ", since that guy is a Phantom Node");
+ continue;
+ }
+ if (counter == lastShown + 250) {
+ lastShown = counter;
+ LOGGER.info("... Checking edges for vertex # "
+ + counter);
+ }
+ Iterator<Edge> eItor = v.edges(Direction.BOTH);
+ while (eItor.hasNext()) {
+ Edge e = null;
+ Vertex vIn = null;
+ Vertex vOut = null;
+ try {
+ e = eItor.next();
+ } catch (Exception iex) {
+ LOGGER.warn(">>> WARNING trying to get next edge on the eItor ", iex);
+ continue;
+ }
+
+ try {
+ vIn = e.inVertex();
+ } catch (Exception err) {
+ LOGGER.warn(">>> WARNING trying to get edge's In-vertex ", err);
+ }
+ String vNtI = "";
+ String vIdI = "";
+ TitanVertex ghost2 = null;
+
+ Boolean keysMissing = true;
+ Boolean cantGetUsingVid = false;
+ if (vIn != null) {
+ try {
+ Object ob = vIn.<Object>property("aai-node-type").orElse(null);
+ if (ob != null) {
+ vNtI = ob.toString();
+ keysMissing = anyKeyFieldsMissing(vNtI, vIn, dbMaps);
+ }
+ ob = vIn.id();
+ long vIdLong = 0L;
+ if (ob != null) {
+ vIdI = ob.toString();
+ vIdLong = Long.parseLong(vIdI);
+ }
+
+ if( ! ghost2CheckOff ){
+ TitanVertex connectedVert = g2.getVertex(vIdLong);
+ if( connectedVert == null ) {
+ LOGGER.warn( "GHOST2 -- got NULL when doing getVertex for vid = " + vIdLong);
+ cantGetUsingVid = true;
+
+ // If we can NOT get this ghost with the SECOND graph-object,
+ // it is still a ghost since even though we can get data about it using the FIRST graph
+ // object.
+ try {
+ ghost2 = g.getVertex(vIdLong);
+ }
+ catch( Exception ex){
+ LOGGER.warn( "GHOST2 -- Could not get the ghost info for a bad edge for vtxId = " + vIdLong, ex);
+ }
+ if( ghost2 != null ){
+ ghostNodeHash.put(vIdI, ghost2);
+ }
+ }
+ }// end of the ghost2 checking
+ }
+ catch (Exception err) {
+ LOGGER.warn(">>> WARNING trying to get edge's In-vertex props ", err);
+ }
+ }
+ if (keysMissing || vIn == null || vNtI.equals("")
+ || cantGetUsingVid) {
+ // this is a bad edge because it points to a vertex
+ // that isn't there anymore or is corrupted
+ String thisEid = e.id().toString();
+ if (deleteCandidateList.contains(thisEid) || deleteCandidateList.contains(vIdI)) {
+ boolean okFlag = true;
+ if (!vIdI.equals("")) {
+ // try to get rid of the corrupted vertex
+ try {
+ if( (ghost2 != null) && ghost2FixOn ){
+ ghost2.remove();
+ }
+ else {
+ vIn.remove();
+ }
+ if (singleCommits) {
+ // NOTE - the singleCommits option is not used in normal processing
+ g.commit();
+ g = AAIGraph.getInstance().getGraph().newTransaction();
+ }
+ deleteCount++;
+ } catch (Exception e1) {
+ okFlag = false;
+ LOGGER.warn("WARNING when trying to delete bad-edge-connected VERTEX VID = "
+ + vIdI, e1);
+ }
+ if (okFlag) {
+ LOGGER.info(" DELETED vertex from bad edge = "
+ + vIdI);
+ }
+ } else {
+ // remove the edge if we couldn't get the
+ // vertex
+ try {
+ e.remove();
+ if (singleCommits) {
+ // NOTE - the singleCommits option is not used in normal processing
+ g.commit();
+ g = AAIGraph.getInstance().getGraph().newTransaction();
+ }
+ deleteCount++;
+ } catch (Exception ex) {
+ // NOTE - often, the exception is just
+ // that this edge has already been
+ // removed
+ okFlag = false;
+ LOGGER.warn("WARNING when trying to delete edge = "
+ + thisEid);
+ }
+ if (okFlag) {
+ LOGGER.info(" DELETED edge = " + thisEid);
+ }
+ }
+ } else {
+ oneArmedEdgeHash.put(thisEid, e);
+ if ((vIn != null) && (vIn.id() != null)) {
+ emptyVertexHash.put(thisEid, vIn.id()
+ .toString());
+ }
+ }
+ }
+
+ try {
+ vOut = e.outVertex();
+ } catch (Exception err) {
+ LOGGER.warn(">>> WARNING trying to get edge's Out-vertex ");
+ }
+ String vNtO = "";
+ String vIdO = "";
+ ghost2 = null;
+ keysMissing = true;
+ cantGetUsingVid = false;
+ if (vOut != null) {
+ try {
+ Object ob = vOut.<Object>property("aai-node-type").orElse(null);
+ if (ob != null) {
+ vNtO = ob.toString();
+ keysMissing = anyKeyFieldsMissing(vNtO,
+ vOut, dbMaps);
+ }
+ ob = vOut.id();
+ long vIdLong = 0L;
+ if (ob != null) {
+ vIdO = ob.toString();
+ vIdLong = Long.parseLong(vIdO);
+ }
+
+ if( ! ghost2CheckOff ){
+ TitanVertex connectedVert = g2.getVertex(vIdLong);
+ if( connectedVert == null ) {
+ cantGetUsingVid = true;
+ LOGGER.info( "GHOST2 -- got NULL when doing getVertex for vid = " + vIdLong);
+ // If we can get this ghost with the other graph-object, then get it -- it's still a ghost
+ try {
+ ghost2 = g.getVertex(vIdLong);
+ }
+ catch( Exception ex){
+ LOGGER.warn( "GHOST2 -- Could not get the ghost info for a bad edge for vtxId = " + vIdLong, ex);
+ }
+ if( ghost2 != null ){
+ ghostNodeHash.put(vIdO, ghost2);
+ }
+ }
+ }
+ } catch (Exception err) {
+ LOGGER.warn(">>> WARNING trying to get edge's Out-vertex props ", err);
+ }
+ }
+ if (keysMissing || vOut == null || vNtO.equals("")
+ || cantGetUsingVid) {
+ // this is a bad edge because it points to a vertex
+ // that isn't there anymore
+ String thisEid = e.id().toString();
+ if (deleteCandidateList.contains(thisEid) || deleteCandidateList.contains(vIdO)) {
+ boolean okFlag = true;
+ if (!vIdO.equals("")) {
+ // try to get rid of the corrupted vertex
+ try {
+ if( (ghost2 != null) && ghost2FixOn ){
+ ghost2.remove();
+ }
+ else {
+ vOut.remove();
+ }
+ if (singleCommits) {
+ // NOTE - the singleCommits option is not used in normal processing
+ g.commit();
+ g = AAIGraph.getInstance().getGraph().newTransaction();
+ }
+ deleteCount++;
+ } catch (Exception e1) {
+ okFlag = false;
+ LOGGER.warn("WARNING when trying to delete bad-edge-connected VID = "
+ + vIdO, e1);
+ }
+ if (okFlag) {
+ LOGGER.info(" DELETED vertex from bad edge = "
+ + vIdO);
+ }
+ } else {
+ // remove the edge if we couldn't get the
+ // vertex
+ try {
+ e.remove();
+ if (singleCommits) {
+ // NOTE - the singleCommits option is not used in normal processing
+ g.commit();
+ g = AAIGraph.getInstance().getGraph().newTransaction();
+ }
+ deleteCount++;
+ } catch (Exception ex) {
+ // NOTE - often, the exception is just
+ // that this edge has already been
+ // removed
+ okFlag = false;
+ LOGGER.warn("WARNING when trying to delete edge = "
+ + thisEid, ex);
+ }
+ if (okFlag) {
+ LOGGER.info(" DELETED edge = " + thisEid);
+ }
+ }
+ } else {
+ oneArmedEdgeHash.put(thisEid, e);
+ if ((vOut != null) && (vOut.id() != null)) {
+ emptyVertexHash.put(thisEid, vOut.id()
+ .toString());
+ }
+ }
+ }
+ }// End of while-edges-loop
+ } catch (Exception exx) {
+ LOGGER.warn("WARNING from in the while-verts-loop ", exx);
+ }
+ }// End of while-vertices-loop
+
+ deleteCount = deleteCount + dupeGrpsDeleted;
+ if (!singleCommits && deleteCount > 0) {
+ try {
+ LOGGER.info("About to do the commit for "
+ + deleteCount + " removes. ");
+ executeFinalCommit = true;
+ LOGGER.info("Commit was successful ");
+ } catch (Exception excom) {
+ LOGGER.error(" >>>> ERROR <<<< Could not commit changes. ", excom);
+ deleteCount = 0;
+ }
+ }
+
+ int ghostNodeCount = ghostNodeHash.size();
+ int orphanNodeCount = orphanNodeHash.size();
+ int missingDepNodeCount = missingDepNodeHash.size();
+ int oneArmedEdgeCount = oneArmedEdgeHash.size();
+ int dupeCount = dupeGroups.size();
+
+ deleteCount = deleteCount + dupeGrpsDeleted;
+
+ bw.write("\n\n ============ Summary ==============\n");
+ bw.write("Ran these nodeTypes: " + ntList + "\n\n");
+ bw.write("There were this many delete candidates from previous run = "
+ + deleteCandidateList.size() + "\n");
+ if (dontFixOrphansFlag) {
+ bw.write(" Note - we are not counting orphan nodes since the -dontFixOrphans parameter was used. \n");
+ }
+ bw.write("Deleted this many delete candidates = " + deleteCount
+ + "\n");
+ bw.write("Total number of nodes looked at = " + totalNodeCount
+ + "\n");
+ bw.write("Ghost Nodes identified = " + ghostNodeCount + "\n");
+ bw.write("Orphan Nodes identified = " + orphanNodeCount + "\n");
+ bw.write("Bad Edges identified = " + oneArmedEdgeCount + "\n");
+ bw.write("Missing Dependent Edge (but not orphaned) node count = "
+ + missingDepNodeCount + "\n");
+ bw.write("Duplicate Groups count = " + dupeCount + "\n");
+ bw.write("MisMatching Label/aai-node-type count = "
+ + misMatchedHash.size() + "\n");
+
+ bw.write("\n ------------- Delete Candidates ---------\n");
+ for (Map.Entry<String, TitanVertex> entry : ghostNodeHash
+ .entrySet()) {
+ String vid = entry.getKey();
+ bw.write("DeleteCandidate: Phantom Vid = [" + vid + "]\n");
+ cleanupCandidateCount++;
+ }
+ for (Map.Entry<String, TitanVertex> entry : orphanNodeHash
+ .entrySet()) {
+ String vid = entry.getKey();
+ bw.write("DeleteCandidate: OrphanDepNode Vid = [" + vid + "]\n");
+ if (!dontFixOrphansFlag) {
+ cleanupCandidateCount++;
+ }
+ }
+ for (Map.Entry<String, Edge> entry : oneArmedEdgeHash.entrySet()) {
+ String eid = entry.getKey();
+ bw.write("DeleteCandidate: Bad EDGE Edge-id = [" + eid + "]\n");
+ cleanupCandidateCount++;
+ }
+ for (Map.Entry<String, TitanVertex> entry : missingDepNodeHash
+ .entrySet()) {
+ String vid = entry.getKey();
+ bw.write("DeleteCandidate: (maybe) missingDepNode Vid = ["
+ + vid + "]\n");
+ cleanupCandidateCount++;
+ }
+ bw.write("\n-- NOTE - To see DeleteCandidates for Duplicates, you need to look in the Duplicates Detail section below.\n");
+
+ bw.write("\n ------------- GHOST NODES - detail ");
+ for (Map.Entry<String, TitanVertex> entry : ghostNodeHash
+ .entrySet()) {
+ try {
+ String vid = entry.getKey();
+ bw.write("\n ==> Phantom Vid = " + vid + "\n");
+ ArrayList<String> retArr = showPropertiesForNode(
+ TRANSID, FROMAPPID, entry.getValue());
+ for (String info : retArr) {
+ bw.write(info + "\n");
+ }
+
+ retArr = showAllEdgesForNode(TRANSID, FROMAPPID,
+ entry.getValue());
+ for (String info : retArr) {
+ bw.write(info + "\n");
+ }
+ } catch (Exception dex) {
+ LOGGER.error("error trying to print detail info for a ghost-node: ", dex);
+ }
+ }
+
+ bw.write("\n ------------- Missing Dependent Edge ORPHAN NODES - detail: ");
+ for (Map.Entry<String, TitanVertex> entry : orphanNodeHash
+ .entrySet()) {
+ try {
+ String vid = entry.getKey();
+ bw.write("\n> Orphan Node Vid = " + vid + "\n");
+ ArrayList<String> retArr = showPropertiesForNode(
+ TRANSID, FROMAPPID, entry.getValue());
+ for (String info : retArr) {
+ bw.write(info + "\n");
+ }
+
+ retArr = showAllEdgesForNode(TRANSID, FROMAPPID,
+ entry.getValue());
+ for (String info : retArr) {
+ bw.write(info + "\n");
+ }
+ } catch (Exception dex) {
+ LOGGER.error("error trying to print detail info for a Orphan Node /missing dependent edge", dex);
+ }
+ }
+
+ bw.write("\n ------------- Missing Dependent Edge (but not orphan) NODES: ");
+ for (Map.Entry<String, TitanVertex> entry : missingDepNodeHash
+ .entrySet()) {
+ try {
+ String vid = entry.getKey();
+ bw.write("\n> Missing edge to Dependent Node (but has edges) Vid = "
+ + vid + "\n");
+ ArrayList<String> retArr = showPropertiesForNode(
+ TRANSID, FROMAPPID, entry.getValue());
+ for (String info : retArr) {
+ bw.write(info + "\n");
+ }
+
+ retArr = showAllEdgesForNode(TRANSID, FROMAPPID,
+ entry.getValue());
+ for (String info : retArr) {
+ bw.write(info + "\n");
+ }
+ } catch (Exception dex) {
+ LOGGER.error("error trying to print detail info for a node missing its dependent edge but not an orphan", dex);
+ }
+ }
+
+ bw.write("\n ------------- EDGES pointing to empty/bad vertices: ");
+ for (Map.Entry<String, Edge> entry : oneArmedEdgeHash.entrySet()) {
+ try {
+ String eid = entry.getKey();
+ Edge thisE = entry.getValue();
+ String badVid = emptyVertexHash.get(eid);
+ bw.write("\n> Edge pointing to bad vertex (Vid = "
+ + badVid + ") EdgeId = " + eid + "\n");
+ bw.write("Label: [" + thisE.label() + "]\n");
+ Iterator<Property<Object>> pI = thisE.properties();
+ while (pI.hasNext()) {
+ Property<Object> propKey = pI.next();
+ bw.write("Prop: [" + propKey + "], val = ["
+ + propKey.value() + "]\n");
+ }
+ } catch (Exception pex) {
+ LOGGER.error("error trying to print empty/bad vertex data: ", pex);
+ }
+ }
+
+ bw.write("\n ------------- Duplicates: ");
+ Iterator<String> dupeIter = dupeGroups.iterator();
+ int dupeSetCounter = 0;
+ while (dupeIter.hasNext()) {
+ dupeSetCounter++;
+ String dset = (String) dupeIter.next();
+
+ bw.write("\n --- Duplicate Group # " + dupeSetCounter
+ + " Detail -----------\n");
+ try {
+ // We expect each line to have at least two vid's, followed
+ // by the preferred one to KEEP
+ String[] dupeArr = dset.split("\\|");
+ ArrayList<String> idArr = new ArrayList<>();
+ int lastIndex = dupeArr.length - 1;
+ for (int i = 0; i <= lastIndex; i++) {
+ if (i < lastIndex) {
+ // This is not the last entry, it is one of the
+ // dupes, so we want to show all its info
+ bw.write(" >> Duplicate Group # "
+ + dupeSetCounter + " Node # " + i
+ + " ----\n");
+ String vidString = dupeArr[i];
+ idArr.add(vidString);
+ long longVertId = Long.parseLong(vidString);
+ Iterator<Vertex> vtxIterator = g.vertices(longVertId);
+ TitanVertex vtx = null;
+ if (vtxIterator.hasNext()) {
+ vtx = (TitanVertex)vtxIterator.next();
+ }
+ ArrayList<String> retArr = showPropertiesForNode(TRANSID, FROMAPPID, vtx);
+ for (String info : retArr) {
+ bw.write(info + "\n");
+ }
+
+ retArr = showAllEdgesForNode(TRANSID,
+ FROMAPPID, vtx);
+ for (String info : retArr) {
+ bw.write(info + "\n");
+ }
+ } else {
+ // This is the last entry which should tell us if we
+ // have a preferred keeper
+ String prefString = dupeArr[i];
+ if (prefString.equals("KeepVid=UNDETERMINED")) {
+ bw.write("\n For this group of duplicates, could not tell which one to keep.\n");
+ bw.write(" >>> This group needs to be taken care of with a manual/forced-delete.\n");
+ } else {
+ // If we know which to keep, then the prefString
+ // should look like, "KeepVid=12345"
+ String[] prefArr = prefString.split("=");
+ if (prefArr.length != 2
+ || (!prefArr[0].equals("KeepVid"))) {
+ throw new Exception("Bad format. Expecting KeepVid=999999");
+ } else {
+ String keepVidStr = prefArr[1];
+ if (idArr.contains(keepVidStr)) {
+ bw.write("\n The vertex we want to KEEP has vertexId = "
+ + keepVidStr);
+ bw.write("\n The others become delete candidates: \n");
+ idArr.remove(keepVidStr);
+ for (int x = 0; x < idArr.size(); x++) {
+ cleanupCandidateCount++;
+ bw.write("DeleteCandidate: Duplicate Vid = ["
+ + idArr.get(x) + "]\n");
+ }
+ } else {
+ throw new Exception("ERROR - Vertex Id to keep not found in list of dupes. dset = ["
+ + dset + "]");
+ }
+ }
+ }// else we know which one to keep
+ }// else last entry
+ }// for each vertex in a group
+ } catch (Exception dex) {
+ LOGGER.error("error trying to print duplicate vertex data", dex);
+ }
+
+ }// while - work on each group of dupes
+
+ bw.write("\n ------------- Mis-matched Label/aai-node-type Nodes: \n ");
+ for (Map.Entry<String, String> entry : misMatchedHash.entrySet()) {
+ String msg = entry.getValue();
+ bw.write("MixedMsg = " + msg + "\n");
+ }
+
+ bw.write("\n ------------- Got these errors while processing: \n");
+ Iterator<String> errIter = errArr.iterator();
+ while (errIter.hasNext()) {
+ String line = (String) errIter.next();
+ bw.write(line + "\n");
+ }
+
+ bw.close();
+
+ LOGGER.info("\n ------------- Done doing all the checks ------------ ");
+ LOGGER.info("Output will be written to " + fullOutputFileName);
+
+ if (cleanupCandidateCount > 0) {
+ // Technically, this is not an error -- but we're throwing this
+ // error so that hopefully a
+ // monitoring system will pick it up and do something with it.
+ throw new AAIException("AAI_6123", "See file: [" + fullOutputFileName
+ + "] and investigate delete candidates. ");
+ }
+ } catch (AAIException e) {
+ LOGGER.error("Caught AAIException while grooming data", e);
+ ErrorLogHelper.logException(e);
+ } catch (Exception ex) {
+ LOGGER.error("Caught exception while grooming data", ex);
+ ErrorLogHelper.logError("AAI_6128", ex.getMessage() + ", resolve and rerun dataGrooming");
+ } finally {
+
+ if (bw != null) {
+ try {
+ bw.close();
+ } catch (IOException iox) {
+ LOGGER.warn("Got an IOException trying to close bufferedWriter() \n", iox);
+ }
+ }
+
+ if (g != null && !g.isClosed()) {
+ // Any changes that worked correctly should have already done
+ // their commits.
+ try {
+ if (executeFinalCommit) {
+ g.commit();
+ }
+ g.rollback();
+ } catch (Exception ex) {
+ // Don't throw anything because Titan sometimes is just saying that the graph is already closed
+ LOGGER.warn("WARNING from final graphTransaction.rollback()", ex);
+ }
+ }
+
+ if (g2 != null && !g2.isClosed()) {
+ // Any changes that worked correctly should have already done
+ // their commits.
+ try {
+ g2.rollback();
+ } catch (Exception ex) {
+ // Don't throw anything because Titan sometimes is just saying that the graph is already closed
+ LOGGER.warn("WARNING from final graphTransaction2.rollback()", ex);
+ }
+ }
+
+ if( finalShutdownFlag ){
+ try {
+ if( graph != null && graph.isOpen() ){
+ graph.tx().close();
+ graph.close();
+ }
+ } catch (Exception ex) {
+ // Don't throw anything because Titan sometimes is just saying that the graph is already closed{
+ LOGGER.warn("WARNING from final graph.shutdown()", ex);
+ }
+
+ try {
+ if( graph2 != null && graph2.isOpen() ){
+ graph2.tx().close();
+ graph2.close();
+ }
+ } catch (Exception ex) {
+ // Don't throw anything because Titan sometimes is just saying that the graph is already closed{
+ LOGGER.warn("WARNING from final graph2.shutdown()", ex);
+ }
+ }
+
+ }
+
+ return cleanupCandidateCount;
+
+ }// end of doTheGrooming()
+
+
+ /**
+ * Vertex has these keys.
+ *
+ * @param tmpV the tmp V
+ * @param propHashWithKeys the prop hash with keys
+ * @return the boolean
+ */
+ private static Boolean vertexHasTheseKeys( TitanVertex tmpV, HashMap <String, Object> propHashWithKeys) {
+ Iterator <?> it = propHashWithKeys.entrySet().iterator();
+ while( it.hasNext() ){
+ String propName = "";
+ String propVal = "";
+ Map.Entry <?,?>propEntry = (Map.Entry<?,?>)it.next();
+ Object propNameObj = propEntry.getKey();
+ if( propNameObj != null ){
+ propName = propNameObj.toString();
+ }
+ Object propValObj = propEntry.getValue();
+ if( propValObj != null ){
+ propVal = propValObj.toString();
+ }
+ Object checkValObj = tmpV.<Object>property(propName).orElse(null);
+ if( checkValObj == null ) {
+ return false;
+ }
+ else if( !propVal.equals(checkValObj.toString()) ){
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ /**
+ * Any key fields missing.
+ *
+ * @param nType the n type
+ * @param v the v
+ * @return the boolean
+ */
+ private static Boolean anyKeyFieldsMissing(String nType, Vertex v, DbMaps dbMaps) {
+
+ try {
+ // Determine what the key fields are for this nodeType
+ Collection <String> keyPropNamesColl = new ArrayList <>();
+ if( dbMaps.NodeKeyProps.containsKey(nType) ){
+ keyPropNamesColl = dbMaps.NodeKeyProps.get(nType);
+ }
+ else {
+ throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nType + ")");
+ }
+
+ Iterator<String> keyPropI = keyPropNamesColl.iterator();
+ while (keyPropI.hasNext()) {
+ String propName = keyPropI.next();
+ Object ob = v.<Object>property(propName).orElse(null);
+ if (ob == null || ob.toString().equals("")) {
+ // It is missing a key property
+ return true;
+ }
+ }
+ } catch (AAIException e) {
+ // Something was wrong
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Gets the delete list.
+ *
+ * @param targetDir the target dir
+ * @param fileName the file name
+ * @param edgesOnlyFlag the edges only flag
+ * @param dontFixOrphans the dont fix orphans
+ * @param dupeFixOn the dupe fix on
+ * @return the delete list
+ * @throws AAIException the AAI exception
+ */
+ private static Set<String> getDeleteList(String targetDir,
+ String fileName, Boolean edgesOnlyFlag, Boolean dontFixOrphans,
+ Boolean dupeFixOn) throws AAIException {
+
+ // Look in the file for lines formated like we expect - pull out any
+ // Vertex Id's to delete on this run
+ Set<String> delList = new LinkedHashSet<>();
+ String fullFileName = targetDir + AAIConstants.AAI_FILESEP + fileName;
+ BufferedReader br = null;
+
+ try {
+ br = new BufferedReader(new FileReader(fullFileName));
+ String line = br.readLine();
+ while (line != null) {
+ if (!line.equals("") && line.startsWith("DeleteCandidate")) {
+ if (edgesOnlyFlag && (!line.contains("Bad Edge"))) {
+ // We're not going to process edge guys
+ } else if (dontFixOrphans && line.contains("Orphan")) {
+ // We're not going to process orphans
+ } else if (!dupeFixOn && line.contains("Duplicate")) {
+ // We're not going to process Duplicates
+ } else {
+ int begIndex = line.indexOf("id = ");
+ int endIndex = line.indexOf("]");
+ String vidVal = line.substring(begIndex + 6, endIndex);
+ delList.add(vidVal);
+ }
+ }
+ line = br.readLine();
+ }
+ br.close();
+ } catch (IOException e) {
+ throw new AAIException("AAI_6124", e, "Could not open input-file [" + fullFileName
+ + "], exception= " + e.getMessage());
+ }
+
+ return delList;
+
+ }// end of getDeleteList
+
+ /**
+ * Gets the preferred dupe.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param g the g
+ * @param dupeVertexList the dupe vertex list
+ * @param ver the ver
+ * @return TitanVertex
+ * @throws AAIException the AAI exception
+ */
+ public static TitanVertex getPreferredDupe(String transId,
+ String fromAppId, TitanTransaction g,
+ ArrayList<TitanVertex> dupeVertexList, String ver, DbMaps dbMaps)
+ throws AAIException {
+
+ // This method assumes that it is being passed a List of vertex objects
+ // which
+ // violate our uniqueness constraints.
+
+ TitanVertex nullVtx = null;
+
+ if (dupeVertexList == null) {
+ return nullVtx;
+ }
+ int listSize = dupeVertexList.size();
+ if (listSize == 0) {
+ return nullVtx;
+ }
+ if (listSize == 1) {
+ return ((TitanVertex) dupeVertexList.get(0));
+ }
+
+ TitanVertex vtxPreferred = null;
+ TitanVertex currentFaveVtx = (TitanVertex) dupeVertexList.get(0);
+ for (int i = 1; i < listSize; i++) {
+ TitanVertex vtxB = (TitanVertex) dupeVertexList.get(i);
+ vtxPreferred = pickOneOfTwoDupes(transId, fromAppId, g,
+ currentFaveVtx, vtxB, ver, dbMaps);
+ if (vtxPreferred == null) {
+ // We couldn't choose one
+ return nullVtx;
+ } else {
+ currentFaveVtx = vtxPreferred;
+ }
+ }
+
+ return (currentFaveVtx);
+
+ } // end of getPreferredDupe()
+
+ /**
+ * Pick one of two dupes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param g the g
+ * @param vtxA the vtx A
+ * @param vtxB the vtx B
+ * @param ver the ver
+ * @return TitanVertex
+ * @throws AAIException the AAI exception
+ */
+ public static TitanVertex pickOneOfTwoDupes(String transId,
+ String fromAppId, TitanTransaction g, TitanVertex vtxA,
+ TitanVertex vtxB, String ver, DbMaps dbMaps) throws AAIException {
+
+ TitanVertex nullVtx = null;
+ TitanVertex preferredVtx = null;
+
+ Long vidA = new Long(vtxA.id().toString());
+ Long vidB = new Long(vtxB.id().toString());
+
+ String vtxANodeType = "";
+ String vtxBNodeType = "";
+ Object obj = vtxA.<Object>property("aai-node-type").orElse(null);
+ if (obj != null) {
+ vtxANodeType = obj.toString();
+ }
+ obj = vtxB.<Object>property("aai-node-type").orElse(null);
+ if (obj != null) {
+ vtxBNodeType = obj.toString();
+ }
+
+ if (vtxANodeType.equals("") || (!vtxANodeType.equals(vtxBNodeType))) {
+ // Either they're not really dupes or there's some bad data - so
+ // don't pick one
+ return nullVtx;
+ }
+
+ // Check that node A and B both have the same key values (or else they
+ // are not dupes)
+ // (We'll check dep-node later)
+ // Determine what the key fields are for this nodeType
+ Collection <String> keyProps = new ArrayList <>();
+ if( dbMaps.NodeKeyProps.containsKey(vtxANodeType) ){
+ keyProps = dbMaps.NodeKeyProps.get(vtxANodeType);
+ }
+ else {
+ throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + vtxANodeType + ")");
+ }
+
+ Iterator<String> keyPropI = keyProps.iterator();
+ while (keyPropI.hasNext()) {
+ String propName = keyPropI.next();
+ String vtxAKeyPropVal = "";
+ obj = vtxA.<Object>property(propName).orElse(null);
+ if (obj != null) {
+ vtxAKeyPropVal = obj.toString();
+ }
+ String vtxBKeyPropVal = "";
+ obj = vtxB.<Object>property(propName).orElse(null);
+ if (obj != null) {
+ vtxBKeyPropVal = obj.toString();
+ }
+
+ if (vtxAKeyPropVal.equals("")
+ || (!vtxAKeyPropVal.equals(vtxBKeyPropVal))) {
+ // Either they're not really dupes or they are missing some key
+ // data - so don't pick one
+ return nullVtx;
+ }
+ }
+
+ // Collect the vid's and aai-node-types of the vertices that each vertex
+ // (A and B) is connected to.
+ ArrayList<String> vtxIdsConn2A = new ArrayList<>();
+ ArrayList<String> vtxIdsConn2B = new ArrayList<>();
+ HashMap<String, String> nodeTypesConn2A = new HashMap<>();
+ HashMap<String, String> nodeTypesConn2B = new HashMap<>();
+
+ ArrayList<TitanVertex> vertListA = getConnectedNodes( g, vtxA );
+ if (vertListA != null) {
+ Iterator<TitanVertex> iter = vertListA.iterator();
+ while (iter.hasNext()) {
+ TitanVertex tvCon = iter.next();
+ String conVid = tvCon.id().toString();
+ String nt = "";
+ obj = tvCon.<Object>property("aai-node-type").orElse(null);
+ if (obj != null) {
+ nt = obj.toString();
+ }
+ nodeTypesConn2A.put(nt, conVid);
+ vtxIdsConn2A.add(conVid);
+ }
+ }
+
+ ArrayList<TitanVertex> vertListB = getConnectedNodes( g, vtxB );
+ if (vertListB != null) {
+ Iterator<TitanVertex> iter = vertListB.iterator();
+ while (iter.hasNext()) {
+ TitanVertex tvCon = iter.next();
+ String conVid = tvCon.id().toString();
+ String nt = "";
+ obj = tvCon.<Object>property("aai-node-type").orElse(null);
+ if (obj != null) {
+ nt = obj.toString();
+ }
+ nodeTypesConn2B.put(nt, conVid);
+ vtxIdsConn2B.add(conVid);
+ }
+ }
+
+ // 1 - If this kind of node needs a dependent node for uniqueness, then
+ // verify that they both nodes
+ // point to the same dependent node (otherwise they're not really
+ // duplicates)
+ // Note - there are sometimes more than one dependent node type since
+ // one nodeType can be used in
+ // different ways. But for a particular node, it will only have one
+ // dependent node that it's
+ // connected to.
+ Collection <String> depNodeTypes = new ArrayList <>();
+ if( dbMaps.NodeDependencies.containsKey(vtxANodeType) ){
+ depNodeTypes = dbMaps.NodeDependencies.get(vtxANodeType);
+ }
+
+ if (depNodeTypes.isEmpty()) {
+ // This kind of node is not dependent on any other. That is ok.
+ } else {
+ String depNodeVtxId4A = "";
+ String depNodeVtxId4B = "";
+ Iterator<String> iter = depNodeTypes.iterator();
+ while (iter.hasNext()) {
+ String depNodeType = iter.next();
+ if (nodeTypesConn2A.containsKey(depNodeType)) {
+ // This is the dependent node type that vertex A is using
+ depNodeVtxId4A = nodeTypesConn2A.get(depNodeType);
+ }
+ if (nodeTypesConn2B.containsKey(depNodeType)) {
+ // This is the dependent node type that vertex B is using
+ depNodeVtxId4B = nodeTypesConn2B.get(depNodeType);
+ }
+ }
+ if (depNodeVtxId4A.equals("")
+ || (!depNodeVtxId4A.equals(depNodeVtxId4B))) {
+ // Either they're not really dupes or there's some bad data - so
+ // don't pick either one
+ return nullVtx;
+ }
+ }
+
+ if (vtxIdsConn2A.size() == vtxIdsConn2B.size()) {
+ // 2 - If they both have edges to all the same vertices, then return
+ // the one with the lower vertexId.
+ boolean allTheSame = true;
+ Iterator<String> iter = vtxIdsConn2A.iterator();
+ while (iter.hasNext()) {
+ String vtxIdConn2A = iter.next();
+ if (!vtxIdsConn2B.contains(vtxIdConn2A)) {
+ allTheSame = false;
+ break;
+ }
+ }
+
+ if (allTheSame) {
+ if (vidA < vidB) {
+ preferredVtx = vtxA;
+ } else {
+ preferredVtx = vtxB;
+ }
+ }
+ } else if (vtxIdsConn2A.size() > vtxIdsConn2B.size()) {
+ // 3 - VertexA is connected to more things than vtxB.
+ // We'll pick VtxA if its edges are a superset of vtxB's edges.
+ boolean missingOne = false;
+ Iterator<String> iter = vtxIdsConn2B.iterator();
+ while (iter.hasNext()) {
+ String vtxIdConn2B = iter.next();
+ if (!vtxIdsConn2A.contains(vtxIdConn2B)) {
+ missingOne = true;
+ break;
+ }
+ }
+ if (!missingOne) {
+ preferredVtx = vtxA;
+ }
+ } else if (vtxIdsConn2B.size() > vtxIdsConn2A.size()) {
+ // 4 - VertexB is connected to more things than vtxA.
+ // We'll pick VtxB if its edges are a superset of vtxA's edges.
+ boolean missingOne = false;
+ Iterator<String> iter = vtxIdsConn2A.iterator();
+ while (iter.hasNext()) {
+ String vtxIdConn2A = iter.next();
+ if (!vtxIdsConn2B.contains(vtxIdConn2A)) {
+ missingOne = true;
+ break;
+ }
+ }
+ if (!missingOne) {
+ preferredVtx = vtxB;
+ }
+ } else {
+ preferredVtx = nullVtx;
+ }
+
+ return (preferredVtx);
+
+ } // end of pickOneOfTwoDupes()
+
+ /**
+ * Check and process dupes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param g the g
+ * @param version the version
+ * @param nType the n type
+ * @param passedVertList the passed vert list
+ * @param dupeFixOn the dupe fix on
+ * @param deleteCandidateList the delete candidate list
+ * @param singleCommits the single commits
+ * @param alreadyFoundDupeGroups the already found dupe groups
+ * @param dbMaps the db maps
+ * @return the array list
+ */
+ private static List<String> checkAndProcessDupes(String transId,
+ String fromAppId, TitanTransaction g, String version, String nType,
+ List<TitanVertex> passedVertList, Boolean dupeFixOn,
+ Set<String> deleteCandidateList, Boolean singleCommits,
+ ArrayList<String> alreadyFoundDupeGroups, DbMaps dbMaps ) {
+
+ ArrayList<String> returnList = new ArrayList<>();
+ ArrayList<TitanVertex> checkVertList = new ArrayList<>();
+ ArrayList<String> alreadyFoundDupeVidArr = new ArrayList<>();
+ Boolean noFilterList = true;
+ Iterator<String> afItr = alreadyFoundDupeGroups.iterator();
+ while (afItr.hasNext()) {
+ String dupeGrpStr = afItr.next();
+ String[] dupeArr = dupeGrpStr.split("\\|");
+ int lastIndex = dupeArr.length - 1;
+ for (int i = 0; i < lastIndex; i++) {
+ // Note: we don't want the last one...
+ String vidString = dupeArr[i];
+ alreadyFoundDupeVidArr.add(vidString);
+ noFilterList = false;
+ }
+ }
+
+ // For a given set of Nodes that were found with a set of KEY
+ // Parameters, (nodeType + key data) we will
+ // see if we find any duplicate nodes that need to be cleaned up. Note -
+ // it's legit to have more than one
+ // node with the same key data if the nodes depend on a parent for
+ // uniqueness -- as long as the two nodes
+ // don't hang off the same Parent.
+ // If we find duplicates, and we can figure out which of each set of
+ // duplicates is the one that we
+ // think should be preserved, we will record that. Whether we can tell
+ // which one should be
+ // preserved or not, we will return info about any sets of duplicates
+ // found.
+ //
+ // Each element in the returned arrayList might look like this:
+ // "1234|5678|keepVid=UNDETERMINED" (if there were 2 dupes, and we
+ // couldn't figure out which one to keep)
+ // or, "100017|200027|30037|keepVid=30037" (if there were 3 dupes and we
+ // thought the third one was the one that should survive)
+
+ // Because of the way the calling code loops over stuff, we can get the
+ // same data multiple times - so we should
+ // not process any vertices that we've already seen.
+
+ try {
+ Iterator<TitanVertex> pItr = passedVertList.iterator();
+ while (pItr.hasNext()) {
+ TitanVertex tvx = (TitanVertex) pItr.next();
+ String passedId = tvx.id().toString();
+ if (noFilterList || !alreadyFoundDupeVidArr.contains(passedId)) {
+ // We haven't seen this one before - so we should check it.
+ checkVertList.add(tvx);
+ }
+ }
+
+ if (checkVertList.size() < 2) {
+ // Nothing new to check.
+ return returnList;
+ }
+
+ if (!dbMaps.NodeDependencies.containsKey(nType)) {
+ // If this was a node that does NOT depend on other nodes for
+ // uniqueness, and we
+ // found more than one node using its key -- record the found
+ // vertices as duplicates.
+ String dupesStr = "";
+ for (int i = 0; i < checkVertList.size(); i++) {
+ dupesStr = dupesStr
+ + ((TitanVertex) (checkVertList.get(i))).id()
+ .toString() + "|";
+ }
+ if (dupesStr != "") {
+ TitanVertex prefV = getPreferredDupe(transId, fromAppId,
+ g, checkVertList, version, dbMaps);
+ if (prefV == null) {
+ // We could not determine which duplicate to keep
+ dupesStr = dupesStr + "KeepVid=UNDETERMINED";
+ returnList.add(dupesStr);
+ } else {
+ dupesStr = dupesStr + "KeepVid=" + prefV.id();
+ Boolean didRemove = false;
+ if (dupeFixOn) {
+ didRemove = deleteNonKeepersIfAppropriate(g,
+ dupesStr, prefV.id().toString(),
+ deleteCandidateList, singleCommits);
+ }
+ if (didRemove) {
+ dupeGrpsDeleted++;
+ } else {
+ // keep them on our list
+ returnList.add(dupesStr);
+ }
+ }
+ }
+ } else {
+ // More than one node have the same key fields since they may
+ // depend on a parent node for
+ // uniqueness. Since we're finding more than one, we want to
+ // check to see if any of the
+ // vertices that have this set of keys are also pointing at the
+ // same 'parent' node.
+ // Note: for a given set of key data, it is possible that there
+ // could be more than one set of
+ // duplicates.
+ HashMap<String, ArrayList<TitanVertex>> vertsGroupedByParentHash = groupVertsByDepNodes(
+ transId, fromAppId, g, version, nType,
+ checkVertList, dbMaps);
+ for (Map.Entry<String, ArrayList<TitanVertex>> entry : vertsGroupedByParentHash
+ .entrySet()) {
+ ArrayList<TitanVertex> thisParentsVertList = entry
+ .getValue();
+ if (thisParentsVertList.size() > 1) {
+ // More than one vertex found with the same key info
+ // hanging off the same parent/dependent node
+ String dupesStr = "";
+ for (int i = 0; i < thisParentsVertList.size(); i++) {
+ dupesStr = dupesStr
+ + ((TitanVertex) (thisParentsVertList
+ .get(i))).id() + "|";
+ }
+ if (dupesStr != "") {
+ TitanVertex prefV = getPreferredDupe(transId,
+ fromAppId, g, thisParentsVertList,
+ version, dbMaps);
+
+ if (prefV == null) {
+ // We could not determine which duplicate to
+ // keep
+ dupesStr = dupesStr + "KeepVid=UNDETERMINED";
+ returnList.add(dupesStr);
+ } else {
+ Boolean didRemove = false;
+ dupesStr = dupesStr + "KeepVid="
+ + prefV.id().toString();
+ if (dupeFixOn) {
+ didRemove = deleteNonKeepersIfAppropriate(
+ g, dupesStr, prefV.id()
+ .toString(),
+ deleteCandidateList, singleCommits);
+ }
+ if (didRemove) {
+ dupeGrpsDeleted++;
+ } else {
+ // keep them on our list
+ returnList.add(dupesStr);
+ }
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ LOGGER.warn(" >>> Threw an error in checkAndProcessDupes - just absorb this error and move on. ", e);
+ }
+
+ return returnList;
+
+ }// End of checkAndProcessDupes()
+
+ /**
+ * Group verts by dep nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param g the g
+ * @param version the version
+ * @param nType the n type
+ * @param passedVertList the passed vert list
+ * @param dbMaps the db maps
+ * @return the hash map
+ * @throws AAIException the AAI exception
+ */
+ private static HashMap<String, ArrayList<TitanVertex>> groupVertsByDepNodes(
+ String transId, String fromAppId, TitanTransaction g, String version,
+ String nType, ArrayList<TitanVertex> passedVertList, DbMaps dbMaps)
+ throws AAIException {
+ // Given a list of Titan Vertices, group them together by dependent
+ // nodes. Ie. if given a list of
+ // ip address nodes (assumed to all have the same key info) they might
+ // sit under several different parent vertices.
+ // Under Normal conditions, there would only be one per parent -- but
+ // we're trying to find duplicates - so we
+ // allow for the case where more than one is under the same parent node.
+
+ HashMap<String, ArrayList<TitanVertex>> retHash = new HashMap<String, ArrayList<TitanVertex>>();
+ if (!dbMaps.NodeDependencies.containsKey(nType)) {
+ // This method really should not have been called if this is not the
+ // kind of node
+ // that depends on a parent for uniqueness, so just return the empty
+ // hash.
+ return retHash;
+ }
+
+ // Find out what types of nodes the passed in nodes can depend on
+ ArrayList<String> depNodeTypeL = new ArrayList<>();
+ Collection<String> depNTColl = dbMaps.NodeDependencies.get(nType);
+ Iterator<String> ntItr = depNTColl.iterator();
+ while (ntItr.hasNext()) {
+ depNodeTypeL.add(ntItr.next());
+ }
+ // For each vertex, we want find its dependent vertex and add it to
+ // other vertexes that are dependent on that same guy.
+ if (passedVertList != null) {
+ Iterator<TitanVertex> iter = passedVertList.iterator();
+ while (iter.hasNext()) {
+ TitanVertex thisVert = iter.next();
+ ArrayList<TitanVertex> connectedVList = getConnectedNodes( g, thisVert );
+ Iterator<TitanVertex> connIter = connectedVList.iterator();
+ while (connIter.hasNext()) {
+ TitanVertex tvCon = connIter.next();
+ String conNt = "";
+ Object obj = tvCon.<Object>property("aai-node-type").orElse(null);
+ if (obj != null) {
+ conNt = obj.toString();
+ }
+ if (depNTColl.contains(conNt)) {
+ // This must be the parent/dependent node
+ String parentVid = tvCon.id().toString();
+ if (retHash.containsKey(parentVid)) {
+ // add this vert to the list for this parent key
+ retHash.get(parentVid).add(thisVert);
+ } else {
+ // This is the first one we found on this parent
+ ArrayList<TitanVertex> vList = new ArrayList<>();
+ vList.add(thisVert);
+ retHash.put(parentVid, vList);
+ }
+ }
+ }
+ }
+ }
+
+ return retHash;
+
+ }// end of groupVertsByDepNodes()
+
+ /**
+ * Delete non keepers if appropriate.
+ *
+ * @param g the g
+ * @param dupeInfoString the dupe info string
+ * @param vidToKeep the vid to keep
+ * @param deleteCandidateList the delete candidate list
+ * @param singleCommits the single commits
+ * @return the boolean
+ */
+ private static Boolean deleteNonKeepersIfAppropriate(TitanTransaction g,
+ String dupeInfoString, String vidToKeep,
+ Set<String> deleteCandidateList, Boolean singleCommits) {
+
+ Boolean deletedSomething = false;
+ // This assumes that the dupeInfoString is in the format of
+ // pipe-delimited vid's followed by
+ // ie. "3456|9880|keepVid=3456"
+ if (deleteCandidateList == null || deleteCandidateList.size() == 0) {
+ // No vid's on the candidate list -- so no deleting will happen on
+ // this run
+ return false;
+ }
+
+ String[] dupeArr = dupeInfoString.split("\\|");
+ ArrayList<String> idArr = new ArrayList<>();
+ int lastIndex = dupeArr.length - 1;
+ for (int i = 0; i <= lastIndex; i++) {
+ if (i < lastIndex) {
+ // This is not the last entry, it is one of the dupes,
+ String vidString = dupeArr[i];
+ idArr.add(vidString);
+ } else {
+ // This is the last entry which should tell us if we have a
+ // preferred keeper
+ String prefString = dupeArr[i];
+ if (prefString.equals("KeepVid=UNDETERMINED")) {
+ // They sent us a bad string -- nothing should be deleted if
+ // no dupe could be tagged as preferred
+ return false;
+ } else {
+ // If we know which to keep, then the prefString should look
+ // like, "KeepVid=12345"
+ String[] prefArr = prefString.split("=");
+ if (prefArr.length != 2 || (!prefArr[0].equals("KeepVid"))) {
+ LOGGER.error("Bad format. Expecting KeepVid=999999");
+ return false;
+ } else {
+ String keepVidStr = prefArr[1];
+ if (idArr.contains(keepVidStr)) {
+ idArr.remove(keepVidStr);
+
+ // So now, the idArr should just contain the vid's
+ // that we want to remove.
+ for (int x = 0; x < idArr.size(); x++) {
+ boolean okFlag = true;
+ String thisVid = idArr.get(x);
+ if (deleteCandidateList.contains(thisVid)) {
+ // This vid is a valid delete candidate from
+ // a prev. run, so we can remove it.
+ try {
+ long longVertId = Long
+ .parseLong(thisVid);
+ TitanVertex vtx = g
+ .getVertex(longVertId);
+ vtx.remove();
+ if (singleCommits) {
+ // NOTE - the singleCommits option is not used in normal processing
+ g.commit();
+ g = AAIGraph.getInstance().getGraph().newTransaction();
+ }
+ } catch (Exception e) {
+ okFlag = false;
+ LOGGER.error("ERROR trying to delete VID = " + thisVid, e);
+ }
+ if (okFlag) {
+ LOGGER.info(" DELETED VID = " + thisVid);
+ deletedSomething = true;
+ }
+ }
+ }
+ } else {
+ LOGGER.error("ERROR - Vertex Id to keep not found in list of dupes. dupeInfoString = ["
+ + dupeInfoString + "]");
+ return false;
+ }
+ }
+ }// else we know which one to keep
+ }// else last entry
+ }// for each vertex in a group
+
+ return deletedSomething;
+
+ }// end of deleteNonKeepersIfAppropriate()
+
+
+ /**
+ * Gets the node just using key params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param keyPropsHash the key props hash
+ * @param apiVersion the api version
+ * @return the node just using key params
+ * @throws AAIException the AAI exception
+ */
+ public static List <TitanVertex> getNodeJustUsingKeyParams( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> keyPropsHash, String apiVersion ) throws AAIException{
+
+ List <TitanVertex> retVertList = new ArrayList <> ();
+
+ // We assume that all NodeTypes have at least one key-property defined.
+ // Note - instead of key-properties (the primary key properties), a user could pass
+ // alternate-key values if they are defined for the nodeType.
+ List<String> kName = new ArrayList<>();
+ List<Object> kVal = new ArrayList<>();
+ if( keyPropsHash == null || keyPropsHash.isEmpty() ) {
+ throw new AAIException("AAI_6120", " NO key properties passed for this getNodeJustUsingKeyParams() request. NodeType = [" + nodeType + "]. ");
+ }
+
+ int i = -1;
+ for( Map.Entry<String, Object> entry : keyPropsHash.entrySet() ){
+ i++;
+ kName.add(i, entry.getKey());
+ kVal.add(i, entry.getValue());
+ }
+ int topPropIndex = i;
+ TitanVertex tiV = null;
+ String propsAndValuesForMsg = "";
+ Iterable <?> verts = null;
+
+ try {
+ if( topPropIndex == 0 ){
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ") ";
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has("aai-node-type",nodeType).vertices();
+ }
+ else if( topPropIndex == 1 ){
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ") ";
+ verts = graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has("aai-node-type",nodeType).vertices();
+ }
+ else if( topPropIndex == 2 ){
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ", "
+ + kName.get(2) + " = " + kVal.get(2) + ") ";
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).has("aai-node-type",nodeType).vertices();
+ }
+ else if( topPropIndex == 3 ){
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ", "
+ + kName.get(2) + " = " + kVal.get(2) + ", "
+ + kName.get(3) + " = " + kVal.get(3) + ") ";
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).has(kName.get(3),kVal.get(3)).has("aai-node-type",nodeType).vertices();
+ }
+ else {
+ throw new AAIException("AAI_6114", " We only support 4 keys per nodeType for now \n");
+ }
+ }
+ catch( Exception ex ){
+ LOGGER.error( " ERROR trying to get node for: [" + propsAndValuesForMsg + "]", ex);
+ }
+
+ if( verts != null ){
+ Iterator <?> vertI = verts.iterator();
+ while( vertI.hasNext() ){
+ tiV = (TitanVertex) vertI.next();
+ retVertList.add(tiV);
+ }
+ }
+
+ if( retVertList.size() == 0 ){
+ LOGGER.debug("DEBUG No node found for nodeType = [" + nodeType +
+ "], propsAndVal = " + propsAndValuesForMsg );
+ }
+
+ return retVertList;
+
+ }// End of getNodeJustUsingKeyParams()
+
+ /**
+ * Show all edges for node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param tVert the t vert
+ * @return the array list
+ */
+ private static ArrayList <String> showAllEdgesForNode( String transId, String fromAppId, TitanVertex tVert ){
+
+ ArrayList <String> retArr = new ArrayList <> ();
+ Iterator <Edge> eI = tVert.edges(Direction.IN);
+ if( ! eI.hasNext() ){
+ retArr.add("No IN edges were found for this vertex. ");
+ }
+ while( eI.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI.next();
+ String lab = ed.label();
+ TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert);
+ if( vtx == null ){
+ retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< ");
+ }
+ else {
+ String nType = vtx.<String>property("aai-node-type").orElse(null);
+ String vid = vtx.id().toString();
+ retArr.add("Found an IN edge (" + lab + ") to this vertex from a [" + nType + "] node with VtxId = " + vid );
+
+ }
+ }
+
+ eI = tVert.edges(Direction.OUT);
+ if( ! eI.hasNext() ){
+ retArr.add("No OUT edges were found for this vertex. ");
+ }
+ while( eI.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI.next();
+ String lab = ed.label();
+ TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert);
+ if( vtx == null ){
+ retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< ");
+ }
+ else {
+ String nType = vtx.<String>property("aai-node-type").orElse(null);
+ String vid = vtx.id().toString();
+ retArr.add("Found an OUT edge (" + lab + ") from this vertex to a [" + nType + "] node with VtxId = " + vid );
+ }
+ }
+ return retArr;
+ }
+
+
+ /**
+ * Show properties for node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param tVert the t vert
+ * @return the array list
+ */
+ private static ArrayList <String> showPropertiesForNode( String transId, String fromAppId, TitanVertex tVert ){
+
+ ArrayList <String> retArr = new ArrayList <> ();
+ if( tVert == null ){
+ retArr.add("null Node object passed to showPropertiesForNode()\n");
+ }
+ else {
+ String nodeType = "";
+ Object ob = tVert.<Object>property("aai-node-type").orElse(null);
+ if( ob == null ){
+ nodeType = "null";
+ }
+ else{
+ nodeType = ob.toString();
+ }
+
+ retArr.add(" AAINodeType/VtxID for this Node = [" + nodeType + "/" + tVert.id() + "]");
+ retArr.add(" Property Detail: ");
+ Iterator<VertexProperty<Object>> pI = tVert.properties();
+ while( pI.hasNext() ){
+ VertexProperty<Object> tp = pI.next();
+ Object val = tp.value();
+ retArr.add("Prop: [" + tp.key() + "], val = [" + val + "] ");
+ }
+ }
+ return retArr;
+ }
+
+
+ private static ArrayList <TitanVertex> getConnectedNodes(TitanTransaction g, TitanVertex startVtx )
+ throws AAIException {
+
+ ArrayList <TitanVertex> retArr = new ArrayList <> ();
+ if( startVtx == null ){
+ return retArr;
+ }
+ else {
+ GraphTraversal<Vertex, Vertex> modPipe = null;
+ modPipe = g.traversal().V(startVtx).both();
+ if( modPipe != null && modPipe.hasNext() ){
+ while( modPipe.hasNext() ){
+ TitanVertex conVert = (TitanVertex) modPipe.next();
+ retArr.add(conVert);
+ }
+ }
+ }
+ return retArr;
+
+ }// End of getConnectedNodes()
+
+
+ private static ArrayList <TitanVertex> getConnectedChildren( TitanTransaction graph,
+ TitanVertex startVtx ) throws AAIException{
+
+ ArrayList <TitanVertex> childList = new ArrayList <> ();
+
+ Iterable <?> verts = startVtx.query().direction(Direction.OUT).has("isParent",true).vertices();
+ Iterator <?> vertI = verts.iterator();
+ TitanVertex tmpVtx = null;
+ while( vertI != null && vertI.hasNext() ){
+ tmpVtx = (TitanVertex) vertI.next();
+ childList.add(tmpVtx);
+ }
+
+ return childList;
+
+ }// End of getConnectedChildren()
+
+
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/dbgen/DbMeth.java b/aai-core/src/main/java/org/openecomp/aai/dbgen/DbMeth.java
new file mode 100644
index 00000000..db33e4dc
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/dbgen/DbMeth.java
@@ -0,0 +1,3643 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.dbgen;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+
+import org.openecomp.aai.dbmodel.DbEdgeRules;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.ingestModel.DbMaps;
+import org.openecomp.aai.ingestModel.IngestModelMoxyOxm;
+import org.openecomp.aai.serialization.db.EdgeRule;
+import org.openecomp.aai.serialization.db.EdgeRules;
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.net.InetAddresses;
+import com.thinkaurelius.titan.core.TitanEdge;
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.thinkaurelius.titan.core.TitanTransaction;
+import com.thinkaurelius.titan.core.TitanVertex;
+
+
+/**
+ * General Database-level Utility class. These methods deal with the database one dataNode / Edge at a time.
+ * Transactions are managed at a higher level by the calling classes by passing in a TitanTransaction object.
+ */
+public class DbMeth{
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DbMeth.class);
+
+ /**
+ * Patch aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param depNodeVal the dep node val
+ * @param apiVersion the api version
+ * @return TitanVertex
+ * @throws AAIException the AAI exception
+ */
+ public static TitanVertex patchAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, TitanVertex depNodeVal, String apiVersion ) throws AAIException{
+ // If they're calling patchAaiNode, then we only want to add/update the properties that they
+ // pass us in the propHash. If there are others already in the DB, we leave them alone.
+
+ // Note: to be really official, we'd throw an error if the node wasn't already in the db.
+ boolean[] objectExists = new boolean[1];
+ objectExists[0] = true;
+ Boolean patchOnly = true;
+ TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists);
+ return( tv );
+
+ } // end of patchAaiNode()
+
+ /**
+ * Patch aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param depNodeVal the dep node val
+ * @return the titan vertex
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanVertex patchAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, TitanVertex depNodeVal) throws AAIException{
+ return patchAaiNode( transId, fromAppId, graph, nodeType,
+ propHash, depNodeVal, null );
+ }
+
+ /**
+ * Persist aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param depNodeVal the dep node val
+ * @param patchOnly the patch only
+ * @param apiVersion the api version
+ * @return the titan vertex
+ * @throws AAIException the AAI exception
+ */
+ public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, TitanVertex depNodeVal, Boolean patchOnly, String apiVersion) throws AAIException{
+ boolean[] objectExists = new boolean[1];
+ objectExists[0] = false;
+ return persistAaiNodeBASE( transId, fromAppId, graph, nodeType,
+ propHash, depNodeVal, patchOnly, apiVersion, objectExists);
+ }
+
+ /**
+ * Persist aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param addIfNotFound the add if not found
+ * @param depNodeVal the dep node val
+ * @param apiVersion the api version
+ * @return the titan vertex
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal, String apiVersion) throws AAIException{
+ // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if
+ // there is already a record in the DB, but they do not pass some of the existing properties, they should
+ // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false
+ Boolean patchOnly = false;
+ boolean[] objectExists = new boolean[1];
+ objectExists[0] = false;
+ TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists);
+ return( tv );
+ }
+
+ /**
+ * Persist aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param addIfNotFound the add if not found
+ * @param depNodeVal the dep node val
+ * @return the titan vertex
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal) throws AAIException{
+ // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if
+ // there is already a record in the DB, but they do not pass some of the existing properties, they should
+ // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false
+ Boolean patchOnly = false;
+ boolean[] objectExists = new boolean[1];
+ objectExists[0] = false;
+ TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, null, objectExists);
+ return( tv );
+ } // end of persistAaiNode()
+
+ /**
+ * Persist aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param addIfNotFound the add if not found
+ * @param depNodeVal the dep node val
+ * @param apiVersion the api version
+ * @param objectExists the object exists
+ * @return TitanVertex
+ * @throws AAIException the AAI exception
+ */
+ public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal, String apiVersion, boolean[] objectExists) throws AAIException{
+ Boolean patchOnly = false;
+ // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if
+ // there is already a record in the DB, but they do not pass some of the existing properties, they should
+ // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false
+ TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists, null);
+ return( tv );
+ }
+
+ /**
+ * Persist aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param addIfNotFound the add if not found
+ * @param depNodeVal the dep node val
+ * @param apiVersion the api version
+ * @param objectExists the object exists
+ * @param thisNodeVertex the this node vertex
+ * @return the titan vertex
+ * @throws AAIException the AAI exception
+ */
+ public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal, String apiVersion, boolean[] objectExists, TitanVertex thisNodeVertex) throws AAIException{
+ Boolean patchOnly = false;
+ // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if
+ // there is already a record in the DB, but they do not pass some of the existing properties, they should
+ // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false
+ TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists, thisNodeVertex);
+ return( tv );
+ }
+
+ /**
+ * Persist aai node BASE.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param depNodeVal the dep node val
+ * @param patchOnly the patch only
+ * @param apiVersion the api version
+ * @param objectExists the object exists
+ * @return the titan vertex
+ * @throws AAIException the AAI exception
+ */
+ public static TitanVertex persistAaiNodeBASE(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, TitanVertex depNodeVal, Boolean patchOnly,
+ String apiVersion, boolean[] objectExists) throws AAIException{
+ return persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists, null);
+ }
+
+ /**
+ * Persist aai node BASE.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param depNodeVal the dep node val
+ * @param patchOnly the patch only
+ * @param apiVersion the api version
+ * @param objectExists the object exists
+ * @param thisNodeVertex the this node vertex
+ * @return the titan vertex
+ * @throws AAIException the AAI exception
+ */
+ public static TitanVertex persistAaiNodeBASE(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, TitanVertex depNodeVal, Boolean patchOnly,
+ String apiVersion, boolean[] objectExists, TitanVertex thisNodeVertex) throws AAIException{
+
+ if( graph == null ){
+ throw new AAIException("AAI_6101", "null graph object passed to persistAaiNodeBASE()");
+ }
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ boolean useDepNode = false;
+ String resourceVersion = null;
+ if( propHash.containsKey("resource-version") ){
+ resourceVersion = (String)(propHash.get("resource-version"));
+ }
+ String aaiUniqueKeyVal = null;
+ if( propHash.containsKey("aai-unique-key") ){
+ // Note -- we are assuming that nobody is monkeying with this. The 16-07 first-pass theory
+ // is that the REST layer is always gonna generate this or pass it through.
+ aaiUniqueKeyVal = (String)(propHash.get("aai-unique-key"));
+ propHash.remove("aai-unique-key");
+ }
+
+ if( needsADepNode4Uniqueness(transId, fromAppId, nodeType, apiVersion) ){
+ // This kind of node needs a dependent node (for uniqueness)
+ if( depNodeVal == null ){
+ // They should have passed in the node that this one depends on
+ throw new AAIException("AAI_6109", "null dependentNode object passed to persistAaiNodeBASE() but " + nodeType + " requires one.");
+ }
+ else if( ! nodeTypeACanDependOnB(transId, fromAppId, nodeType, depNodeVal.<String>property("aai-node-type").orElse(null), apiVersion) ){
+ // They should have passed in the right type of node as the dependent node
+ throw new AAIException("AAI_6109", "dependentNode of type " + depNodeVal.<String>property("aai-node-type").orElse(null) + " passed to persistAaiNodeBASE() for nodeType" + nodeType + ".");
+ }
+ useDepNode = true;
+ }
+ else {
+ depNodeVal = null;
+ }
+
+ // Note: as of 1607, we no longer validate property names since that's covered by the REST layer.
+ // Same goes for required fields (as of 1602)
+
+ // Special ip-address validation for ipAddr nodes only... This will go away when we go to YANG and
+ // do validations like this up at that layer.
+ if( nodeType.equals("ipaddress") ){
+ // Note - this will throw an exception if the ipAddress is using a bad format
+ ipAddressFormatOK( transId, fromAppId, (String)propHash.get("addr"), (String)propHash.get("version") );
+ }
+
+ // Use the key-fields/dependentNode to check if this is an add or an update
+ // We assume that all NodeTypes at least one key-property defined. A dependentNode is optional.
+ if( ! dbMaps.NodeKeyProps.containsKey(nodeType) ){
+ // Problem if no key Properties defined for this nodeType
+ String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+ throw new AAIException("AAI_6105", "No node-key-properties defined in dbMaps for nodeType = " + nodeType + " (ver=" + defVer + ")");
+ }
+
+ Boolean hasAltKey1 = false;
+ HashMap <String,Object>nodeAltKey1PropsHash = new HashMap<String,Object>();
+ Collection <String> altKey1Props = getNodeAltKey1PropNames(transId, fromAppId, nodeType, apiVersion);
+ if( altKey1Props != null ){
+ Iterator <String> altKey1PropI = altKey1Props.iterator();
+ while( altKey1PropI.hasNext() ){
+ String propName = altKey1PropI.next();
+ // NOTE: alt-keys are not always required fields. If it is null or blank, we won't
+ // do alt-key checks on it.
+ Object value = propHash.get(propName);
+ if( value != null && !value.toString().equals("") ){
+ hasAltKey1 = true;
+ nodeAltKey1PropsHash.put(propName, value);
+ }
+ }
+ }
+ HashMap <String,Object>nodeKeyPropsHash = new HashMap<String,Object>();
+ Collection <String> keyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion);
+ Iterator <String> keyPropI = keyProps.iterator();
+ while( keyPropI.hasNext() ){
+ String propName = keyPropI.next();
+
+ Object value = propHash.get(propName);
+ nodeKeyPropsHash.put(propName, value);
+ }
+
+ // Check if this node is already in the database based on the Primary Key Info
+ TitanVertex existingVert = thisNodeVertex;
+ boolean foundTheNodeInDb = true;
+
+ if (existingVert == null) {
+ try {
+ existingVert = getUniqueNode( transId, fromAppId, graph, nodeType, nodeKeyPropsHash, depNodeVal, apiVersion );
+ }
+ catch (AAIException e) {
+ if (e.getErrorObject().getErrorCode().equals("6114")) {
+ foundTheNodeInDb = false;
+ }
+ else {
+ throw e;
+ }
+ }
+ }
+
+ // this is so the notification knows whether or not the operation was an UPDATE or a CREATe
+ objectExists[0] = foundTheNodeInDb;
+ if( foundTheNodeInDb ){
+ // A record was found in the DB using the PK.
+ if( needToDoResourceVerCheck(apiVersion, patchOnly) ){
+ // Need to check that they knew what they were updating
+ String existingResVer = existingVert.<String>property("resource-version").orElse(null);
+ if( resourceVersion == null || resourceVersion.equals("") ){
+ throw new AAIException("AAI_6130", "Resource-version not passed for update of = " + nodeType + ", " + nodeKeyPropsHash.toString());
+ }
+ else if( (existingResVer != null) && !resourceVersion.equals(existingResVer) ){
+ throw new AAIException("AAI_6131", "Resource-version " + resourceVersion + " MISMATCH WITH EXISTING " + existingResVer + " for update of = " + nodeType + ", " + nodeKeyPropsHash.toString());
+ }
+ }
+
+ // Need to ensure that the Alternate key isn't changing to a value that points to a different existing node.
+ // It is ok if it points to nothing -- that would just be an update for this node. It's also ok if
+ // it points to this (existing) node - that just means that it wasn't being updated.
+ if( hasAltKey1 ){
+ try {
+ TitanVertex chkVert = getUniqueNode( transId, fromAppId, graph, nodeType, nodeAltKey1PropsHash, depNodeVal, apiVersion );
+ if( ! chkVert.id().toString().equals(existingVert.id().toString()) ){
+ throw new AAIException("AAI_6117", "In-Use AlternateKey value passed for update of nodeType = " + nodeType);
+ }
+ }
+ catch (AAIException e) {
+ if(! e.getErrorObject().getErrorCode().equals("6114") ){
+ throw e;
+ }
+ }
+ }
+ }
+ else {
+ // Note not in the DB -- This will be an ADD of a new node
+ // a) make sure they didn't say they were just doing "patchOnly" which cannot be an ADD.
+ // b) if there is an alternate key, we need to make sure the AK isn't already in use by somebody else.
+ if( patchOnly ){
+ String depMsg = "";
+ if( useDepNode ){
+ depMsg = " plus dependent node. ";
+ }
+ throw new AAIException("AAI_6114", "Patch Request, but no Node of type " + nodeType + " found for properties: [" + propHash + "] " + depMsg);
+ }
+
+ if( needToDoResourceVerCheck(apiVersion, patchOnly) && (resourceVersion != null) && !resourceVersion.equals("") ){
+ throw new AAIException("AAI_6131", "Resource-version was passed in, but this is an ADD of a " + nodeType + ", with these params: " + nodeKeyPropsHash.toString());
+ }
+ if( hasAltKey1 ){
+ try {
+ getUniqueNode( transId, fromAppId, graph, nodeType, nodeAltKey1PropsHash, depNodeVal, apiVersion );
+ // Since the Primary Key for this nodeType wasn't found in the DB yet, the fact that
+ // we are able to find a record (no "6114" exception thrown) using the Alternate-Key is an error.
+ // We can't create a new node that uses an AK that's already in use.
+ throw new AAIException("AAI_6117", "Conflicting Key and Alternate-Key values passed for add of nodeType = " + nodeType);
+ }
+ catch (AAIException e) {
+ if(! e.getErrorObject().getErrorCode().equals("6114") ){
+ throw e;
+ }
+ }
+ }
+ }
+
+ // ------------- Done with checking. Do the add or update to the dB -----------------------
+
+ if( foundTheNodeInDb ){
+ long unixTimeNow = System.currentTimeMillis() / 1000L;
+ // ----- This is an UPDATE ------
+
+
+ String existingSourceOfTruth = fromAppId; // default value if we can't get the old one
+ Object tmpOb = existingVert.<Object>property("source-of-truth").orElse(null);
+ if( tmpOb != null ){
+ existingSourceOfTruth = tmpOb.toString();
+ }
+ long existingCreateTs = unixTimeNow; // default value if we can't get the old one
+ tmpOb = existingVert.<Object>property("aai-created-ts").orElse(null);
+ if( tmpOb != null ){
+ existingCreateTs = (long) tmpOb;
+ }
+
+ String msg = "UPDATE vertex of type = [" + nodeType + "] ";
+ if( useDepNode ){
+ String depNType = depNodeVal.<String>property("aai-node-type").orElse(null);
+ HashMap <String, Object> depNodePropKeysHash = getNodeKeyPropHash(transId, fromAppId, graph, depNodeVal);
+ LOGGER.info("UPDATE existing node: type = " + nodeType + ", key(s) = [" + nodeKeyPropsHash +
+ "] which rides on dependent node: type = " + depNType + ", with key(s) = [" + depNodePropKeysHash + "].");
+ }
+ else {
+ LOGGER.info("UPDATE existing node: type = " + nodeType + ", key(s) = [" + nodeKeyPropsHash + "] (no dep. node).");
+ }
+ String removeList = "";
+ if( ! patchOnly ){
+ // They are updating an existing record, and they want us to "process all defined properties" (not just patch)
+ // So we will see if the node has any properties that were not passed-in. Those need to be removed.
+ Collection <String> propCol = dbMaps.NodeProps.get(nodeType);
+ Iterator <String> propIter = propCol.iterator();
+ while( propIter.hasNext() ){
+ String propName = propIter.next();
+ if( ! propHash.containsKey(propName) && !DbEdgeRules.ReservedPropNames.containsKey(propName)){
+ if( thisPropertyWasPutByNewerVersionOfCode(apiVersion, nodeType, propName) ){
+ // we must be using an older version of code here - but the property that
+ // has not been passed in this persist call is one that this older version of
+ // the database did not know about. So leave it alone.
+ }
+ else {
+ removeList = removeList + "," + propName;
+ existingVert.property(propName).remove();
+ }
+ }
+ }
+ }
+ if( !removeList.equals("") ){
+ LOGGER.info("Removed these props on update: [" + removeList + "]");
+ }
+ for( Map.Entry<String, Object> entry : propHash.entrySet() ){
+ // update the parameters that have been passed in (except the key-properties)
+ // taking away the key-property check. We will now allow this since
+ // the keys were used to identify this node, so they should be good and
+ // there are times when Titan resolves conflicts by only using the
+ // data set in an update - and was losing our key info...
+ // Similar to the change noted below.
+ //if( ! nodeKeyPropsHash.containsKey(entry.getKey()) ){
+ // existingVert.setProperty( entry.getKey(), entry.getValue() );
+ //}
+ if( ! entry.getKey().equals("resource-version") ){
+ boolean nonSingleCardinality = false;
+ boolean setSoNoDupes = false;
+ if( checkPropCardinality(entry.getKey(), "Set") ){
+ nonSingleCardinality = true;
+ setSoNoDupes = true;
+ }
+ else if( checkPropCardinality(entry.getKey(), "List") ){
+ nonSingleCardinality = true;
+ }
+
+ Iterator <Object> valIter = null;
+ if( nonSingleCardinality ){
+ String className = entry.getValue().getClass().getSimpleName();
+ if( className.equals("ArrayList") ){
+ valIter = ((ArrayList)(entry.getValue())).iterator();
+ }
+ else if( className.equals("List") ){
+ valIter = ((List)(entry.getValue())).iterator();
+ }
+ else if( className.equals("Set") ){
+ valIter = ((Set)(entry.getValue())).iterator();
+ }
+ }
+
+ if( nonSingleCardinality ){
+ // This property has Cardinality of List or Set - which need to be handled carefully
+ // Note -- for Lists or Sets, we assume they are of dataType String - that is all
+ // the Rest layer supports at the moment (16-02)
+ ArrayList <String> currentData = new ArrayList <String> ();
+ if( patchOnly ){
+ // When patching - gotta know what's already in the db
+ Iterator<VertexProperty<Object>> existingPropsIter = (existingVert.properties(entry.getKey()));
+ if( existingPropsIter != null ){
+ while( existingPropsIter.hasNext() ){
+ String existingVal = existingPropsIter.next().value().toString();
+ currentData.add( existingVal );
+ }
+ }
+ }
+ else {
+ // Since this is not a patch-update, we first have to clear out what is currently in the db.
+ existingVert.property(entry.getKey()).remove();
+ }
+
+ if( valIter != null ){
+ while( valIter.hasNext() ){
+ Object thisVal = valIter.next();
+ if( setSoNoDupes ){
+ // For Sets, we need to check that the data isn't already in the db or wasn't passed
+ // in to us twice in the propHash. Otherwise Titan throws an exception (instead of just ignoring it...)
+ if( !currentData.contains(thisVal) ){
+ // We don't have this data yet, so add it to the Set
+ existingVert.property( entry.getKey(), thisVal );
+ currentData.add( thisVal.toString() );
+ }
+ }
+ else {
+ // For List data types, it's ok to have duplicate values in the db (why would we want this?)
+ existingVert.property( entry.getKey(), thisVal );
+ }
+ }
+ }
+ }
+ else {
+ // This is a normal, "Cardinality = SINGLE" kind of property
+ // ResourceVersion is not populated based on passed-in data, it is set along with other internal properties below.
+ //Object cleanVal = convertTypeIfNeeded( entry.getKey(), entry.getValue() );
+ //existingVert.setProperty( entry.getKey(), cleanVal );
+ // ********************************
+ existingVert.property( entry.getKey(), entry.getValue() );
+ }
+ }
+ }
+
+ // DEBUG - trying to deal with the case where simultaneous PUTs
+ // cause our db to wind up with a vertex that does not have these three properties filled in.
+ existingVert.property( "aai-node-type", nodeType );
+ existingVert.property( "aai-created-ts", existingCreateTs );
+ existingVert.property( "source-of-truth", existingSourceOfTruth );
+
+ if( aaiUniqueKeyVal != null ){
+ existingVert.property( "aai-unique-key", aaiUniqueKeyVal );
+ }
+
+ existingVert.property( "aai-last-mod-ts", unixTimeNow );
+ String resVers = "" + unixTimeNow;
+ existingVert.property( "resource-version", resVers );
+ existingVert.property( "last-mod-source-of-truth", fromAppId );
+
+ LOGGER.info(msg + ", [aai-last-mod-ts]/[" + unixTimeNow + "]");
+
+ return( existingVert );
+ }
+ else{
+ // ----- Not found in the DB, This must be an ADD ------
+ if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
+ throw new AAIException("AAI_6120", "nodeTypeCategory " + nodeType + " cannot be used to ADD a node. Need to pass a valid nodeType");
+ }
+
+ TitanVertex tiVnew = graph.addVertex( nodeType );
+
+ String msg = "ADD vertex of type = [" + nodeType + "] ";
+ if( depNodeVal != null ){
+ String depNType = depNodeVal.<String>property("aai-node-type").orElse(null);
+ HashMap <String, Object> depNodePropKeysHash = getNodeKeyPropHash(transId, fromAppId, graph, depNodeVal);
+ msg = msg + " onto dependent node: type = " + depNType + ", which has key(s) = [" + depNodePropKeysHash +
+ "]. New Node Prop/values = ";
+ }
+ else {
+ msg = msg + " Note: no dependent node. New Node Prop/values = ";
+ }
+ boolean first = true;
+ for( Map.Entry<String, Object> entry : propHash.entrySet() ){
+ if( ! entry.getKey().equals("resource-version") ){
+ if( first ){
+ msg = msg + " [" + entry.getKey() + "]/[" + entry.getValue() + "]";
+ first = false;
+ }
+ else {
+ msg = msg + ", [" + entry.getKey() + "]/[" + entry.getValue() + "]";
+ }
+
+ boolean nonSingleCardinality = false;
+ boolean setSoNoDupes = false;
+ if( checkPropCardinality(entry.getKey(), "Set") ){
+ nonSingleCardinality = true;
+ setSoNoDupes = true;
+ }
+ else if( checkPropCardinality(entry.getKey(), "List") ){
+ nonSingleCardinality = true;
+ }
+
+ Iterator <Object> valIter = null;
+ if( nonSingleCardinality ){
+ String className = entry.getValue().getClass().getSimpleName();
+ if( className.equals("ArrayList") ){
+ valIter = ((ArrayList)(entry.getValue())).iterator();
+ }
+ else if( className.equals("List") ){
+ valIter = ((List)(entry.getValue())).iterator();
+ }
+ else if( className.equals("Set") ){
+ valIter = ((Set)(entry.getValue())).iterator();
+ }
+ }
+
+ if( nonSingleCardinality ){
+ // This property has Cardinality of List or Set - which need to be handled carefully
+ ArrayList <String> currentData = new ArrayList <String> ();
+ if( valIter != null ){
+ while( valIter.hasNext() ){
+ Object thisVal = valIter.next();
+ if( setSoNoDupes ){
+ // For Sets, we need to check that they're not passing us duplicate data in propHash.
+ // Otherwise Titan throws an exception (instead of just ignoring it...)
+ if( !currentData.contains(thisVal) ){
+ // We don't have this data yet, so add it to the Set
+ tiVnew.property( entry.getKey(), thisVal );
+ currentData.add( thisVal.toString() );
+ }
+ }
+ else {
+ // For List data types, it's ok to have duplicate values in the db (why would we want this?)
+ tiVnew.property( entry.getKey(), thisVal );
+ }
+ }
+ }
+ }
+ else {
+ // This is a normal, "Cardinality = SINGLE" kind of property
+ // ResourceVersion is not populated based on passed-in data, it is set along with other internal properties below.
+ tiVnew.property( entry.getKey(), entry.getValue() );
+ }
+ }
+ }
+
+ tiVnew.property( "aai-node-type", nodeType );
+ //long unixTime = System.currentTimeMillis() / 1000L;
+ long unixTime = System.currentTimeMillis();
+ tiVnew.property( "aai-created-ts", unixTime );
+ tiVnew.property( "aai-last-mod-ts", unixTime );
+ String resVers = "" + unixTime;
+ tiVnew.property( "resource-version", resVers );
+ tiVnew.property( "source-of-truth", fromAppId );
+ tiVnew.property( "last-mod-source-of-truth", fromAppId );
+ if( aaiUniqueKeyVal != null ){
+ tiVnew.property( "aai-unique-key", aaiUniqueKeyVal );
+ }
+
+ LOGGER.info(msg + ", [aai-created-ts]/[" + unixTime + "]");
+ return( tiVnew );
+ }
+
+ } // end of persistAaiNodeBASE()
+
+
+ /**
+ * Need to do resource ver check.
+ *
+ * @param apiVersion the api version
+ * @param patchOnlyFlag the patch only flag
+ * @return the boolean
+ * @throws AAIException the AAI exception
+ */
+ public static Boolean needToDoResourceVerCheck(String apiVersion, Boolean patchOnlyFlag)
+ throws AAIException{
+
+ if( patchOnlyFlag ){
+ // we do not do resource checking for patch requests.
+ return false;
+ }
+
+ String resourceCheckOnFlag = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG);
+
+ int apiVerInt = cleanUpApiVersion(apiVersion);
+
+ if( (resourceCheckOnFlag != null) && resourceCheckOnFlag.equals("true") ){
+ // Only do the check if the resource enable flag is set to "true"
+ if( apiVerInt > 4 ){
+ // We're only doing the resource version checks for v5 and later
+ return true;
+ }
+ }
+
+ return false;
+ }// End needToDoResourceVerCheck()
+
+
+ /**
+ * Clean up api version.
+ *
+ * @param apiVersionString the api version string
+ * @return the int
+ * @throws AAIException the AAI exception
+ */
+ private static int cleanUpApiVersion( String apiVersionString ) throws AAIException {
+ // Note: we expect an apiVersion to start with the letter "v", followed by an integer.
+
+ int versionInt = 0;
+ String verStr = apiVersionString;
+ if( (apiVersionString == null) || (apiVersionString.length() < 2) ){
+ // Passed in version doesn't look right
+ verStr = org.openecomp.aai.util.AAIApiVersion.get();
+ }
+ versionInt = getVerNumFromVerString( verStr );
+
+ return versionInt;
+ }
+
+ /**
+ * Gets the ver num from ver string.
+ *
+ * @param versionString the version string
+ * @return the ver num from ver string
+ * @throws AAIException the AAI exception
+ */
+ private static int getVerNumFromVerString( String versionString )throws AAIException {
+ int versionInt = 0;
+ if( versionString == null || versionString.length() < 2 ){
+ throw new AAIException("AAI_6121", " Bad Version (format) passed to getVerNumFromVerString: [" + versionString + "].");
+ }
+
+ int strLen = versionString.length();
+ // We assume that a version looks like "v" followed by an integer
+ if( ! versionString.substring(0,1).equals("v") ){
+ String detail = " Bad Version (format) passed to getVerNumFromVerString: [" + versionString + "].";
+ throw new AAIException("AAI_6121", detail);
+ }
+ else {
+ String intPart = versionString.substring(1,strLen);
+ try {
+ versionInt = Integer.parseInt( intPart );
+ }
+ catch( Exception e ){
+ String detail = " Bad Version passed to getVerNumFromVerString: [" + versionString + "].";
+ throw new AAIException("AAI_6121", detail);
+ }
+ }
+ return versionInt;
+ }
+
+
+ /**
+ * Gets the node key prop names.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param apiVersion the api version
+ * @return HashMap of keyProperties
+ * @throws AAIException the AAI exception
+ */
+ public static Collection <String> getNodeKeyPropNames( String transId, String fromAppId, String nodeType, String apiVersion ) throws AAIException{
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ Collection <String> keyProps = new ArrayList <String>();
+ if( dbMaps.NodeKeyProps.containsKey(nodeType) ){
+ keyProps = dbMaps.NodeKeyProps.get(nodeType);
+ }
+ else if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
+ // The passed-in nodeType was really a nodeCategory, so we need to look up the key params
+ Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType);
+ Iterator <String> catItr = nTypeCatCol.iterator();
+ String catInfo = "";
+ if( catItr.hasNext() ){
+ // For now, we only look for one.
+ catInfo = catItr.next();
+ }
+ else {
+ String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+ throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nodeType+ " (ver=" + defVer + ")");
+ }
+
+ String [] flds = catInfo.split(",");
+ if( flds.length != 4 ){
+ throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data for nodeType = [" + nodeType + "].");
+ }
+
+ String keyPropsString = flds[0];
+ String [] propNames = keyPropsString.split("\\|");
+ for( int i = 0; i < propNames.length; i++ ){
+ keyProps.add(propNames[i]);
+ }
+ }
+ else {
+ String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+ throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nodeType+ " (ver=" + defVer + ")");
+ }
+
+ return keyProps;
+
+ }// end of getNodeKeyPropNames
+
+ /**
+ * Gets the node key prop names.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @return the node key prop names
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static Collection <String> getNodeKeyPropNames( String transId, String fromAppId, String nodeType ) throws AAIException{
+ return getNodeKeyPropNames( transId, fromAppId, nodeType, null);
+ }
+
+ /**
+ * Gets the node alt key 1 prop names.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param apiVersion the api version
+ * @return HashMap of keyProperties
+ * @throws AAIException the AAI exception
+ */
+ public static Collection <String> getNodeAltKey1PropNames( String transId, String fromAppId, String nodeType, String apiVersion ) throws AAIException{
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ Collection <String> altKey1Props = new ArrayList <String>();
+ if( dbMaps.NodeAltKey1Props.containsKey(nodeType) ){
+ altKey1Props = dbMaps.NodeAltKey1Props.get(nodeType);
+ }
+ else if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
+ // The passed-in nodeType was really a nodeCategory, so we need to look up the key params
+ Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType);
+ Iterator <String> catItr = nTypeCatCol.iterator();
+ String catInfo = "";
+ if( catItr.hasNext() ){
+ catInfo = catItr.next();
+ String [] flds = catInfo.split(",");
+ if( flds.length != 4 ){
+ throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data (itemCount=" + flds.length + ") for nodeType = [" + nodeType + "].");
+ }
+
+ String altKeyPropsString = flds[1];
+ String [] propNames = altKeyPropsString.split("\\|");
+ for( int i = 0; i < propNames.length; i++ ){
+ altKey1Props.add(propNames[i]);
+ }
+ }
+ }
+
+ return altKey1Props;
+
+ }// end of getNodeAltKey1PropNames
+
+ /**
+ * Gets the node alt key 1 prop names.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @return the node alt key 1 prop names
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static Collection <String> getNodeAltKey1PropNames( String transId, String fromAppId, String nodeType ) throws AAIException{
+ return getNodeAltKey1PropNames( transId, fromAppId, nodeType, null);
+ }
+
+
+ /**
+ * Gets the unique node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param keyPropsHash the key props hash
+ * @param depNodeVal the dep node val
+ * @param apiVersion the api version
+ * @return TitanVertex
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanVertex getUniqueNode( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> keyPropsHash, TitanVertex depNodeVal, String apiVersion ) throws AAIException{
+
+ // NOTE - this is really for use by the PersistNode method -- it is looking to see if
+ // a node exists in the database given either Primary or Alternate Key data and dependent
+ // node data (if required for uniqueness).
+
+ // Note - the passed in nodeType could really be a nodeTypeCategory ---
+ Boolean nodeTypeIsCategory = DbEdgeRules.NodeTypeCategory.containsKey(nodeType);
+
+ Boolean useDepNode = false;
+ if( needsADepNode4Uniqueness(transId, fromAppId, nodeType, apiVersion) ){
+ // This kind of node depends on another node for uniqueness
+ if( depNodeVal == null ){
+ // They should have passed in the node that this one depends on
+ throw new AAIException("AAI_6109", "null dependentNode object passed to getUniqueNode() but " + nodeType + " requires one.");
+ }
+ else if( ! nodeTypeACanDependOnB(transId, fromAppId, nodeType, depNodeVal.<String>property("aai-node-type").orElse(null), apiVersion) ){
+ // They should have passed in the right type of node as the dependent node
+ throw new AAIException("AAI_6109", "dependentNode of type " + depNodeVal.<String>property("aai-node-type").orElse(null) + " passed to getUniqueNode() for nodeType" + nodeType + ".\n");
+ }
+ useDepNode = true;
+ }
+ else {
+ depNodeVal = null;
+ }
+
+ // We assume that all NodeTypes have at least one key-property defined. A dependentNode is optional.
+ // Note - instead of key-properties (the primary key properties), a user could pass
+ // alternate-key values if they are defined for the nodeType.
+ ArrayList<String> kName = new ArrayList<String>();
+ ArrayList<Object> kVal = new ArrayList<Object>();
+
+ Collection <String> keyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion);
+ Iterator <String> keyPropI = keyProps.iterator();
+ Boolean haveSomePrimKeyProps = false;
+ Boolean primaryKeyComplete = true;
+ while( keyPropI.hasNext() ){
+ haveSomePrimKeyProps = true;
+
+ String propName = keyPropI.next();
+ if( ! keyPropsHash.containsKey(propName) ){
+ primaryKeyComplete = false;
+ }
+ else {
+ Object valObj = keyPropsHash.get(propName);
+ if( valObj == null ){
+ primaryKeyComplete = false;
+ }
+ else {
+ String value = valObj.toString();
+ if( value == null || value.equals("") ){
+ // They passed the property name, but no value
+ primaryKeyComplete = false;
+ }
+ }
+ }
+ }
+
+ int i = -1;
+ if( haveSomePrimKeyProps && primaryKeyComplete ){
+ keyPropI = keyProps.iterator();
+ while( keyPropI.hasNext() ){
+ String propName = keyPropI.next();
+ String value = (keyPropsHash.get(propName)).toString();
+ i++;
+ kName.add(i, propName);
+ kVal.add(i, (Object)value);
+ }
+ }
+ else {
+ // See if they're using the alternate key
+ Collection <String> altKey1Props = getNodeAltKey1PropNames(transId, fromAppId, nodeType, apiVersion);
+ Iterator <String> altKey1PropI = altKey1Props.iterator();
+ Boolean haveSomeAltKey1Props = false;
+ Boolean altKey1Complete = true;
+ while( altKey1PropI.hasNext() ){
+ haveSomeAltKey1Props = true;
+ String propName = altKey1PropI.next();
+ if( ! keyPropsHash.containsKey(propName) ){
+ altKey1Complete = false;
+ }
+ else {
+ Object valObj = keyPropsHash.get(propName);
+ if( valObj == null ){
+ altKey1Complete = false;
+ }
+ else {
+ String value = valObj.toString();
+ if( value == null || value.equals("") ){
+ // They passed the property name, but no value
+ altKey1Complete = false;
+ }
+ }
+ }
+ }
+ if( haveSomeAltKey1Props && altKey1Complete ){
+ altKey1PropI = altKey1Props.iterator();
+ while( altKey1PropI.hasNext() ){
+ String propName = altKey1PropI.next();
+ String value = (keyPropsHash.get(propName)).toString();
+ i++;
+ kName.add(i, propName);
+ kVal.add(i, (Object)value);
+ }
+ }
+ }
+
+ int topPropIndex = i;
+ TitanVertex tiV = null;
+ String propsAndValuesForMsg = "";
+ if( !useDepNode ){
+ // There is no node that this type of node depends on, so we can look for it based
+ // solely on the Aai-defined key fields.
+ Iterable <?> verts = null;
+
+ if( topPropIndex == -1 ){
+ // Problem if no key Properties defined for this nodeType
+ String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+ throw new AAIException("AAI_6105", "Bad or Incomplete Key Property params: (" + keyPropsHash.toString() +
+ ") for nodeType: " + nodeType + " (ver=" + defVer + ")");
+ }
+ else if( topPropIndex == 0 ){
+ if (nodeTypeIsCategory) // dont know real type
+ verts= graph.query().has(kName.get(0),kVal.get(0)).vertices();
+ else // need this to find dvs switch: dvs.switch-name and port-group.switch-name issue
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has("aai-node-type",nodeType).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ") ";
+ }
+ else if( topPropIndex == 1 ){
+ verts = graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ") ";
+ }
+ else if( topPropIndex == 2 ){
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ", "
+ + kName.get(2) + " = " + kVal.get(2) + ") ";
+ }
+ else if( topPropIndex == 3 ){
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).has(kName.get(3),kVal.get(3)).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ", "
+ + kName.get(2) + " = " + kVal.get(2) + ", "
+ + kName.get(3) + " = " + kVal.get(3) + ") ";
+ }
+ else {
+ String emsg = " We only support 4 keys per nodeType for now \n";
+ throw new AAIException("AAI_6114", emsg);
+ }
+
+ Iterator <?> vertI = verts.iterator();
+ if( vertI != null && vertI.hasNext()) {
+ // We found a vertex that meets the input criteria.
+ tiV = (TitanVertex) vertI.next();
+
+ if( vertI.hasNext() ){
+ // Since this routine is looking for a unique node for the given input values, if
+ // more than one is found - it's a problem.
+ throw new AAIException("AAI_6112", "More than one Node found by getUniqueNode for params: " + propsAndValuesForMsg);
+ }
+ }
+ else {
+ // No Vertex was found for this key - throw a not-found exception
+ throw new AAIException("AAI_6114", "No Node of type " + nodeType + " found for properties: " + propsAndValuesForMsg);
+ }
+ }
+ else {
+ // Need to use the dependent vertex to look for this one.
+ // filter this to the actual keys because
+ HashMap<String,Object> onlyKeysHash = new HashMap<String,Object>();
+
+ Collection <String> onlyKeyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion);
+
+ Iterator <String> onlyKeyPropsI = onlyKeyProps.iterator();
+
+ while( onlyKeyPropsI.hasNext() ){
+ String keyName = onlyKeyPropsI.next();
+ onlyKeysHash.put(keyName, keyPropsHash.get(keyName));
+ }
+
+ propsAndValuesForMsg = onlyKeysHash.toString() + " combined with a Dependent [" + depNodeVal.<String>property("aai-node-type").orElse(null) + "] node.";
+ ArrayList<TitanVertex> resultList = DbMeth.getConnectedNodes(transId, fromAppId, graph, nodeType, onlyKeysHash,
+ depNodeVal, apiVersion, false);
+ if( resultList.size() > 1 ){
+ // More than one vertex found when we thought there should only be one.
+ throw new AAIException("AAI_6112", "More than one Node found by getUniqueNode for params: " + propsAndValuesForMsg);
+ }
+ else if( resultList.size() == 1 ){
+ tiV = resultList.get(0);
+ }
+ }
+
+ if( tiV == null ){
+ // No Vertex was found for this key - throw a not-found exception
+ throw new AAIException("AAI_6114", "No Node of type " + nodeType + " found for properties: " + propsAndValuesForMsg);
+ }
+ else {
+ if( !DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
+ // The nodeType passed in was a real one, not a nodeTypeCategory, so we will
+ // use it as part of the query to make sure we find the right type of node.
+ // This can be an issue if they're using nodeTypes covered by a nodeTypeCategory but
+ // pass in the wrong nodeType. We don't want them to ask for one thing and get the other.
+ String foundNodeType = tiV.<String>property("aai-node-type").orElse(null);
+ if( foundNodeType != null && !foundNodeType.equals(nodeType) ){
+ throw new AAIException("AAI_6114", "No Node of type " + nodeType + " found for properties: " + propsAndValuesForMsg + " (did find a " + foundNodeType + " though.)");
+ }
+ }
+
+ return tiV;
+ }
+
+ }// End of getUniqueNode()
+
+ /**
+ * Gets the unique node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param keyPropsHash the key props hash
+ * @param depNodeVal the dep node val
+ * @return the unique node
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanVertex getUniqueNode( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> keyPropsHash, TitanVertex depNodeVal) throws AAIException {
+ return getUniqueNode( transId, fromAppId, graph, nodeType,
+ keyPropsHash, depNodeVal, null );
+ }
+ // End getUniqueNode()
+
+
+ /**
+ * Gets the unique node with dep params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param nodePropsHash the node props hash
+ * @param apiVersion the api version
+ * @return TitanVertex
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanVertex getUniqueNodeWithDepParams( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> nodePropsHash, String apiVersion )
+ throws AAIException{
+ /*
+ * This method uses the nodePropsHash to walk back over dependent nodes until it finds one that
+ * does not depend on any other for uniqueness. It uses the getUniqueNode() method as it finds
+ * dependent nodes. NOTE -- it is passed a hash of all the nodeProperties -- for itself and
+ * for any dependent nodes that it will need to find. There are some types of nodes that can
+ * depend on more than one node, we assume that there wouldn't be a case where BOTH types of
+ * dependent nodes are in the trail that we need to traverse. Ie. an ipaddress can depend on
+ * either a vserver or pserver. NOTE this case can now happen -- nodePropsHash
+ * should now be sent as a LinkedHashMap in this case so we can search in order.
+ */
+
+ // NOTE ALSO -- We're currently supporting 6 layers of dependency. We never thought there would be this
+ // many layers before hitting a node-type that would be uniquely identifiable on it's own. So the
+ // code is a little ugly with all these nested if-then-else's. Since we're supporting so many
+ // layers, it should be re-written so we can support "n" layers instead of having to go in hear
+ // and adding code... But as of 15-07, we really don't NEED more than 5.
+
+ // NOTE: The passed in nodeType could really be a nodeTypeCategory --
+ // The calls to figureDepNodeTypeForRequest() below will deal with it for the dep nodes, the
+ // call to getUniqueNode() takes care of it for the node itself.
+
+ TitanVertex nullVert = null;
+ String depNodeType = figureDepNodeTypeForRequest( transId, fromAppId, nodeType, nodePropsHash, apiVersion );
+ if( depNodeType.equals("")){
+ // This kind of node does not depend on another node for uniqueness, so
+ // we can just use the "getUniqueNode()" method to get it.
+ HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
+ return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, nullVert, apiVersion) );
+ }
+ else {
+ // Will need to find the second-layer dependent node
+ String secondLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, depNodeType, nodePropsHash, apiVersion );
+ if( secondLayerDepNodeType.equals("")){
+ // This second-layer kind of node does not depend on another node for uniqueness.
+ // So once we find the second-layer node, we can use it to get the top-layer guy.
+ HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
+ TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
+ return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
+ }
+ else {
+ // Will need to find the third-layer dependent node
+ /// String thirdLayerDepNodeType = dbMaps.NodeDependencies.get(secondLayerDepNodeType);
+ String thirdLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion );
+
+ if( thirdLayerDepNodeType.equals("")){
+ // This third-layer kind of node does not depend on another node for uniqueness.
+ // So we can find it, and then use it to find the second-layer and then use that to find the top guy.
+ HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
+ TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
+
+ return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
+ }
+ else {
+ // Will need to find the third-layer dependent node
+ String forthLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion );
+ if( forthLayerDepNodeType == null || forthLayerDepNodeType.equals("")){
+ // This forth-layer kind of node does not depend on another node for uniqueness.
+ // So we can find it, and then use it to find the third, then second-layer and then use that to find the top guy.
+ HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex forthLayerDepVert = getUniqueNode(transId, fromAppId, graph, thirdLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, forthLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
+ TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
+ return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
+ }
+ else {
+ // Will need to find the forth-layer dependent node
+ String fifthLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, forthLayerDepNodeType, nodePropsHash, apiVersion );
+ if( fifthLayerDepNodeType == null || fifthLayerDepNodeType.equals("")){
+ // This fifth-layer kind of node does not depend on another node for uniqueness.
+ // So we can find it, and then use it to find the forth, third, then second-layer and then use that to find the top guy.
+ HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, forthLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex fifthLayerDepVert = getUniqueNode(transId, fromAppId, graph, forthLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex forthLayerDepVert = getUniqueNode(transId, fromAppId, graph, thirdLayerDepNodeType, thisNodeTypeParamHash, fifthLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, forthLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
+ TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
+ return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
+ }
+ else {
+ // Will need to find the fifth-layer dependent node
+ String sixthLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, fifthLayerDepNodeType, nodePropsHash, apiVersion );
+ if( sixthLayerDepNodeType == null || sixthLayerDepNodeType.equals("")){
+ // This six-layer kind of node does not depend on another node for uniqueness.
+ // So we can find it, and then use it to find the fifth, forth, third, then second-layer and then use that to find the top guy.
+ HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, fifthLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex sixthLayerDepVert = getUniqueNode(transId, fromAppId, graph, fifthLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, forthLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex fifthLayerDepVert = getUniqueNode(transId, fromAppId, graph, forthLayerDepNodeType, thisNodeTypeParamHash, sixthLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex forthLayerDepVert = getUniqueNode(transId, fromAppId, graph, thirdLayerDepNodeType, thisNodeTypeParamHash, fifthLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, forthLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
+ TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
+ return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
+ }
+ else {
+ // We don't currently support more layers. We can later if we need to.
+ // Hopefully, we'll never need to go this deep -- there should be unique keys in there somewhere!
+ throw new AAIException("AAI_6114", "CODE-LIMITATION - Can't resolve dependant node layers for nodeType = " + nodeType);
+ }
+ }
+ }
+ }
+ }
+ }
+ } // End getUniqueNodeWithDepParams()
+
+ /**
+ * Gets the unique node with dep params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param nodePropsHash the node props hash
+ * @return the unique node with dep params
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanVertex getUniqueNodeWithDepParams( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> nodePropsHash ) throws AAIException {
+ return getUniqueNodeWithDepParams(transId, fromAppId, graph, nodeType, nodePropsHash, null);
+ }
+
+
+ /**
+ * Gets the this node type params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param targetNodeType the target node type
+ * @param passedHash the passed hash
+ * @param apiVersion the api version
+ * @return the this node type params
+ * @throws AAIException the AAI exception
+ */
+ private static HashMap <String, Object> getThisNodeTypeParams(String transId, String fromAppId, String targetNodeType,
+ HashMap<String,Object> passedHash, String apiVersion )throws AAIException{
+ /*
+ * For the passed-in hash, each key is assumed to look like, "nodeType.paramName". We want to
+ * pick out the entries that match the targetNodeType and return those with the values they go with. The
+ * returned keys will have the "nodeType." stripped off.
+ *
+ * NOTE - the nodeType passed to this method could actually be a nodeTypeCategory. Just keepin it ugly.
+ */
+
+ if( passedHash == null ){
+ throw new AAIException("AAI_6120", "Bad param: null passedHash ");
+ }
+
+ String targetNodeTypeCat = "";
+ if( DbEdgeRules.NodeTypeCatMap.containsKey(targetNodeType) ){
+ targetNodeTypeCat = DbEdgeRules.NodeTypeCatMap.get(targetNodeType);
+ }
+
+ HashMap <String,Object> returnHash = new HashMap <String,Object> ();
+ Iterator <Map.Entry<String,Object>>it = passedHash.entrySet().iterator();
+ while( it.hasNext() ){
+ Map.Entry <String,Object>pairs = (Map.Entry<String,Object>)it.next();
+ String k = (pairs.getKey()).toString();
+ int periodLoc = k.indexOf(".");
+ if( periodLoc <= 0 ){
+ throw new AAIException("AAI_6120", "Bad filter param key passed in: [" + k + "]. Expected format = [nodeName.paramName]\n");
+ }
+ else {
+ String nty = k.substring(0,periodLoc);
+ String paramName = k.substring(periodLoc + 1);
+ if( nty.equals(targetNodeType) || (!targetNodeTypeCat.equals("") && nty.equals(targetNodeTypeCat)) ){
+ String newK = paramName;
+ returnHash.put( newK,pairs.getValue() );
+ }
+ }
+ }
+
+ //aaiLogger.debug(logline, " - end ");
+ return returnHash;
+
+ }// End of getThisNodeTypeParams()
+
+ /**
+ * Gets the this node type params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param targetNodeType the target node type
+ * @param passedHash the passed hash
+ * @return the this node type params
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ private static HashMap <String, Object> getThisNodeTypeParams(String transId, String fromAppId, String targetNodeType,
+ HashMap<String,Object> passedHash )throws AAIException{
+ return getThisNodeTypeParams( transId, fromAppId, targetNodeType,
+ passedHash, null);
+
+ }
+
+ /**
+ * Gets the dep node types.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param apiVersion the api version
+ * @return the dep node types
+ * @throws AAIException the AAI exception
+ */
+ public static ArrayList <String> getDepNodeTypes(String transId, String fromAppId, String nodeType, String apiVersion)throws AAIException{
+ /*
+ * This returns any nodeTypes that this nodeType can be dependent on. A particular instance of a node will only
+ * depend on one other node - we don't currently support dependence on multiple nodes.
+ */
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ ArrayList <String> depNodeTypeL = new ArrayList <String> ();
+ if( !DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
+ // This is a good-ole nodeType
+ Collection <String> depNTColl = dbMaps.NodeDependencies.get(nodeType);
+ Iterator <String> ntItr = depNTColl.iterator();
+ while( ntItr.hasNext() ){
+ depNodeTypeL.add(ntItr.next());
+ }
+ }
+ else {
+ // The passed-in nodeType must really be a nodeTypeCategory
+ Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType);
+ Iterator <String> catItr = nTypeCatCol.iterator();
+ String catInfo = "";
+ if( catItr.hasNext() ){
+ // For now, we only look for one.
+ catInfo = catItr.next();
+ }
+ else {
+ throw new AAIException("AAI_6121", "Error getting DbEdgeRules.NodeTypeCategory info for nodeTypeCat = " + nodeType);
+ }
+
+ String [] flds = catInfo.split(",");
+ if( flds.length != 4 ){
+ throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data (itemCount=" + flds.length + ") for nodeType = [" + nodeType + "].");
+ }
+
+ String nodeTypesString = flds[0];
+ String hasDepNodes = flds[3];
+ if( hasDepNodes.equals("true") ){
+ String [] ntNames = nodeTypesString.split("\\|");
+ for( int i = 0; i < ntNames.length; i++ ){
+ Collection <String> depNTColl = dbMaps.NodeDependencies.get(nodeType);
+ Iterator <String> ntItr = depNTColl.iterator();
+ while( ntItr.hasNext() ){
+ String depNode = ntItr.next();
+ if( !depNodeTypeL.contains(depNode) ){
+ depNodeTypeL.add(depNode);
+ }
+ }
+ }
+ }
+ }
+
+
+ return depNodeTypeL;
+
+ }// End getDepNodeTypes()
+
+ /**
+ * Gets the dep node types.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @return the dep node types
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static ArrayList <String> getDepNodeTypes(String transId, String fromAppId, String nodeType)throws AAIException{
+ return getDepNodeTypes( transId, fromAppId, nodeType, null);
+ }
+
+ /**
+ * Gets the default delete scope.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param apiVersion the api version
+ * @return the default delete scope
+ * @throws AAIException the AAI exception
+ */
+ private static String getDefaultDeleteScope(String transId, String fromAppId, String nodeType, String apiVersion)throws AAIException{
+
+ // At some point we may have different delete rules for different services, so this is
+ // a list for now even thought there's only one scope per nodeType.
+ Collection <String> scopeList = DbEdgeRules.DefaultDeleteScope.get(nodeType);
+ if( scopeList.isEmpty() ){
+ throw new AAIException("AAI_6121", "No default deleteScope found for nodeType = [" + nodeType + "] ");
+ }
+ else {
+ Iterator <String> ito = scopeList.iterator();
+ return ito.next();
+ }
+
+ }// End getDefaultDeleteScope()
+
+ /**
+ * Gets the default delete scope.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @return the default delete scope
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ private static String getDefaultDeleteScope(String transId, String fromAppId, String nodeType)throws AAIException{
+ return getDefaultDeleteScope( transId, fromAppId, nodeType, null);
+ }
+
+ /**
+ * Needs A dep node 4 uniqueness.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param apiVersion the api version
+ * @return the boolean
+ * @throws AAIException the AAI exception
+ */
+ public static Boolean needsADepNode4Uniqueness(String transId, String fromAppId, String nodeType, String apiVersion)throws AAIException{
+ // Note: the passed in nodeType could really be a nodeTypeCategory. That is handled by getDepNodeTypes()
+
+ ArrayList <String> depList = getDepNodeTypes(transId, fromAppId, nodeType, apiVersion);
+ if( depList.isEmpty() ){
+ return false;
+ }
+ else {
+ return true;
+ }
+
+ }// End needsADepNode4Uniqueness()
+
+ /**
+ * Needs A dep node 4 uniqueness.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @return the boolean
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ private static Boolean needsADepNode4Uniqueness(String transId, String fromAppId, String nodeType)throws AAIException{
+ return needsADepNode4Uniqueness( transId, fromAppId, nodeType, null);
+ }
+
+ /**
+ * Node type A can depend on B.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeTypeA the node type A
+ * @param nodeTypeB the node type B
+ * @param apiVersion the api version
+ * @return the boolean
+ * @throws AAIException the AAI exception
+ */
+ public static Boolean nodeTypeACanDependOnB(String transId, String fromAppId, String nodeTypeA, String nodeTypeB, String apiVersion)
+ throws AAIException{
+ // Note: the passed in nodeType could really be a nodeTypeCategory. That is handled by getDepNodeTypes()
+
+ ArrayList <String> depList = getDepNodeTypes(transId, fromAppId, nodeTypeA, apiVersion);
+ if( depList.isEmpty() ){
+ return false;
+ }
+ else if( depList.contains(nodeTypeB) ){
+ return true;
+ }
+ else {
+ return false;
+ }
+
+ }// End nodeTypeACanDependOnB()
+
+ /**
+ * Node type A can depend on B.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeTypeA the node type A
+ * @param nodeTypeB the node type B
+ * @return the boolean
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ private static Boolean nodeTypeACanDependOnB(String transId, String fromAppId, String nodeTypeA, String nodeTypeB)
+ throws AAIException{
+ return nodeTypeACanDependOnB( transId, fromAppId, nodeTypeA, nodeTypeB, null);
+ }
+
+ /**
+ * Figure dep node type for request.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param requestParamHash the request param hash
+ * @param apiVersion the api version
+ * @return the string
+ * @throws AAIException the AAI exception
+ */
+ public static String figureDepNodeTypeForRequest(String transId, String fromAppId, String nodeType,
+ HashMap<String,Object> requestParamHash, String apiVersion )throws AAIException{
+ /*
+ * This is ugly. But if the passed-in nodeType is dependent on another nodeType for
+ * uniqueness, we need to return what that dependent node-type is. The ugly comes in
+ * because a node can be dependent on more than one type of node. So, to tell which one
+ * is going to apply, we root through the passed request parameters to see which of
+ * the possible dependent node types is being used.
+ * Note -- if there comes a day when there are so many dependencies that the request could
+ * have more than one that match -- Then we need to think up something new. But for now,
+ * we have to assume that if there are more than one legal dep-node-types, only one will
+ * be represented in the requestHash data. >>> NOTE >>> That day has come. For
+ * the upstreamers will send in a LinkedHashMap instead of just an unordered
+ * HashMap so we can look in order for the dependent node.
+ *
+ */
+
+ if( requestParamHash == null ){
+ throw new AAIException("AAI_6120", "Bad param: null requestParamHash ");
+ }
+
+ ArrayList <String> depNodeTypes = getDepNodeTypes(transId, fromAppId, nodeType, apiVersion);
+ if( depNodeTypes.isEmpty() ){
+ // This kind of node is not dependent on any other
+ //aaiLogger.debug(logline, " (not dependent) - end ");
+ return "";
+ }
+ else if( depNodeTypes.size() == 1 ){
+ // This kind of node can only depend on one other nodeType - so return that.
+ //aaiLogger.debug(logline, " (depends on " + depNodeTypes.get(0) + " - end ");
+ return depNodeTypes.get(0);
+ }
+ else {
+ // We need to look to find the first of the dep-node types that is represented in the passed-in
+ // request data. That will be the one we need to use.
+
+ // first find out what node-types are represented in the requestHash
+
+ Iterator <Map.Entry<String,Object>>it = requestParamHash.entrySet().iterator();
+ while( it.hasNext() ){
+ Map.Entry <String,Object>pairs = (Map.Entry<String,Object>)it.next();
+ String k = (pairs.getKey()).toString();
+ int periodLoc = k.indexOf(".");
+ if( periodLoc <= 0 ){
+ throw new AAIException("AAI_6120", "Bad filter param key passed in: [" + k + "]. Expected format = [nodeName.paramName]\n");
+ }
+ else {
+ String nty = k.substring(0,periodLoc);
+ if( depNodeTypes.contains(nty) ){
+ // This is the first possible dep. node type we've found for the passed in data set
+ return nty;
+ }
+ }
+ }
+
+ }
+
+ // It's not an error if none is found - the caller needs to deal with cases where there
+ // should be a dep. node identified but isn't.
+ //aaiLogger.debug(logline, " no dep NT found - end ");
+ return "";
+
+ }// End of figureDepNodeTypeForRequest()
+
+ /**
+ * Figure dep node type for request.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param requestParamHash the request param hash
+ * @return the string
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static String figureDepNodeTypeForRequest(String transId, String fromAppId, String nodeType,
+ HashMap<String,Object> requestParamHash )throws AAIException{
+ return figureDepNodeTypeForRequest( transId, fromAppId, nodeType, requestParamHash, null);
+ }
+
+ /**
+ * Detach connected nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param startNodeVal the start node val
+ * @param autoDeleteOrphans the auto delete orphans
+ * @param apiVersion the api version
+ * @return deletedNodeCount
+ * @throws AAIException the AAI exception
+ */
+ public static int detachConnectedNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, boolean autoDeleteOrphans, String apiVersion ) throws AAIException{
+
+ /* Find nodes that are attached to this node which meet the nodeType/filterParams criteria.
+ * Remove the edges that go to those nodes.
+ * If that turns any of the nodes into an orphan, then delete it if the autoDeleteOrphans flag is set.
+ * Return a count of how many nodes were actually deleted (not just detached).
+ */
+
+ int deletedCount = 0;
+
+ if( startNodeVal == null ){
+ // They should have passed in the node that this query starts from
+ throw new AAIException("AAI_6109", "null startNode object passed to detachConnectedNodes().");
+ }
+
+ // We want to loop through the connected Nodes that we found.
+ // For each connected Node, we'll get the all edges that start from that node and look for the one
+ // that connects back to our startNode.
+ // Only delete the edge that connects back to our startNode.
+ // then autoDeleteOrphans flag is set, then delete the connectedNode if it's now orphaned.
+ //
+
+ String startNodeVId = startNodeVal.id().toString();
+ ArrayList<TitanVertex> conNodeList = getConnectedNodes( transId, fromAppId, graph, nodeType, propFilterHash, startNodeVal, apiVersion, false );
+ Iterator<TitanVertex> conVIter = conNodeList.iterator();
+ while( conVIter.hasNext() ){
+ TitanVertex connectedVert = conVIter.next();
+ boolean isFirstOne = true;
+ Iterator<Edge> eI = connectedVert.edges(Direction.BOTH);
+ while( eI.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI.next();
+ TitanVertex otherVtx = (TitanVertex) ed.otherVertex(connectedVert);
+ String otherSideLookingBackVId = otherVtx.id().toString();
+ if( startNodeVId.equals(otherSideLookingBackVId) ){
+ // This is an edge from the connected node back to our starting node
+ if( isFirstOne && !eI.hasNext() && autoDeleteOrphans ){
+ // This was the one and only edge for this connectedNode, so
+ // delete the node and edge since flag was set
+ String resVers = connectedVert.<String>property("resource-version").orElse(null);
+ removeAaiNode( transId, fromAppId, graph, connectedVert, "USE_DEFAULT", apiVersion, resVers);
+ deletedCount = deletedCount + 1;
+ }
+ else {
+ removeAaiEdge( transId, fromAppId, graph, ed );
+ }
+ }
+ isFirstOne = false;
+ }
+ }
+ return deletedCount;
+
+ } // end of detachConnectedNodes()
+
+
+
+ /**
+ * Detach connected nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param startNodeVal the start node val
+ * @param autoDeleteOrphans the auto delete orphans
+ * @return the int
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static int detachConnectedNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, boolean autoDeleteOrphans ) throws AAIException{
+ return detachConnectedNodes( transId, fromAppId, graph, nodeType,
+ propFilterHash, startNodeVal, autoDeleteOrphans, null);
+ }
+
+ /**
+ * Gets the nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param noFilterOnPurpose the no filter on purpose
+ * @param apiVersion the api version
+ * @return ArrayList<TitanVertex>
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static ArrayList<TitanVertex> getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, Boolean noFilterOnPurpose, String apiVersion ) throws AAIException{
+ boolean skipGroomingFlag = true;
+ // we will only do real-time grooming if a system variable is set, telling us not to skip it.
+ String skipGroomingStr = AAIConstants.AAI_SKIPREALTIME_GROOMING;
+ if( skipGroomingStr.equals("false") ){
+ skipGroomingFlag = false;
+ }
+ return( getNodes(transId, fromAppId, graph, nodeType, propFilterHash, noFilterOnPurpose, apiVersion, skipGroomingFlag) );
+ }
+
+ /**
+ * Gets the nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param noFilterOnPurpose the no filter on purpose
+ * @param apiVersion the api version
+ * @param skipGroomCheck the skip groom check
+ * @return ArrayList<TitanVertex>
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static ArrayList<TitanVertex> getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, Boolean noFilterOnPurpose, String apiVersion, boolean skipGroomCheck )
+ throws AAIException{
+ // Note - the skipGroomCheck flag is set to true when the DataGrooming tool is using this method to collect
+ // node data. When the grooming tool is collecting data, we don't want any nodes skipped, because we
+ // want details about what nodes/edges are bad - more detail than the check in this method does
+ // as it checks if a node is ok to return to a caller.
+
+ /* Use the nodeType + filterParams to find nodes.
+ */
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ ArrayList<TitanVertex> returnVertList = new ArrayList<TitanVertex>();
+ if( nodeType == null || nodeType.equals("") ){
+ // They should have passed in a nodeType
+ throw new AAIException("AAI_6118", "Required field: nodeType not passed to getNodes().");
+ }
+
+ if( !noFilterOnPurpose && (propFilterHash == null || propFilterHash.isEmpty()) ){
+ // They should have passed at least one property to filter on
+ throw new AAIException("AAI_6118", "Required field: propFilterHash not passed to getNodes().");
+ }
+
+ ArrayList<String> kName = new ArrayList<String>();
+ ArrayList<Object> kVal = new ArrayList<Object>();
+ int i = -1;
+ Collection <String> indexedProps = dbMaps.NodeMapIndexedProps.get(nodeType);
+ // First loop through to pick up the indexed-properties if there are any being used
+
+ if( propFilterHash != null ){
+ Iterator <?> it = propFilterHash.entrySet().iterator();
+ while( it.hasNext() ){
+ Map.Entry<?,?> propEntry = (Map.Entry<?,?>) it.next();
+ String propName = (propEntry.getKey()).toString();
+ // Don't allow search on properties that do not have SINGLE cardinality
+ if( !checkPropCardinality(propName, "Set") && !checkPropCardinality(propName, "List") ){
+ if( indexedProps.contains(propName) ){
+ i++;
+ kName.add(i, propName);
+ kVal.add(i, (Object)propEntry.getValue());
+ }
+ }
+ }
+
+ // Now go through again and pick up the non-indexed properties
+ it = propFilterHash.entrySet().iterator();
+ while( it.hasNext() ){
+ Map.Entry <?,?> propEntry = (Map.Entry<?,?>)it.next();
+ String propName = (propEntry.getKey()).toString();
+ // Don't allow search on properties that do not have SINGLE cardinality
+ if( !checkPropCardinality(propName, "Set") && !checkPropCardinality(propName, "List") ){
+ if( ! indexedProps.contains(propName) ){
+ i++;
+ kName.add(i, propName);
+ kVal.add(i, (Object)propEntry.getValue());
+ }
+ }
+ }
+ }
+
+ Iterable <?> verts = null;
+ String propsAndValuesForMsg = "";
+ int topPropIndex = i;
+ if( topPropIndex == -1 ){
+ // No Filtering -- just go get them all
+ verts= graph.query().has("aai-node-type",nodeType).vertices();
+ propsAndValuesForMsg = " ( no filter props ) ";
+ }
+ else if( topPropIndex == 0 ){
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has("aai-node-type",nodeType).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ") ";
+ }
+ else if( topPropIndex == 1 ){
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has("aai-node-type",nodeType).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ") ";
+ }
+ else if( topPropIndex == 2 ){
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).has("aai-node-type",nodeType).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ", "
+ + kName.get(2) + " = " + kVal.get(2) + ") ";
+ }
+ else if( topPropIndex == 3 ){
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).has(kName.get(3),kVal.get(3)).has("aai-node-type",nodeType).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ", "
+ + kName.get(2) + " = " + kVal.get(2) + ", "
+ + kName.get(3) + " = " + kVal.get(3) + ") ";
+ }
+ else {
+ String emsg = " -- Sorry -- we only support 4 filter properties in getNodes() for now... \n";
+ throw new AAIException("AAI_6114", emsg);
+ }
+ if( verts != null ){
+ // We did find some matching vertices
+ Iterator <?> it = verts.iterator();
+ while( it.hasNext() ){
+ TitanVertex v = (TitanVertex)it.next();
+
+ if( skipGroomCheck ){
+ // Good or bad, just return everything we find
+ returnVertList.add( v );
+ }
+ else {
+ // Weed out any bad vertices we find
+ if( thisVertexNotReachable(transId, fromAppId, graph, v, apiVersion) ){
+ LOGGER.info("IN-LINE GROOMING - Unreachable Node DETECTED > skipping it. ");
+ }
+ else if( thisVertexHasBadEdges(transId, fromAppId, graph, v, apiVersion) ){
+ LOGGER.info("IN-LINE GROOMING - BAD EDGE DETECTED > skipping vtxId = [" + v.id() + "] ");
+ }
+ else if( thisVertexIsAPhantom(transId, fromAppId, graph, v, apiVersion) ){
+ LOGGER.info("IN-LINE GROOMING - BAD NODE DETECTED > skipping vtxId = [" + v.id() + "] ");
+ }
+ else {
+ returnVertList.add( v );
+ }
+ }
+ }
+ }
+
+ return returnVertList;
+ }
+
+ /**
+ * Gets the nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param noFilterOnPurpose the no filter on purpose
+ * @return the nodes
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static ArrayList<TitanVertex> getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, Boolean noFilterOnPurpose ) throws AAIException{
+ return getNodes(transId, fromAppId, graph, nodeType,
+ propFilterHash, noFilterOnPurpose, null );
+ }
+ // End of getNodes()
+
+
+ /**
+ * Gets the connected children.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVtx the start vtx
+ * @param limitToThisNodeType the limit to this node type
+ * @return ArrayList <TitanVertex>
+ * @throws AAIException the AAI exception
+ */
+ public static ArrayList<TitanVertex> getConnectedChildren( String transId, String fromAppId, TitanTransaction graph,
+ TitanVertex startVtx, String limitToThisNodeType ) throws AAIException{
+
+ // Just get child nodes (ie. other end of an OUT edge that is tagged as a parent/Child edge)
+
+ ArrayList <TitanVertex> childList = new ArrayList <TitanVertex> ();
+ Boolean doNodeTypeCheck = false;
+ if( limitToThisNodeType != null && ! limitToThisNodeType.equals("") ){
+ doNodeTypeCheck = true;
+ }
+
+
+ List<Vertex> verts = graph.traversal().V(startVtx).union(__.inE().has("isParent-REV", true).outV(), __.outE().has("isParent", true).inV()).toList();
+ TitanVertex tmpVtx = null;
+ int vertsSize = verts.size();
+ for (int i = 0; i < vertsSize; i++){
+ tmpVtx = (TitanVertex) verts.get(i);
+ if( ! doNodeTypeCheck ){
+ childList.add(tmpVtx);
+ }
+ else {
+ String tmpNT = tmpVtx.<String>property("aai-node-type").orElse(null);
+ if( tmpNT != null && tmpNT.equals(limitToThisNodeType) ){
+ childList.add(tmpVtx);
+ }
+ }
+ }
+
+ return childList;
+
+ }// End of getConnectedChildren()
+
+
+
+ /**
+ * Gets the connected nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param startNodeVal the start node val
+ * @param apiVersion the api version
+ * @param excludeRecurComingIn the exclude recur coming in
+ * @return ArrayList <TitanVertex>
+ * @throws AAIException the AAI exception
+ */
+ public static ArrayList<TitanVertex> getConnectedNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, String apiVersion, Boolean excludeRecurComingIn ) throws AAIException{
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+ /* Get (almost) all the nodes that are connected to this vertex.
+ * Narrow down what is returned using optional filter parameters nodeType and propFilterHash
+ * NOTE - the default behavior has changed slightly. For start-Nodes that
+ * can be recursivly connected, this method will only bring back the same kind of
+ * connected node by following an OUT edge. Ie. if the start node is an "model-element",
+ * then this method will only follow OUT edges to get to other "model-element" type nodes.
+ */
+
+ String startNodeNT = "";
+ if( startNodeVal == null ){
+ // They should have passed in the node that this query starts from
+ throw new AAIException("AAI_6109", "null startNode object passed to getConnectedNodes().");
+ }
+ else {
+ startNodeNT = startNodeVal.<String>property("aai-node-type").orElse(null);
+ }
+
+ boolean nodeTypeFilter = false;
+ if( nodeType != null && !nodeType.equals("") ){
+ // They want to filter using nodeType
+ if( ! dbMaps.NodeProps.containsKey(nodeType) ){
+ throw new AAIException("AAI_6115", "Unrecognized nodeType [" + nodeType + "] passed to getConnectedNodes().");
+ }
+ nodeTypeFilter = true;
+ }
+
+ ArrayList <String> excludeVidList = new <String> ArrayList ();
+ if( DbEdgeRules.CanBeRecursiveNT.containsKey(startNodeNT) && excludeRecurComingIn ){
+ // If we're starting on a nodeType that supports recursion, then find any connected
+ // nodes that are coming from IN edges so we can exclude them later.
+
+ Iterable <?> vertsR = startNodeVal.query().direction(Direction.IN).vertices();
+ Iterator <?> vertIR = vertsR.iterator();
+ while( vertIR != null && vertIR.hasNext() ){
+ TitanVertex tmpVertIN = (TitanVertex) vertIR.next();
+ String tmpNT = tmpVertIN.<String>property("aai-node-type").orElse(null);
+ if( tmpNT != null && tmpNT.equals(startNodeNT) ){
+ // We're on a nodetype that supports recursion (like model-element) and we've
+ // found an connected Node of this same type on an IN edge - put this
+ // on our excludeList.
+ excludeVidList.add( tmpVertIN.id().toString() );
+ }
+ }
+ }
+
+ boolean propertyFilter = false;
+ if( propFilterHash != null && !propFilterHash.isEmpty() ){
+ // They want to filter using some properties
+ Iterator <?> it = propFilterHash.entrySet().iterator();
+ while( it.hasNext() ){
+ Map.Entry<?,?> propEntry = (Map.Entry<?,?>)it.next();
+ String propName = (propEntry.getKey()).toString();
+ if( ! dbMaps.NodeProps.containsValue(propName) ){
+ throw new AAIException("AAI_6116", "Unrecognized property name [" + propName + "] passed to getConnectedNodes().");
+ }
+ // Don't allow search on properties that do not have SINGLE cardinality
+ if( !checkPropCardinality(propName, "Set") && !checkPropCardinality(propName, "List") ){
+ propertyFilter = true;
+ }
+ }
+ }
+ // If filter-properties were passed in, then look for nodes that have those values.
+ ArrayList<TitanVertex> returnVertList = new ArrayList<TitanVertex>();
+ Iterable<TitanVertex> qResult = null;
+ Iterator<TitanVertex> resultI = null;
+ try {
+ qResult = startNodeVal.query().vertices();
+ resultI = qResult.iterator();
+ }
+ catch( NullPointerException npe ){
+ throw new AAIException("AAI_6125", "Titan null pointer exception trying to get nodes connected to vertexId = " +
+ startNodeVal.id() + ", aai-node-type = [" + startNodeVal.property("aai-node-type") + "].");
+ }
+
+ while( resultI != null && resultI.hasNext() ){
+ boolean addThisOne = true;
+ TitanVertex tmpV = (TitanVertex)resultI.next();
+ if( tmpV == null ){
+ LOGGER.info("Titan gave a null vertex when looking for nodes connected to vertexId = " +
+ startNodeVal.id() + ", aai-node-type = [" + startNodeVal.property("aai-node-type") + "].");
+ // Note - we will skip this one, but try to return any others that we find.
+ addThisOne = false;
+ }
+
+ else {
+ String tmpVid = tmpV.id().toString();
+ if( nodeTypeFilter ){
+ Object nto = tmpV.<Object>property("aai-node-type").orElse(null);
+ if( nto == null || !nto.toString().equals(nodeType) ){
+ //LOGGER.info("Found a connected vertex (vertexId = " +
+ // tmpVid + "), but we will not collect it. It had aai-node-type [" +
+ // nto + "], we are looking for [" + nodeType + "]. ");
+ // Note - we will skip this one, but try to return any others that we find.
+ addThisOne = false;
+ }
+ }
+
+ if( excludeVidList.contains(tmpVid) ){
+ LOGGER.info("Found a connected vertex (vertexId = " +
+ tmpVid + "), but will exclude it since it is on an IN edge and this nodeType " +
+ startNodeNT + " can be recursively attached.");
+ // Note - we will skip this one, but try to return any others that we find.
+ addThisOne = false;
+ }
+
+ if( propertyFilter ){
+ Iterator <?> it = propFilterHash.entrySet().iterator();
+ while( it.hasNext() ){
+ Map.Entry <?,?>propEntry = (Map.Entry<?,?>)it.next();
+ String propName = (propEntry.getKey()).toString();
+ if( checkPropCardinality(propName, "Set") || checkPropCardinality(propName, "List") ){
+ // Don't allow search on properties that do not have SINGLE cardinality
+ continue;
+ }
+ Object propVal = propEntry.getValue();
+ Object foundVal = tmpV.<Object>property(propName).orElse(null);
+ if( foundVal != null && propVal != null && !foundVal.toString().equals(propVal.toString()) ){
+ addThisOne = false;
+ break;
+ }
+ else if( (foundVal == null && propVal != null) || (foundVal != null && propVal == null) ){
+ addThisOne = false;
+ break;
+ }
+ }
+ }
+ }
+ if( addThisOne ){
+ // This node passed the tests -- put it on the return List
+ returnVertList.add( (TitanVertex)tmpV );
+ }
+ }
+ //aaiLogger.debug(logline, " end ");
+ return returnVertList;
+
+ }// End of getConnectedNodes()
+
+
+ /**
+ * Gets the connected nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param startNodeVal the start node val
+ * @param apiVersion the api version
+ * @return the connected nodes
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static ArrayList<TitanVertex> getConnectedNodes(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, String apiVersion ) throws AAIException {
+ return getConnectedNodes( transId, fromAppId, graph, nodeType,
+ propFilterHash, startNodeVal, apiVersion, true );
+ }
+
+ /**
+ * Gets the connected nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param startNodeVal the start node val
+ * @return the connected nodes
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static ArrayList<TitanVertex> getConnectedNodes(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, TitanVertex startNodeVal ) throws AAIException {
+ return getConnectedNodes( transId, fromAppId, graph, nodeType,
+ propFilterHash, startNodeVal, null, true );
+
+ }
+
+ /**
+ * Ip address format OK.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param addrVal the addr val
+ * @param addrVer the addr ver
+ * @param apiVersion the api version
+ * @return Boolean
+ * @throws AAIException the AAI exception
+ */
+ public static Boolean ipAddressFormatOK(String transId, String fromAppId, String addrVal, String addrVer, String apiVersion) throws AAIException{
+
+ /* NOTE -- the google methods we use do not allow leading zeros in ipV4 addresses.
+ * So it will reject, "22.33.44.001"
+ */
+
+ if( addrVal == null ){
+ throw new AAIException("AAI_6120", "Bad data (addrVal = null) passed to ipAddressFormatOK()");
+ }
+ else if( addrVer == null ){
+ throw new AAIException("AAI_6120", "Bad data (addrType = null) passed to ipAddressFormatOK()");
+ }
+
+ Boolean retVal = false;
+ Boolean lookingForV4 = false;
+ Boolean lookingForV6 = false;
+ InetAddress inetAddr = null;
+
+ if( addrVer.equalsIgnoreCase("v4") || addrVer.equals("ipv4") || addrVer.equals("4")){
+ lookingForV4 = true;
+ }
+ else if( addrVer.equalsIgnoreCase("v6") || addrVer.equals("ipv6") || addrVer.equals("6")){
+ lookingForV6 = true;
+ }
+ else {
+ throw new AAIException("AAI_6120", " Bad data for addressVersion [" + addrVer + "] passed to ipAddressFormatOK()");
+ }
+
+ try {
+ inetAddr = InetAddresses.forString(addrVal);
+ if( inetAddr instanceof Inet4Address ){
+ if( lookingForV4 ){
+ retVal = true;
+ }
+ else {
+ throw new AAIException("AAI_6120", "Bad data. Address is a V4, but addressType said it should be V6. ["
+ + addrVal + "], [" + addrVer + "] passed to ipAddressFormatOK()");
+ }
+ }
+ else if( inetAddr instanceof Inet6Address ){
+ if( lookingForV6 ){
+ retVal = true;
+ }
+ else {
+ throw new AAIException("AAI_6120", "Bad data. Address is a V6, but addressType said it should be V4. ["
+ + addrVal + "], [" + addrVer + "] passed to ipAddressFormatOK().");
+ }
+ }
+ }
+ catch (IllegalArgumentException e) {
+ throw new AAIException("AAI_6120", "Badly formed ip-address: [" + addrVal + "] passed to ipAddressFormatOK()");
+ }
+
+ return retVal;
+
+ }//end of ipAddressFormatOk()
+
+ /**
+ * Ip address format OK.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param addrVal the addr val
+ * @param addrVer the addr ver
+ * @return the boolean
+ * @throws AAIException the AAI exception
+ */
+ public static Boolean ipAddressFormatOK(String transId, String fromAppId, String addrVal, String addrVer) throws AAIException{
+ return ipAddressFormatOK( transId, fromAppId, addrVal, addrVer, null);
+ }
+
+ /**
+ * Save aai edge to db.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param edgeLabel the edge label
+ * @param outV the out V
+ * @param inV the in V
+ * @param propHash the prop hash
+ * @param apiVersion the api version
+ * @return TitanEdge
+ * @throws AAIException the AAI exception
+ */
+ private static TitanEdge saveAaiEdgeToDb(String transId, String fromAppId, TitanTransaction graph, String edgeLabel,
+ TitanVertex outV, TitanVertex inV, HashMap <String,Object> propHash, String apiVersion) throws AAIException{
+
+ // If this edge doesn't exist yet, then create it.
+
+ // NOTE - the Titan javaDoc says that there might not always be an id for a node.
+ // This is the internal-titan-unique-id, not any of our data.
+ // Not sure how to know when it might be there and when it might not?!
+ // So far, it has worked for all my testing, but this might warrant some
+ // further investigation.
+
+ TitanEdge existingEdge = null;
+ String inVId = inV.id().toString();
+ Iterator <Edge> eI = outV.edges(Direction.BOTH, edgeLabel);
+ while( eI.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI.next();
+ TitanVertex otherVtx = (TitanVertex) ed.otherVertex(outV);
+ if( (otherVtx.id().toString()).equals(inVId) ){
+ // NOTE -?- Not sure -- at some point we might want to check the edgeLabels also since we might
+ // want to allow two different-type edges between the same two vertexes? (or maybe not.)
+ existingEdge = ed;
+ break;
+ }
+ }
+
+ if( existingEdge != null ){
+ // This is just an UPDATE
+ for( Map.Entry<String, Object> entry : propHash.entrySet() ){
+ LOGGER.debug("update edge property/val = [" + entry.getKey() + "]/[" + entry.getValue() + "]");
+ existingEdge.property( entry.getKey(), entry.getValue() );
+ }
+
+ return( existingEdge );
+ }
+ else {
+ // This is an ADD
+
+ // Uniqueness double-check. This is just to catch the possibility that at the transaction layer,
+ // if data came in for two identical nodes that point to the same dependant node (for uniqueness),
+ // we would only be able to catch the problem at the time the edge to the second node is added.
+ // For example - if they had a VM and then got a request to add two ipAddress nodes, but some
+ // bad data was passed and those two ipAddress nodes were identical -- we'd want to catch it.
+ String outV_NType = outV.<String>property("aai-node-type").orElse(null);
+ String inV_NType = inV.<String>property("aai-node-type").orElse(null);
+ if( needsADepNode4Uniqueness(transId, fromAppId, outV_NType, apiVersion)
+ && nodeTypeACanDependOnB(transId, fromAppId, outV_NType, inV_NType, apiVersion) ){
+ // The out-Vertex has a uniqueness dependency on the in-vertex
+ // Make sure we haven't already added an node/edge like this in this transaction
+ HashMap <String, Object> nodeKeyPropsHash = getNodeKeyPropHash(transId, fromAppId, graph, outV);
+ ArrayList<TitanVertex> resultList = new ArrayList<TitanVertex>();
+ resultList = DbMeth.getConnectedNodes("transId", "fromAppId", graph, outV_NType, nodeKeyPropsHash, inV, apiVersion, false);
+ if( resultList.size() > 0 ){
+ String propInfo = "";
+ if( nodeKeyPropsHash != null ){
+ propInfo = nodeKeyPropsHash.toString();
+ }
+ throw new AAIException("AAI_6117", "Failed to add edge. This node (" + inV_NType + ") already has an edge to a " + outV_NType +
+ " node with kepProps [" + propInfo + "]");
+ }
+ }
+ else if( needsADepNode4Uniqueness(transId, fromAppId, inV_NType, apiVersion)
+ && nodeTypeACanDependOnB(transId, fromAppId, inV_NType, outV_NType, apiVersion) ){
+ // The in-Vertex has a uniqueness dependency on the out-vertex
+ // Make sure we haven't already added an node/edge like this in this transaction
+ HashMap <String, Object> nodeKeyPropsHash = getNodeKeyPropHash(transId, fromAppId, graph, inV);
+ ArrayList<TitanVertex> resultList = new ArrayList<TitanVertex>();
+ resultList = DbMeth.getConnectedNodes("transId", "fromAppId", graph, inV_NType, nodeKeyPropsHash, outV, apiVersion, false);
+ if( resultList.size() > 0 ){
+ String propInfo = "";
+ if( nodeKeyPropsHash != null ){
+ propInfo = nodeKeyPropsHash.toString();
+ }
+ throw new AAIException("AAI_6117", "Failed to add edge. This node (" + outV_NType + ") already has an edge to a " + inV_NType +
+ " node with kepProps [" + propInfo + "]");
+ }
+ }
+
+
+ // We're good to go to add this edge
+
+ TitanEdge tEdge = outV.addEdge( edgeLabel, inV );
+ // Add the properties to the new Edge
+ for( Map.Entry<String, Object> entry : propHash.entrySet() ){
+ tEdge.property( entry.getKey(), entry.getValue() );
+ }
+
+ // For (resource-id updates) we need to "touch" the vertices on each side of the edge so
+ // anybody working on one of those vertices will know that something (ADDing this edge) has happened.
+ touchVertex( transId, fromAppId, inV );
+ touchVertex( transId, fromAppId, outV );
+
+ return tEdge;
+ }
+
+ }// End saveAaiEdgeToDb()
+
+
+
+ /**
+ * Derive edge rule key for this edge.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param tEdge the t edge
+ * @return String - key to look up edgeRule (fromNodeType|toNodeType)
+ * @throws AAIException the AAI exception
+ */
+ public static String deriveEdgeRuleKeyForThisEdge( String transId, String fromAppId, TitanTransaction graph,
+ TitanEdge tEdge ) throws AAIException{
+
+ TitanVertex fromVtx = tEdge.outVertex();
+ TitanVertex toVtx = tEdge.inVertex();
+ String startNodeType = fromVtx.<String>property("aai-node-type").orElse(null);
+ String targetNodeType = toVtx.<String>property("aai-node-type").orElse(null);
+ String key = startNodeType + "|" + targetNodeType;
+ if( EdgeRules.getInstance().hasEdgeRule(startNodeType, targetNodeType) ){
+ // We can use the node info in the order they were given
+ return( key );
+ }
+ else {
+ key = targetNodeType + "|" + startNodeType;
+ if( EdgeRules.getInstance().hasEdgeRule(targetNodeType, startNodeType) ){
+ return( key );
+ }
+ else {
+ // Couldn't find a rule for this edge
+ throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + startNodeType + ", "
+ + targetNodeType);
+ }
+ }
+ }// end of deriveEdgeRuleKeyForThisEdge()
+
+
+
+ /**
+ * Save aai edge to db.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param edgeLabel the edge label
+ * @param outV the out V
+ * @param inV the in V
+ * @param propHash the prop hash
+ * @return the titan edge
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ private static TitanEdge saveAaiEdgeToDb(String transId, String fromAppId, TitanTransaction graph, String edgeLabel,
+ TitanVertex outV, TitanVertex inV, HashMap <String,Object> propHash) throws AAIException{
+ return saveAaiEdgeToDb( transId, fromAppId, graph, edgeLabel,
+ outV, inV, propHash, null);
+ }
+
+ /**
+ * Persist aai edge.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param targetVert the target vert
+ * @param apiVersion the api version
+ * @return the titan edge
+ * @throws AAIException the AAI exception
+ */
+ public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph,
+ TitanVertex startVert, TitanVertex targetVert, String apiVersion ) throws AAIException{
+ TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, apiVersion, "");
+ return returnEdge;
+ }
+
+ /**
+ * Persist aai edge.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param targetVert the target vert
+ * @param apiVersion the api version
+ * @param edgeType the edge type
+ * @return TitanEdge
+ * @throws AAIException the AAI exception
+ */
+ public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph,
+ TitanVertex startVert, TitanVertex targetVert, String apiVersion, String edgeType ) throws AAIException{
+
+ TitanVertex fromVtx = null;
+ TitanVertex toVtx = null;
+ String startNodeType = startVert.<String>property("aai-node-type").orElse(null);
+ String targetNodeType = targetVert.<String>property("aai-node-type").orElse(null);
+ String fwdRuleKey = startNodeType + "|" + targetNodeType;
+ int fwdRuleCount = 0;
+ String fwdRule = "";
+ String fwdLabel = "";
+ String revRuleKey = targetNodeType + "|" + startNodeType;
+ int revRuleCount = 0;
+ String revRule = "";
+ String revLabel = "";
+ String edRule = "";
+ String edLabel = "";
+
+ Boolean checkType = false;
+ if( (edgeType != null) && edgeType != "" ){
+ checkType = true;
+ }
+
+ // As of 16-07, it is possible to have more than one kind of edge defined between a given
+ // pair of nodeTypes. So we need to check to see if there is only one possibility, or if
+ // we need to look at the edgeType to determine which to use.
+ // NOTE -- we're only supporting having 2 edges between a given pair of nodeTypes and
+ // one and only one of them would have to be a parent-child edge.
+
+ if( DbEdgeRules.EdgeRules.containsKey(fwdRuleKey) ){
+ Collection <String> edRuleColl = DbEdgeRules.EdgeRules.get(fwdRuleKey);
+ Iterator <String> ruleItr = edRuleColl.iterator();
+ while( ruleItr.hasNext() ){
+ String tmpRule = ruleItr.next();
+ String [] rules = tmpRule.split(",");
+ String tmpLabel = rules[0];
+ String tmpParChild = rules[3];
+ if( !checkType
+ || (checkType && tmpParChild.equals("true") && edgeType.equals("parentChild"))
+ || (checkType && tmpParChild.equals("false") && edgeType.equals("cousin")) ){
+ // Either they didn't want us to check the edgeType or it is a match
+ fwdRuleCount++;
+ if( fwdRuleCount > 1 ){
+ // We found more than one with the given info
+ throw new AAIException("AAI_6120", "Multiple EdgeRules found for nodeTypes: [" + startNodeType + "], ["
+ + targetNodeType + "], edgeType = [" + edgeType + "].");
+ }
+ else {
+ fwdRule = tmpRule;
+ fwdLabel = tmpLabel;
+ }
+ }
+ }
+ }
+
+ // Try it the other way also (unless this is the case of a nodeType recursively pointing to itself
+ // Ie. the edge rule: "model-element|model-element"
+ if( !revRuleKey.equals(fwdRuleKey) && DbEdgeRules.EdgeRules.containsKey(revRuleKey) ){
+ Collection <String> edRuleColl = DbEdgeRules.EdgeRules.get(revRuleKey);
+ Iterator <String> ruleItr = edRuleColl.iterator();
+ while( ruleItr.hasNext() ){
+ String tmpRule = ruleItr.next();
+ String [] rules = tmpRule.split(",");
+ String tmpLabel = rules[0];
+ String tmpParChild = rules[3];
+ if( !checkType
+ || (checkType && tmpParChild.equals("true") && edgeType.equals("parentChild"))
+ || (checkType && tmpParChild.equals("false") && edgeType.equals("cousin")) ){
+ // Either they didn't want us to check the edgeType or it is a match
+ revRuleCount++;
+ if( revRuleCount > 1 ){
+ // We found more than one with the given info
+ throw new AAIException("AAI_6120", "Multiple EdgeRules found for nodeTypes: [" + targetNodeType + "], ["
+ + startNodeType + "], edgeType = [" + edgeType + "].");
+ }
+ else {
+ revRule = tmpRule;
+ revLabel = tmpLabel;
+ }
+ }
+ }
+ }
+
+ if( (fwdRuleCount == 1) && (revRuleCount == 0) ){
+ // We can use the node info in the order they were given
+ fromVtx = startVert;
+ toVtx = targetVert;
+ edRule = fwdRule;
+ edLabel = fwdLabel;
+ }
+ else if( (fwdRuleCount == 0) && (revRuleCount == 1) ){
+ // We need to switch the vertex order so the edge-direction is correct
+ toVtx = startVert;
+ fromVtx = targetVert;
+ edRule = revRule;
+ edLabel = revLabel;
+ }
+ else if( (fwdRuleCount == 0) && (revRuleCount == 0) ){
+ // No edge rule found for this
+ throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + startNodeType + ", " + targetNodeType
+ + "], checkLabelType = [" + edgeType + "].");
+ }
+ else if( (fwdRuleCount > 0) && (revRuleCount > 0) ){
+ // We found more than one with the given info
+ throw new AAIException("AAI_6120", "Multiple EdgeRules (fwd and rev) found for nodeTypes: [" + startNodeType + "], ["
+ + targetNodeType + "], checkLabelType = [" + edgeType + "].");
+ }
+
+ // If we got to this point, we now have a single edge label and we know to and from Vtx.
+
+ HashMap <String,Object> edgeParamHash = getEdgeTagPropPutHash4Rule(transId, fromAppId, edRule);
+ // We do "source-of-truth" for all edges
+ edgeParamHash.put("source-of-truth", fromAppId );
+
+ TitanEdge returnEdge = saveAaiEdgeToDb(transId, fromAppId, graph, edLabel, fromVtx, toVtx, edgeParamHash, apiVersion);
+
+ return returnEdge;
+
+ }
+
+ /**
+ * Persist aai edge.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param targetVert the target vert
+ * @return the titan edge
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph,
+ TitanVertex startVert, TitanVertex targetVert ) throws AAIException{
+ return persistAaiEdge( transId, fromAppId, graph,
+ startVert, targetVert, null);
+ }
+ // End persistAaiEdge()
+
+
+ /**
+ * Persist aai edge.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param edgeLabel the edge label
+ * @param startVert the start vert
+ * @param targetVert the target vert
+ * @param propHash the prop hash
+ * @param addIfNotFound the add if not found
+ * @return the titan edge
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph,
+ String edgeLabel, TitanVertex startVert, TitanVertex targetVert,
+ HashMap <String,Object> propHash, Boolean addIfNotFound ) throws AAIException{
+
+ /*----- This method is depricated ------
+ * We will ignore the parameters: edgeLabel, propHash and addIfNotFound
+ * We will use the remaining params to call the newer version of this method
+ */
+ TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, null);
+
+ return returnEdge;
+
+ }// End depricated version of persistAaiEdge()
+
+
+ /**
+ * Persist aai edge with dep params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param targetNodeType the target node type
+ * @param targetNodeParamHash the target node param hash
+ * @param apiVersion the api version
+ * @return TitanEdge
+ * @throws AAIException the AAI exception
+ */
+ public static TitanEdge persistAaiEdgeWithDepParams( String transId, String fromAppId, TitanTransaction graph,
+ TitanVertex startVert, String targetNodeType, HashMap <String,Object> targetNodeParamHash, String apiVersion) throws AAIException{
+
+ TitanVertex targetVert = getUniqueNodeWithDepParams( transId, fromAppId, graph, targetNodeType, targetNodeParamHash, apiVersion );
+ TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, apiVersion);
+
+ return returnEdge;
+
+ }// End persistAaiEdgeWithDepParams()
+
+ // Version that lets you pass in an edgeType ("parentChild" or "cousin" since it sometimes cannot be determined
+ /**
+ * Persist aai edge with dep params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param targetNodeType the target node type
+ * @param targetNodeParamHash the target node param hash
+ * @param apiVersion the api version
+ * @param edgeType the edge type
+ * @return the titan edge
+ * @throws AAIException the AAI exception
+ */
+ // from the two nodeTypes anymore (16-07)
+ public static TitanEdge persistAaiEdgeWithDepParams( String transId, String fromAppId, TitanTransaction graph,
+ TitanVertex startVert, String targetNodeType, HashMap <String,Object> targetNodeParamHash,
+ String apiVersion, String edgeType) throws AAIException{
+ TitanVertex targetVert = getUniqueNodeWithDepParams( transId, fromAppId, graph, targetNodeType, targetNodeParamHash, apiVersion );
+ TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, apiVersion, edgeType);
+
+ return returnEdge;
+
+ }// End persistAaiEdgeWithDepParams()
+
+ /**
+ * Persist aai edge with dep params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param targetNodeType the target node type
+ * @param targetNodeParamHash the target node param hash
+ * @return the titan edge
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanEdge persistAaiEdgeWithDepParams( String transId, String fromAppId, TitanTransaction graph,
+ TitanVertex startVert, String targetNodeType, HashMap <String,Object> targetNodeParamHash) throws AAIException{
+ return persistAaiEdgeWithDepParams( transId, fromAppId, graph,
+ startVert, targetNodeType, targetNodeParamHash, null);
+ }
+
+ /**
+ * Gets the node key prop hash.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param vtx the vtx
+ * @return nodeKeyPropHash
+ * @throws AAIException the AAI exception
+ */
+ public static HashMap <String, Object> getNodeKeyPropHash( String transId, String fromAppId, TitanTransaction graph, TitanVertex vtx) throws AAIException{
+
+ if( vtx == null ){
+ throw new AAIException("AAI_6109", "null node object passed to getNodeKeyPropHash().");
+ }
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ String nType = vtx.<String>property("aai-node-type").orElse(null);
+ if( ! dbMaps.NodeKeyProps.containsKey(nType) ){
+ // Problem if no key Properties defined for this nodeType
+ String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+ throw new AAIException("AAI_6105", "No node-key-properties defined in dbMaps for nodeType = " + nType + " (ver=" + defVer + ")");
+ }
+
+ HashMap <String,Object>nodeKeyPropsHash = new HashMap<String,Object>();
+ Collection <String> keyProps = dbMaps.NodeKeyProps.get(nType);
+ Iterator <String> keyPropI = keyProps.iterator();
+ while( keyPropI.hasNext() ){
+ String propName = keyPropI.next();
+ Object value = (Object) vtx.<Object>property(propName).orElse(null);
+ nodeKeyPropsHash.put(propName, value);
+ }
+
+ return nodeKeyPropsHash;
+
+ }// End of getNodeKeyPropHash()
+
+ /**
+ * Gets the node name prop hash.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param vtx the vtx
+ * @param apiVersion the api version
+ * @return nodeKeyPropHash
+ * @throws AAIException the AAI exception
+ */
+ public static HashMap <String, Object> getNodeNamePropHash( String transId, String fromAppId, TitanTransaction graph, TitanVertex vtx, String apiVersion) throws AAIException{
+
+ if( vtx == null ){
+ throw new AAIException("AAI_6109", "null node object passed to getNodeNamePropHash()." );
+ }
+
+ String nType = vtx.<String>property("aai-node-type").orElse(null);
+ HashMap <String,Object>nodeNamePropsHash = new HashMap<String,Object>();
+ Collection <String> keyProps = DbMeth.getNodeNameProps(transId, fromAppId, nType, apiVersion);
+ Iterator <String> keyPropI = keyProps.iterator();
+ while( keyPropI.hasNext() ){
+ String propName = keyPropI.next();
+ Object value = (Object) vtx.<Object>property(propName).orElse(null);
+ nodeNamePropsHash.put(propName, value);
+ }
+
+ return nodeNamePropsHash;
+
+ }// End of getNodeNamePropHash()
+
+
+ /**
+ * Removes the aai edge.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param tEdge the t edge
+ * @return void
+ */
+ public static void removeAaiEdge( String transId, String fromAppId, TitanTransaction graph, TitanEdge tEdge){
+ // Before removing the edge, touch the vertices on each side so their resource-versions will get updated
+ TitanVertex tmpVIn = tEdge.inVertex();
+ touchVertex( transId, fromAppId, tmpVIn );
+
+ TitanVertex tmpVOut = tEdge.outVertex();
+ touchVertex( transId, fromAppId, tmpVOut );
+
+ // Remove the passed in edge.
+ tEdge.remove();
+
+ }// end of removeAaiEdge()
+
+
+ /**
+ * Removes the aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param thisVtx the this vtx
+ * @param scopeParam the scope param
+ * @param apiVersion the api version
+ * @param resourceVersion the resource version
+ * @throws AAIException the AAI exception
+ */
+ public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam,
+ String apiVersion, String resourceVersion ) throws AAIException{
+ // Note: the resource Version Override flag is only set to true when called by the Model Delete code which
+ // has no way to know the resource-versions of nodes at lower-levels of it's model topology.
+ Boolean resVersionOverrideFlag = false;
+ removeAaiNode( transId, fromAppId, graph, thisVtx, scopeParam, apiVersion, resourceVersion, resVersionOverrideFlag );
+ }
+
+
+ /**
+ * <pre>
+ * Possible values for deleteScope can be:
+ * USE_DEFAULT - Get the scope from ref data for this node
+ * THIS_NODE_ONLY (but should fail if it there are nodes that depend on it for uniqueness)
+ * CASCADE_TO_CHILDREN - will look for OUT-Edges that have parentOf/hasDelTarget = true and follow those down
+ * ERROR_4_IN_EDGES_OR_CASCADE - combo of error-if-any-IN-edges + CascadeToChildren
+ * ERROR_IF_ANY_IN_EDGES - Fail if this node has any existing IN edges
+ * ERROR_IF_ANY_EDGES - Fail if this node has any existing edges at all!
+ * </pre>.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param thisVtx the this vtx
+ * @param scopeParam the scope param
+ * @param apiVersion the api version
+ * @param resourceVersion the resource version
+ * @param resVerOverride the res ver override
+ * @return void
+ * @throws AAIException the AAI exception
+ */
+ public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam,
+ String apiVersion, String resourceVersion, Boolean resVerOverride ) throws AAIException{
+ String nodeType2Del = thisVtx.<String>property("aai-node-type").orElse(null);
+ String deleteScope = scopeParam;
+ if( scopeParam.equals("USE_DEFAULT") ){
+ deleteScope = getDefaultDeleteScope(transId, fromAppId, nodeType2Del, apiVersion);
+ }
+
+ if( !resVerOverride && needToDoResourceVerCheck(apiVersion, false) ){
+ // Need to check that they knew what they were deleting
+ String existingResVer = thisVtx.<String>property("resource-version").orElse(null);
+ if( resourceVersion == null || resourceVersion.equals("") ){
+ throw new AAIException("AAI_6130", "Resource-version not passed for delete of = " + nodeType2Del);
+ }
+ else if( (existingResVer != null) && !resourceVersion.equals(existingResVer) ){
+ throw new AAIException("AAI_6131", "Resource-version MISMATCH for delete of = " + nodeType2Del);
+ }
+ }
+
+ if( !deleteScope.equals("THIS_NODE_ONLY")
+ && !deleteScope.equals("CASCADE_TO_CHILDREN")
+ && !deleteScope.equals("ERROR_4_IN_EDGES_OR_CASCADE")
+ && !deleteScope.equals("ERROR_IF_ANY_EDGES")
+ && !deleteScope.equals("ERROR_IF_ANY_IN_EDGES") ){
+ throw new AAIException("AAI_6120", "Unrecognized value in deleteScope: [" + deleteScope + "].");
+ }
+
+ if( deleteScope.equals("ERROR_IF_ANY_EDGES") ){
+ if ( thisVtx.edges(Direction.BOTH).hasNext() ) {
+ throw new AAIException("AAI_6110", "Node cannot be deleted because it still has Edges and the ERROR_IF_ANY_EDGES scope was used.");
+ }
+ }
+ else if( deleteScope.equals("ERROR_IF_ANY_IN_EDGES") || deleteScope.equals("ERROR_4_IN_EDGES_OR_CASCADE") ){
+ Iterator <Edge> eI = thisVtx.edges(Direction.IN);
+ boolean onlyHasParent = false;
+ Edge temp = null;
+ if( eI != null && eI.hasNext() ){
+ temp = eI.next();
+ Boolean isParent = temp.<Boolean>property("isParent").orElse(null);
+ if (isParent != null && isParent && !eI.hasNext()) {
+ onlyHasParent = true;
+ }
+
+ if (!onlyHasParent) {
+ throw new AAIException("AAI_6110", "Node cannot be deleted because it still has Edges and the " + deleteScope + " scope was used.");
+ }
+ }
+ }
+ else if( deleteScope.equals("THIS_NODE_ONLY")){
+ // Make sure nobody depends on this node.
+ Iterator<Edge> eI = thisVtx.edges(Direction.BOTH);
+ while( eI.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI.next();
+ TitanVertex otherVtx = (TitanVertex) ed.otherVertex(thisVtx);
+ String nodeTypeA = otherVtx.<String>property("aai-node-type").orElse(null);
+ if( nodeTypeACanDependOnB(transId, fromAppId, nodeTypeA, nodeType2Del, apiVersion)){
+ // We're only supposed to delete this node - but another node is dependant on it,
+ // so we shouldn't delete this one.
+ throw new AAIException("AAI_6110", "Node cannot be deleted using scope = " + deleteScope +
+ " another node (type = " + nodeTypeA + ") depends on it for uniqueness.");
+ }
+ }
+ }
+
+ // We've passed our checks - so do some deleting of edges and maybe pass
+ // the delete request down to children or delete-targets.
+
+ // First we deal with the "IN"-Edges which can't have children/delete-targets which
+ // by definition (of "IN") on the other end
+ Iterator <Edge> eI_In = thisVtx.edges(Direction.IN);
+ while( eI_In.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI_In.next();
+
+ //- "touch" vertex on other side of this edge so it gets a fresh resource-version
+ TitanVertex tmpVOther = ed.otherVertex(thisVtx);
+ touchVertex( transId, fromAppId, tmpVOther );
+
+ ed.remove();
+ }
+
+ // Now look at the "OUT"-edges which might include children or delete-targets
+ String cascadeMsg = "This nt = " + nodeType2Del + ", Cascading del to: ";
+ Iterator <Edge> eI_Out = thisVtx.edges(Direction.OUT);
+ if( !eI_Out.hasNext() ){
+ cascadeMsg = cascadeMsg + "[no children for this node]";
+ }
+ while( eI_Out.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI_Out.next();
+
+ // "touch" vertex on other side of this edge so it gets a fresh resource-version
+ TitanVertex tmpVOther = ed.otherVertex(thisVtx);
+ touchVertex( transId, fromAppId, tmpVOther );
+
+ Boolean otherVtxAChild = ed.<Boolean>property("isParent").orElse(null);
+ if( otherVtxAChild == null ){
+ otherVtxAChild = false;
+ }
+
+ Boolean otherVtxADeleteTarget = ed.<Boolean>property("hasDelTarget").orElse(null);
+ if( otherVtxADeleteTarget == null ){
+ otherVtxADeleteTarget = false;
+ }
+
+ if( (otherVtxAChild || otherVtxADeleteTarget) &&
+ (deleteScope.equals("CASCADE_TO_CHILDREN") || deleteScope.equals("ERROR_4_IN_EDGES_OR_CASCADE")) ){
+ // Delete the edge to the child and Pass the delete down to it.
+ ed.remove();
+ TitanVertex otherVtx = (TitanVertex) ed.otherVertex(thisVtx);
+ String vid = otherVtx.id().toString();
+ String nty = otherVtx.<String>property("aai-node-type").orElse(null);
+ String resVers = otherVtx.<String>property("resource-version").orElse(null);
+ cascadeMsg = cascadeMsg + "[" + nty + ":" + vid + "]";
+ removeAaiNode(transId, fromAppId, graph, otherVtx, "CASCADE_TO_CHILDREN", apiVersion, resVers);
+ }
+ else {
+ // The other node is not a child or deleteTarget. Delete the edge to it if it is not
+ // dependent (Should never be dependent since it's not a child/delTarget... but
+ // someone could create a node that was dependent for Uniqueness without
+ // being a child/target.
+
+ // DEBUG -- eventually add the check for dependancy that isn't on a parent-type or delTarget-type edge
+ ed.remove();
+ }
+ }
+
+ LOGGER.info(cascadeMsg);
+
+ Iterator<Edge> eI = thisVtx.edges(Direction.BOTH);
+ if( ! eI.hasNext() ){
+ // By this point, either there were no edges to deal with, or we have dealt with them.
+ thisVtx.remove();
+ }
+ else {
+ // Something went wrong and we couldn't delete all the edges for this guy.
+ throw new AAIException("AAI_6110", "Node could be deleted because it unexpectedly still has Edges.\n");
+ }
+ }
+
+
+ /**
+ * Removes the aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param thisVtx the this vtx
+ * @param scopeParam the scope param
+ * @return void
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam) throws AAIException{
+ removeAaiNode(transId, fromAppId, graph, thisVtx, scopeParam, null, null);
+ }
+
+ /**
+ * Removes the aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param thisVtx the this vtx
+ * @param scopeParam the scope param
+ * @param apiVersion the api version
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam,
+ String apiVersion ) throws AAIException{
+ removeAaiNode(transId, fromAppId, graph, thisVtx, scopeParam, apiVersion, null);
+ }
+ // end of removeAaiNode()
+
+
+ /**
+ * Delete all graph data.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @return void
+ */
+ public static void deleteAllGraphData( String transId, String fromAppId, TitanGraph graph ){
+ /** ======================================================================
+ * WARNING -- this removes ALL the data that is currently in the graph.
+ * ======================================================================
+ **/
+ LOGGER.warn("deleteAllGraphData called! Run for the hills!");
+ Iterator<Edge> edges = graph.edges(Direction.BOTH);
+ graph.tx().commit();
+ Edge edge = null;
+ while (edges.hasNext()) {
+ edge = edges.next();
+ edges.remove();
+ }
+ graph.tx().commit();
+ Iterator<Vertex> vertices = graph.vertices();
+ graph.tx().commit();
+ Vertex vertex = null;
+ while (vertices.hasNext()) {
+ vertex = vertices.next();
+ vertex.remove();
+ }
+ graph.tx().commit();
+ }
+
+
+ /**
+ * Show all edges for node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param tVert the t vert
+ * @return the array list
+ */
+ public static ArrayList <String> showAllEdgesForNode( String transId, String fromAppId, TitanVertex tVert ){
+
+ ArrayList <String> retArr = new ArrayList <String> ();
+ Iterator <Edge> eI = tVert.edges(Direction.IN);
+ if( ! eI.hasNext() ){
+ retArr.add("No IN edges were found for this vertex. ");
+ }
+ while( eI.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI.next();
+ String lab = ed.label();
+ TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert);
+ if( vtx == null ){
+ retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< ");
+ }
+ else {
+ String nType = vtx.<String>property("aai-node-type").orElse(null);
+ String vid = vtx.id().toString();
+ retArr.add("Found an IN edge (" + lab + ") to this vertex from a [" + nType + "] node with VtxId = " + vid );
+ //DEBUG ---
+ //showPropertiesForEdge( transId, fromAppId, ed );
+ }
+ }
+
+ eI = tVert.edges(Direction.OUT);
+ if( ! eI.hasNext() ){
+ retArr.add("No OUT edges were found for this vertex. ");
+ }
+ while( eI.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI.next();
+ String lab = ed.label();
+ TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert);
+ if( vtx == null ){
+ retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< ");
+ }
+ else {
+ String nType = vtx.<String>property("aai-node-type").orElse(null);
+ String vid = vtx.id().toString();
+ retArr.add("Found an OUT edge (" + lab + ") from this vertex to a [" + nType + "] node with VtxId = " + vid );
+ //DEBUG ---
+ //showPropertiesForEdge( transId, fromAppId, ed );
+ }
+ }
+ return retArr;
+ }
+
+
+ /**
+ * Show properties for node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param tVert the t vert
+ * @return the array list
+ */
+ public static ArrayList <String> showPropertiesForNode( String transId, String fromAppId, TitanVertex tVert ){
+
+ ArrayList <String> retArr = new ArrayList <String> ();
+ if( tVert == null ){
+ retArr.add("null Node object passed to showPropertiesForNode()\n");
+ }
+ else {
+ String nodeType = "";
+ //String datType = "";
+ Object ob = tVert.<Object>property("aai-node-type").orElse(null);
+ if( ob == null ){
+ nodeType = "null";
+ }
+ else{
+ nodeType = ob.toString();
+ //datType = ob.getClass().getSimpleName();
+ }
+
+ retArr.add(" AAINodeType/VtxID for this Node = [" + nodeType + "/" + tVert.id() + "]");
+ retArr.add(" Property Detail: ");
+ Iterator<VertexProperty<Object>> pI = tVert.properties();
+ while( pI.hasNext() ){
+ VertexProperty<Object> tp = pI.next();
+ Object val = tp.value();
+ //retArr.add("Prop: [" + tp.getPropertyKey() + "], val = [" + val + "], dataType = " + val.getClass() );
+ retArr.add("Prop: [" + tp.key() + "], val = [" + val + "] ");
+ }
+ }
+ return retArr;
+ }
+
+
+ /**
+ * Gets the node name props.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param apiVersion the api version
+ * @return HashMap of keyProperties
+ * @throws AAIException the AAI exception
+ */
+ public static Collection <String> getNodeNameProps( String transId, String fromAppId, String nodeType, String apiVersion ) throws AAIException{
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ Collection <String> nameProps = new ArrayList <String>();
+ if( dbMaps.NodeNameProps.containsKey(nodeType) ){
+ nameProps = dbMaps.NodeNameProps.get(nodeType);
+ }
+ else if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
+ // The passed-in nodeType was really a nodeCategory, theoretically, all the guys in the same
+ // category should have the same name property -- so if they just give us the category, we will
+ // just give the name info from the first nodeType we encounter of that category.
+ Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType);
+ Iterator <String> catItr = nTypeCatCol.iterator();
+ String catInfo = "";
+ if( catItr.hasNext() ){
+ // For now, we only look for one.
+ catInfo = catItr.next();
+ }
+ else {
+ throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nodeType);
+ }
+
+ String [] flds = catInfo.split(",");
+ if( flds.length != 4 ){
+ throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data (itemCount=" + flds.length + ") for nodeType = [" + nodeType + "].");
+ }
+
+ String nodeTypesString = flds[0];
+ String [] nodeTypeNames = nodeTypesString.split("\\|");
+ if( nodeTypeNames != null && nodeTypeNames.length > 0 ){
+ // We'll just use the first one
+ String nt = nodeTypeNames[0];
+ nameProps = dbMaps.NodeNameProps.get(nt);
+ }
+ }
+
+
+ // Note - it's ok if there was no defined name property for this nodeType.
+
+ return nameProps;
+
+ }// end of getNodeKeyPropNames
+
+
+ /**
+ * Gets the edge tag prop put hash 4 rule.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param edRule the ed rule
+ * @return the edge tag prop put hash 4 rule
+ * @throws AAIException the AAI exception
+ */
+ public static HashMap <String,Object> getEdgeTagPropPutHash4Rule( String transId, String fromAppId, String edRule )
+ throws AAIException{
+ // For a given edgeRule - already pulled out of DbEdgeRules.EdgeRules -- parse out the "tags" that
+ // need to be set for this kind of edge.
+ // These are the Boolean properties like, "isParent", "usesResource" etc.
+ HashMap <String,Object> retEdgePropPutMap = new HashMap <String,Object>();
+
+ if( (edRule == null) || edRule.equals("") ){
+ // No edge rule found for this
+ throw new AAIException("AAI_6120", "blank edRule passed to getEdgeTagPropPutHash4Rule()");
+ }
+
+ int tagCount = DbEdgeRules.EdgeInfoMap.size();
+ String [] rules = edRule.split(",");
+ if( rules.length != tagCount ){
+ throw new AAIException("AAI_6121", "Bad EdgeRule data (itemCount =" + rules.length + ") for rule = [" + edRule + "].");
+ }
+
+ // In DbEdgeRules.EdgeRules -- What we have as "edRule" is a comma-delimited set of strings.
+ // The first item is the edgeLabel.
+ // The second in the list is always "direction" which is always OUT for the way we've implemented it.
+ // Items starting at "firstTagIndex" and up are all assumed to be booleans that map according to
+ // tags as defined in EdgeInfoMap.
+ // Note - if they are tagged as 'reverse', that means they get the tag name with "-REV" on it
+ for( int i = DbEdgeRules.firstTagIndex; i < tagCount; i++ ){
+ String booleanStr = rules[i];
+ Integer mapKey = new Integer(i);
+ String propName = DbEdgeRules.EdgeInfoMap.get(mapKey);
+ String revPropName = propName + "-REV";
+
+ if( booleanStr.equals("true") ){
+ retEdgePropPutMap.put(propName, true);
+ retEdgePropPutMap.put(revPropName,false);
+ }
+ else if( booleanStr.equals("false") ){
+ retEdgePropPutMap.put(propName, false);
+ retEdgePropPutMap.put(revPropName,false);
+ }
+ else if( booleanStr.equals("reverse") ){
+ retEdgePropPutMap.put(propName, false);
+ retEdgePropPutMap.put(revPropName,true);
+ }
+ else {
+ throw new AAIException("AAI_6121", "Bad EdgeRule data for rule = [" + edRule + "], val = [" + booleanStr + "].");
+ }
+
+ }
+
+ return retEdgePropPutMap;
+
+ } // End of getEdgeTagPropPutHash()
+
+
+
+ /**
+ * Gets the edge tag prop put hash.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param edgeRuleKey the edge rule key
+ * @return the edge tag prop put hash
+ * @throws AAIException the AAI exception
+ */
+ public static Map<String, EdgeRule> getEdgeTagPropPutHash( String transId, String fromAppId, String edgeRuleKey )
+ throws AAIException{
+ // For a given edgeRuleKey (nodeTypeA|nodeTypeB), look up the rule that goes with it in
+ // DbEdgeRules.EdgeRules and parse out the "tags" that need to be set on each edge.
+ // These are the Boolean properties like, "isParent", "usesResource" etc.
+ // Note - this code is also used by the updateEdgeTags.java code
+
+ String[] edgeRuleKeys = edgeRuleKey.split("\\|");
+
+ if (edgeRuleKeys.length < 2 || ! EdgeRules.getInstance().hasEdgeRule(edgeRuleKeys[0], edgeRuleKeys[1])) {
+ throw new AAIException("AAI_6120", "Could not find an DbEdgeRule entry for passed edgeRuleKey (nodeTypeA|nodeTypeB): " + edgeRuleKey + ".");
+ }
+
+ Map<String, EdgeRule> edgeRules = EdgeRules.getInstance().getEdgeRules(edgeRuleKeys[0], edgeRuleKeys[1]);
+
+ return edgeRules;
+
+ } // End of getEdgeTagPropPutHash()
+
+
+ /**
+ * This property was put by newer version of code.
+ *
+ * @param apiVersionStr the api version str
+ * @param nodeType the node type
+ * @param propName the prop name
+ * @return true, if successful
+ * @throws AAIException the AAI exception
+ */
+ private static boolean thisPropertyWasPutByNewerVersionOfCode( String apiVersionStr,
+ String nodeType, String propName) throws AAIException{
+ // We want to return True if the nodeType + property-name combo was introduced AFTER the apiVersion passed.
+
+ int apiVerInt = 0;
+ int propIntroVerInt = 0;
+
+ if( apiVersionStr == null || apiVersionStr.equals("") ){
+ apiVersionStr = org.openecomp.aai.util.AAIApiVersion.get();
+ }
+ apiVerInt = getVerNumFromVerString(apiVersionStr);
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+ String propIntroKey = nodeType + "|" + propName;
+ if( propName.equals("prov-status") ){
+ // This is a special case -- The dbMaps from v2 has it in there, but it was introduced half way through. So
+ // it needs to be catogorized as v3.
+ propIntroVerInt = 3;
+ }
+ else if( ! dbMaps.PropertyVersionInfoMap.containsKey(propIntroKey) ){
+ String detail = propIntroKey + " [" + propIntroKey + "] not found in dbMaps.PropertyVersionInfoMap.";
+ throw new AAIException("AAI_6121", detail);
+ }
+ else {
+ String propIntroVerString = dbMaps.PropertyVersionInfoMap.get(propIntroKey);
+ propIntroVerInt = getVerNumFromVerString( propIntroVerString );
+ }
+
+ if( propIntroVerInt > apiVerInt ){
+ return true;
+ }
+ else {
+ return false;
+ }
+
+ } // End of thisPropertyWasPutByNewerVersionOfCode()
+
+
+ /**
+ * Touch vertex.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param v the v
+ * @return void
+ */
+ public static void touchVertex( String transId, String fromAppId, TitanVertex v ){
+ // We want to "touch" the vertex -- Ie. update it's last-mod-date, last-mod- resource-version to the current date/time
+ if( v != null ){
+ long unixTimeNow = System.currentTimeMillis() / 1000L;
+ String timeNowInSec = "" + unixTimeNow;
+ v.property( "aai-last-mod-ts", timeNowInSec );
+ v.property( "resource-version", timeNowInSec );
+ v.property( "last-mod-source-of-truth", fromAppId );
+ }
+ } // End of touchVertex()
+
+
+ /**
+ * Check prop cardinality.
+ *
+ * @param propName the prop name
+ * @param cardinalityType the cardinality type
+ * @return boolean
+ * @throws AAIException the AAI exception
+ */
+ public static boolean checkPropCardinality( String propName, String cardinalityType ) throws AAIException {
+
+ // Return true if the named property is tagged in our dbMaps PropetyDataTypeMap as
+ // having the passed in cardinality type.
+ // NOTE: supported cardinality types in dbMaps = "Set" or "List"
+ // In Titan (and ex5.json), those go in as "SET" and "LIST"
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ if( dbMaps.PropertyDataTypeMap.containsKey(propName) ){
+ String propDataType = dbMaps.PropertyDataTypeMap.get(propName);
+ if( propDataType != null && propDataType.startsWith(cardinalityType) ){
+ return true;
+ }
+ }
+ return false;
+
+ } // End of checkPropCardinality()
+
+ /**
+ * Convert type if needed.
+ *
+ * @param propName the prop name
+ * @param val the val
+ * @return convertedValue (if it was a String but needed to be a Boolean)
+ * @throws AAIException the AAI exception
+ */
+ public static Object convertTypeIfNeeded( String propName, Object val )
+ throws AAIException {
+ // Make sure the dataType of the passed-in Object matches what the DB expects
+
+ // NOTE: since this is a fix very late in our dev cycle, we'll just fix the scenarios that
+ // we're having trouble with which is Strings getting into the db which should be going in as
+ // Booleans or Integers.
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ if( dbMaps.PropertyDataTypeMap.containsKey(propName) ){
+ String dbExpectedDataType = dbMaps.PropertyDataTypeMap.get(propName);
+ if( dbExpectedDataType != null
+ && dbExpectedDataType.equals("Boolean")
+ && val != null
+ && !(val instanceof Boolean) ){
+ String valStr = val.toString().trim();
+ if( valStr.equals("true") || valStr.equals("True") || valStr.equals("TRUE") ){
+ return Boolean.valueOf("true");
+ }
+ else if( valStr.equals("false") || valStr.equals("False") || valStr.equals("FALSE") ){
+ return Boolean.valueOf("false");
+ }
+ else {
+ String emsg = "Error trying to convert value: [" + valStr + "] to a Boolean for property + " + propName + "\n";
+ throw new AAIException("AAI_6120", emsg);
+ }
+ }
+ else if( dbExpectedDataType != null
+ && dbExpectedDataType.equals("Integer")
+ && val != null
+ && !(val.toString().trim().equals(""))
+ && !(val instanceof Integer) ){
+ String valStr = val.toString().trim();
+ Integer newInt;
+ try {
+ newInt = Integer.valueOf(valStr);
+ return newInt;
+ }
+ catch( Exception e ){
+ String emsg = "Error trying to convert value: [" + valStr + "] to an Integer for property + " + propName + "\n";
+ throw new AAIException("AAI_6120", emsg);
+ }
+ }
+ }
+
+ // If it didn't need to be converted, just return it.
+ return val;
+
+ } // End of convertTypeIfNeeded()
+
+
+
+ /**
+ * This vertex not reachable.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param v the v
+ * @param version the version
+ * @return boolean
+ */
+ public static boolean thisVertexNotReachable( String transId, String fromAppId, TitanTransaction graph, TitanVertex v, String version){
+ if( v == null ){
+ return true;
+ }
+ else {
+ try {
+ v.id().toString();
+ }
+ catch( Exception ex ){
+ // Could not get this -- sometimes we're holding a vertex object that has gotten deleted, so
+ // when we try to get stuff from it, we get an "Element Has Been Removed" error from Titan
+ return true;
+ }
+ }
+
+ return false;
+
+ } // End of thisVertexNotReachable()
+
+ /**
+ * This vertex has bad edges.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param v the v
+ * @param version the version
+ * @return boolean
+ */
+ public static boolean thisVertexHasBadEdges( String transId, String fromAppId, TitanTransaction graph, TitanVertex v, String version){
+
+ Iterator <Edge> eItor = v.edges(Direction.BOTH);
+ while( eItor.hasNext() ){
+ Edge e = null;
+ e = eItor.next();
+ if( e == null ){
+ return true;
+ }
+ Vertex vIn = e.inVertex();
+ if( (vIn == null) || (vIn.<String>property("aai-node-type").orElse(null) == null) ){
+ // this is a bad edge because it points to a vertex that isn't there anymore
+ return true;
+ }
+
+ Vertex vOut = e.outVertex();
+ if( (vOut == null) || (vOut.<String>property("aai-node-type").orElse(null) == null) ){
+ // this is a bad edge because it points to a vertex that isn't there anymore
+ return true;
+ }
+ }
+
+ // If we made it to here, the vertex's edges must be ok.
+ return false;
+
+ } // End of thisVertexHasBadEdges()
+
+
+ /**
+ * This vertex is A phantom.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param v the v
+ * @param version the version
+ * @return boolean
+ * @throws AAIException the AAI exception
+ */
+ public static boolean thisVertexIsAPhantom( String transId, String fromAppId, TitanTransaction graph, TitanVertex v, String version )
+ throws AAIException {
+
+
+ // The kind of Phantom we're looking for is the kind that we sometimes get when we do a select without
+ // using key properties. They can be in the database as a vertex, but the indexes that should point to
+ // them are not working -- so they cannot be used by normal interfaces (like the REST API) which means
+ // that if we return it, it can mess up a caller who tries to use it.
+ if( v == null ){
+ return true;
+ }
+ String thisVid = v.id().toString();
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ Object propOb = v.<Object>property("aai-node-type").orElse(null);
+ if( propOb == null ){
+ // This vertex does not have an aai-node-type ---> it is messed up
+ return true;
+ }
+ String nType = propOb.toString();
+ if( ! dbMaps.NodeKeyProps.containsKey(nType) ){
+ // This node Type does not have keys defined
+ // This could just be bad reference data, so we will not flag this guy, but we
+ // can't really do our test...
+ return false;
+ }
+
+ HashMap <String,Object> propHashWithKeys = new HashMap<String, Object>();
+ Collection <String> keyProps = null;
+ try {
+ keyProps = getNodeKeyPropNames(transId, fromAppId, nType, version);
+ }
+ catch (AAIException ex) {
+ // something wrong with getting this guy's key property names - we'll abandon this test...
+ return false;
+ }
+
+ Iterator <String> keyPropI = keyProps.iterator();
+ while( keyPropI.hasNext() ){
+ String propName = keyPropI.next();
+ String propVal = "";
+ Object ob = v.<Object>property(propName).orElse(null);
+ if( ob != null ){
+ propVal = ob.toString();
+ }
+ propHashWithKeys.put(propName, propVal);
+ }
+ try {
+ // Note - We can get more than one back since some nodes need a dep. node for uniqueness.
+ // We don't care about that -- we just want to make sure we can get this vertex back when
+ // we're searching with it's indexed fields.
+ // NOTE - we're passing the skipGroomCheck to getNodes so we don't wind up in an infinite loop
+ ArrayList <TitanVertex> vertList2 = getNodes( transId, fromAppId, graph, nType, propHashWithKeys, false, version, true );
+ Iterator<TitanVertex> iter2 = vertList2.iterator();
+ while( iter2.hasNext() ){
+ TitanVertex tvx2 = iter2.next();
+ String foundId = tvx2.id().toString();
+ if( foundId.equals( thisVid ) ){
+ // We could get back the vertex by looking it up using key properties... That's good.
+ return false;
+ }
+ }
+ }
+ catch (Exception e2) {
+ //String msg = " Error encountered for this vertex id: [" + thisVid +
+ // "]. Caught this exception: " + e2.toString();
+ // Something messed up - but that doesn't prove that this is a phantom.
+ return false;
+ }
+
+ // If we dropped down to here, we have looked but could not pull the vertex out of the
+ // db using it's key fields, so it gets flagged as a Phantom.
+ return true;
+
+ } // End of thisVertexIsAPhantom()
+
+
+ /**
+ * Gets the node by unique key.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param aaiUniquekey the aai uniquekey
+ * @return the node by unique key
+ */
+ public TitanVertex getNodeByUniqueKey(String transId, String fromAppId, TitanTransaction graph, String aaiUniquekey) {
+
+ TitanVertex vert = null;
+
+ Iterator<?> vertI = graph.query().has("aai-unique-key", aaiUniquekey).vertices().iterator();
+
+ if( vertI != null && vertI.hasNext()) {
+ // We found a vertex that meets the input criteria.
+ vert = (TitanVertex) vertI.next();
+ }
+
+ return vert;
+ }
+
+
+
+}
+
diff --git a/aai-core/src/main/java/org/openecomp/aai/dbgen/GenTester.java b/aai-core/src/main/java/org/openecomp/aai/dbgen/GenTester.java
new file mode 100644
index 00000000..43f8f76b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/dbgen/GenTester.java
@@ -0,0 +1,123 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.dbgen;
+
+import com.att.eelf.configuration.Configuration;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.thinkaurelius.titan.core.schema.TitanManagement;
+import org.openecomp.aai.dbmap.AAIGraph;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+
+import java.util.Properties;
+
+
+public class GenTester {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(GenTester.class);
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+
+ TitanGraph graph = null;
+
+ // Set the logging file properties to be used by EELFManager
+ Properties props = System.getProperties();
+ props.setProperty(Configuration.PROPERTY_LOGGING_FILE_NAME, AAIConstants.AAI_CREATE_DB_SCHEMA_LOGBACK_PROPS);
+ props.setProperty(Configuration.PROPERTY_LOGGING_FILE_PATH, AAIConstants.AAI_HOME_ETC_APP_PROPERTIES);
+ boolean addDefaultCR = true;
+
+ try {
+ AAIConfig.init();
+ if (args != null && args.length > 0 ){
+ if( "genDbRulesOnly".equals(args[0]) ){
+ ErrorLogHelper.logError("AAI_3100",
+ " This option is no longer supported. What was in DbRules is now derived from the OXM files. ");
+ return;
+ }
+ else if ( "GEN_DB_WITH_NO_SCHEMA".equals(args[0]) ){
+ // Note this is done to create an empty DB with no Schema so that
+ // an HBase copyTable can be used to set up a copy of the db.
+ LOGGER.info(" ---- NOTE --- about to load a graph without doing any schema processing (takes a little while) -------- ");
+ graph = AAIGraph.getInstance().getGraph();
+
+ if( graph == null ){
+ ErrorLogHelper.logError("AAI_5102", "Error creating Titan graph.");
+ return;
+ }
+ else {
+ LOGGER.auditEvent("Successfully loaded a Titan graph without doing any schema work. ");
+ return;
+ }
+ } else if ("GEN_DB_WITH_NO_DEFAULT_CR".equals(args[0])) {
+ addDefaultCR = false;
+ }
+ else {
+ ErrorLogHelper.logError("AAI_3000", "Unrecognized argument passed to GenTester.java: [" + args[0] + "]. ");
+ LOGGER.error("Unrecognized argument passed to GenTester.java: [" + args[0] + "]. ");
+ LOGGER.error("Either pass no argument for normal processing, or use 'GEN_DB_WITH_NO_SCHEMA'.");
+ return;
+ }
+ }
+
+ //AAIConfig.init();
+ ErrorLogHelper.loadProperties();
+ LOGGER.info(" ---- NOTE --- about to open graph (takes a little while)--------;");
+ graph = AAIGraph.getInstance().getGraph();
+
+ if( graph == null ){
+ ErrorLogHelper.logError("AAI_5102", "Error creating Titan graph. ");
+ return;
+ }
+
+ // Load the propertyKeys, indexes and edge-Labels into the DB
+ TitanManagement graphMgt = graph.openManagement();
+
+ LOGGER.info("-- Loading new schema elements into Titan --");
+ SchemaGenerator.loadSchemaIntoTitan( graph, graphMgt, addDefaultCR );
+
+ } catch(Exception ex) {
+ ErrorLogHelper.logError("AAI_4000", ex.getMessage());
+ }
+
+
+ if( graph != null ){
+ LOGGER.info("-- graph commit");
+ graph.tx().commit();
+
+ LOGGER.info("-- graph shutdown ");
+ graph.close();
+ }
+
+ LOGGER.auditEvent("-- all done, if program does not exit, please kill.");
+ System.exit(0);
+ }
+
+}
+
+
diff --git a/aai-core/src/main/java/org/openecomp/aai/dbgen/PropertyLimitDesc.java b/aai-core/src/main/java/org/openecomp/aai/dbgen/PropertyLimitDesc.java
new file mode 100644
index 00000000..aad519e4
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/dbgen/PropertyLimitDesc.java
@@ -0,0 +1,27 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.dbgen;
+
+public enum PropertyLimitDesc {
+ SHOW_NONE,
+ SHOW_ALL,
+ SHOW_NAME_AND_KEYS_ONLY
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/dbgen/SchemaGenerator.java b/aai-core/src/main/java/org/openecomp/aai/dbgen/SchemaGenerator.java
new file mode 100644
index 00000000..fb8e8977
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/dbgen/SchemaGenerator.java
@@ -0,0 +1,168 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.dbgen;
+
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.collect.Multimap;
+import com.thinkaurelius.titan.core.*;
+import com.thinkaurelius.titan.core.schema.TitanManagement;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.LoaderFactory;
+import org.openecomp.aai.introspection.ModelType;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+import org.openecomp.aai.serialization.db.EdgeRule;
+import org.openecomp.aai.serialization.db.EdgeRules;
+import org.openecomp.aai.util.AAIConfig;
+
+import java.util.*;
+
+
+public class SchemaGenerator {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(SchemaGenerator.class);
+ private static boolean addDefaultCR = true;
+
+
+ /**
+ * Load schema into titan.
+ *
+ * @param graph the graph
+ * @param graphMgmt the graph mgmt
+ * @param addDefaultCloudRegion the add default cloud region
+ */
+ public static void loadSchemaIntoTitan(final TitanGraph graph, final TitanManagement graphMgmt, boolean addDefaultCloudRegion) {
+ addDefaultCR = addDefaultCloudRegion;
+ loadSchemaIntoTitan(graph, graphMgmt);
+ }
+
+ /**
+ * Load schema into titan.
+ *
+ * @param graph the graph
+ * @param graphMgmt the graph mgmt
+ */
+ public static void loadSchemaIntoTitan(final TitanGraph graph, final TitanManagement graphMgmt) {
+
+ try {
+ AAIConfig.init();
+ }
+ catch (Exception ex){
+ LOGGER.error(" ERROR - Could not run AAIConfig.init(). ", ex);
+ System.exit(1);
+ }
+
+ // NOTE - Titan 0.5.3 doesn't keep a list of legal node Labels.
+ // They are only used when a vertex is actually being created. Titan 1.1 will keep track (we think).
+
+
+ // Use EdgeRules to make sure edgeLabels are defined in the db. NOTE: the multiplicty used here is
+ // always "MULTI". This is not the same as our internal "Many2Many", "One2One", "One2Many" or "Many2One"
+ // We use the same edge-label for edges between many different types of nodes and our internal
+ // multiplicty definitions depends on which two types of nodes are being connected.
+
+ Multimap<String, EdgeRule> edges = null;
+ Set<String> labels = new HashSet<>();
+ try {
+ edges = EdgeRules.getInstance().getAllRules();
+ for (EdgeRule rule : edges.values()) {
+ labels.add(rule.getLabel());
+ }
+ } catch (AAIException e) {
+ LOGGER.error("could not get edge rules", e);
+ System.exit(1);
+ }
+ for( String label: labels){
+ if( graphMgmt.containsRelationType(label) ) {
+ LOGGER.debug(" EdgeLabel [" + label + "] already existed. ");
+ } else {
+ LOGGER.debug("Making EdgeLabel: [" + label + "]");
+ graphMgmt.makeEdgeLabel(label).multiplicity(Multiplicity.valueOf("MULTI")).make();
+ }
+ }
+
+ Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, AAIProperties.LATEST);
+ Map<String, Introspector> objs = loader.getAllObjects();
+ Map<String, PropertyKey> seenProps = new HashMap<>();
+
+ for (Introspector obj : objs.values()) {
+ for (String propName : obj.getProperties()) {
+ String dbPropName = propName;
+ Optional<String> alias = obj.getPropertyMetadata(propName, PropertyMetadata.DB_ALIAS);
+ if (alias.isPresent()) {
+ dbPropName = alias.get();
+ }
+ if( graphMgmt.containsRelationType(propName) ){
+ LOGGER.debug(" PropertyKey [" + propName + "] already existed in the DB. ");
+ } else {
+ Class<?> type = obj.getClass(propName);
+ Cardinality cardinality = Cardinality.SINGLE;
+ boolean process = false;
+ if (obj.isListType(propName) && obj.isSimpleGenericType(propName)) {
+ cardinality = Cardinality.SET;
+ type = obj.getGenericTypeClass(propName);
+ process = true;
+ } else if (obj.isSimpleType(propName)) {
+ process = true;
+ }
+
+ if (process) {
+
+ LOGGER.info("Creating PropertyKey: [" + dbPropName + "], ["+ type.getSimpleName() + "], [" + cardinality + "]");
+ PropertyKey propK;
+ if (!seenProps.containsKey(dbPropName)) {
+ propK = graphMgmt.makePropertyKey(dbPropName).dataType(type).cardinality(cardinality).make();
+ seenProps.put(dbPropName, propK);
+ } else {
+ propK = seenProps.get(dbPropName);
+ }
+ if (graphMgmt.containsGraphIndex(dbPropName)) {
+ LOGGER.debug(" Index [" + dbPropName + "] already existed in the DB. ");
+ } else {
+ if( obj.getIndexedProperties().contains(propName) ){
+ if( obj.getUniqueProperties().contains(propName) ){
+ LOGGER.info("Add Unique index for PropertyKey: [" + dbPropName + "]");
+ graphMgmt.buildIndex(dbPropName,Vertex.class).addKey(propK).unique().buildCompositeIndex();
+ } else {
+ LOGGER.info("Add index for PropertyKey: [" + dbPropName + "]");
+ graphMgmt.buildIndex(dbPropName,Vertex.class).addKey(propK).buildCompositeIndex();
+ }
+ } else {
+ LOGGER.info("No index added for PropertyKey: [" + dbPropName + "]");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ LOGGER.info("-- About to call graphMgmt commit");
+ graphMgmt.commit();
+ }// End of loadSchemaIntoTitan()
+
+}
+
+
diff --git a/aai-core/src/main/java/org/openecomp/aai/dbgraphgen/DbSearchWithTags.java b/aai-core/src/main/java/org/openecomp/aai/dbgraphgen/DbSearchWithTags.java
new file mode 100644
index 00000000..cceb950b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/dbgraphgen/DbSearchWithTags.java
@@ -0,0 +1,366 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.dbgraphgen;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+import org.openecomp.aai.util.AAIConfig;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+
+
+/**
+ * Database-level Search-Utility class that uses edge-tags to help it navigate the graph.
+ */
+public class DbSearchWithTags{
+
+ private EELFLogger LOGGER = EELFManager.getInstance().getLogger(DbSearchWithTags.class);
+
+ private TransactionalGraphEngine engine;
+
+ protected DbSearchWithTags() {
+
+ }
+ public DbSearchWithTags(Loader loader, TransactionalGraphEngine engine, DBSerializer serializer) {
+ this.engine = engine;
+ }
+
+ /**
+ * Run edge tag query.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param edgeTag the edge tag
+ * @param searchRootType - root collection point when doing the search
+ * @param displayRootType - if they want more data than would be included using the searchRootType, this
+ * lets them specify it.
+ * @param searchDirectionStr the search direction str
+ * @param initialFilterHash the initial filter hash
+ * @param secondaryFilterHash the secondary filter hash
+ * @param pruneLevel either "none", "searchLevel" or "displayLevel".
+ * @param retNodeType could be either "all" for the full map, or a single nodeType
+ * @param trimList list of nodes to "stop" at when collecting data
+ * @return List<resultSet>
+ * @throws AAIException the AAI exception
+ */
+ public Tree<Vertex> runEdgeTagQuery( String transId, String fromAppId,
+ String edgeTag,
+ String searchRootType,
+ Map<String,Object> initialFilterHash,
+ Map<String,Object> secondaryFilterHash)
+ throws AAIException{
+
+ final String tag = edgeTag;
+ final String reverseTag = edgeTag + "-REV";
+ //max levels is not used at this time, but may be used again
+ int maxLevels = 50; // default value
+ String maxString = AAIConfig.get("aai.edgeTag.proc.max.levels");
+ if( maxString != null && !maxString.equals("") ){
+ try {
+ int maxVal = Integer.parseInt(maxString);
+ maxLevels = maxVal;
+ }
+ catch ( Exception nfe ){
+ // Don't worry, we will leave "maxLevels" set to the default value it was initialized with
+ }
+ }
+
+ // First, we need to use the intialFilter plus the edgeTag to identify a set of search-root-nodes
+ HashMap <String, Vertex> searchRootHash = identifyTopNodeSet( transId, fromAppId,
+ edgeTag, searchRootType, initialFilterHash, maxLevels );
+
+
+ Set<String> keySet = searchRootHash.keySet();
+ Iterator<String> itr = keySet.iterator();
+ String[] arrayOfVertices = new String[keySet.size()];
+ int i = 0;
+ while (itr.hasNext()) {
+ arrayOfVertices[i] = itr.next();
+ i++;
+ }
+ //start from all vertices provided
+ //repeat checking the out edge for the tag and the in edge for reverse tag
+ //emit all vertices not already seen and start again
+ //return a tree structure of the vertices and edges touched by this traversal
+ Tree<Element> resultTree = this.engine.asAdmin().getReadOnlyTraversalSource().V(arrayOfVertices)
+ .emit().repeat(__.union(__.outE().has(tag, true), __.inE().has(reverseTag, true)).otherV()).tree().next();
+
+ //the resulting tree includes the edges because of our query, we'll need to remove them
+ Tree<Vertex> sanitizedTree = removeUnwantedItems(resultTree);
+
+ //if we have secondary filters then check each tree returned for matches
+ if (!secondaryFilterHash.isEmpty()) {
+ filterOutResultTrees(sanitizedTree, secondaryFilterHash);
+ }
+ return sanitizedTree;
+
+ }// End of runEdgeTagQuery()
+
+ /**
+ * Identify top node set.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param edgeTag the edge tag
+ * @param topNodeType the top node type
+ * @param initialFilterHash the initial filter hash
+ * @param maxLevels the max levels
+ * @return List<titanVertex>
+ * @throws AAIException the AAI exception
+ */
+ public HashMap<String, Vertex> identifyTopNodeSet( String transId, String fromAppId,
+ String edgeTag, String topNodeType, Map<String,Object> initialFilterHash, int maxLevels )
+ throws AAIException {
+
+ final String tag = edgeTag;
+ final String reverseTag = edgeTag + "-REV";
+ HashMap <String, Vertex> topVertHash = new HashMap <>();
+
+ // Given the filter, we want to select all the nodes of the type the filter tells us that have the
+ // property they gave us.
+ // Then looping through those start points, we will look "up" and then "down" to find the set of target/top nodes.
+
+ if( initialFilterHash == null || initialFilterHash.isEmpty() ){
+ throw new AAIException("AAI_6118", " initialFilterHash is required for identifyInitialNodeSet() call. \n");
+ }
+
+ // NOTE: we're expecting the filter to have a format like this: "nodeType.parameterName:parameterValue"
+ Iterator <?> it = initialFilterHash.entrySet().iterator();
+ // -- DEBUG -- for now we only deal with ONE initial filter parameter
+ // it would be easy enough to deal with multiple parameters if they all
+ // applied to the same nodeType.
+ String propNodeTypeDotName = "";
+ String initNodeType = "";
+ String initPropName = "";
+
+ String extraChecks = "";
+
+ String propVal = "";
+ if( it.hasNext() ){
+ Map.Entry<?,?> propEntry = (Map.Entry<?,?>) it.next();
+ propNodeTypeDotName = (propEntry.getKey()).toString();
+ propVal = (propEntry.getValue()).toString();
+ }
+
+ GraphTraversalSource source = this.engine.asAdmin().getReadOnlyTraversalSource();
+ GraphTraversal<Vertex, Vertex> g;
+
+ int periodLoc = propNodeTypeDotName.indexOf(".");
+ if( periodLoc <= 0 ){
+ throw new AAIException("AAI_6120", "Bad filter param key passed in: [" + propNodeTypeDotName + "]. Expected format = [nodeName.paramName]\n");
+ }
+ else {
+ initNodeType = propNodeTypeDotName.substring(0,periodLoc);
+ initPropName = propNodeTypeDotName.substring(periodLoc + 1);
+
+ //there used to be logic here that would do something special for generic-vnf.vnf-name and vserver.vserver-name
+ //it would attempt a search as they sent it, if nothing came back, try as all upper, try as all lower, then fail
+ //here it checks whether something comes back or not, if not change the case and try again
+ if( (initNodeType.equals("generic-vnf") && initPropName.equals("vnf-name"))
+ || (initNodeType.equals("vserver") && initPropName.equals("vserver-name")) ){
+ if (!this.checkKludgeCase(initNodeType, initPropName, propVal)) {
+ if (this.checkKludgeCase(initNodeType, initPropName, propVal.toUpperCase())) {
+ propVal = propVal.toUpperCase();
+ } else {
+ if (this.checkKludgeCase(initNodeType, initPropName, propVal)) {
+ propVal = propVal.toLowerCase();
+ }
+ }
+ }
+ }
+ g = source.V().has(AAIProperties.NODE_TYPE, initNodeType).has(initPropName, propVal);
+
+ //search all around bounded by our edge tag for start nodes that match our topNodeType
+ if (!topNodeType.equals(initNodeType)) {
+
+ g.union(__.<Vertex>start().until(__.has(AAIProperties.NODE_TYPE, topNodeType))
+ .repeat(__.union(__.inE().has(reverseTag, true), __.outE().has(tag, true)).otherV()),
+ __.<Vertex>start().until(__.has(AAIProperties.NODE_TYPE, topNodeType))
+ .repeat(__.union(__.inE().has(tag, true), __.outE().has(reverseTag, true)).otherV())).dedup();
+ }
+
+ List<Vertex> results = g.toList();
+
+ results.forEach(v -> {
+ topVertHash.put(v.id().toString(), v);
+ });
+ }
+ if( topVertHash.isEmpty() ){
+ // No Vertex was found - throw a not-found exception
+ throw new AAIException("AAI_6114", "No Node of type " + topNodeType + " found for properties: " + initialFilterHash.toString() + extraChecks);
+ }
+ else {
+ return topVertHash;
+ }
+
+ }// End identifyInitialNodeSet()
+
+ /**
+ * This is a carryover from the previous version.
+ * We may be able to remove this.
+ *
+ * @param nodeType
+ * @param propName
+ * @param propValue
+ * @return
+ */
+ private boolean checkKludgeCase(String nodeType, String propName, String propValue) {
+ return this.engine.getQueryBuilder().getVerticesByIndexedProperty(AAIProperties.NODE_TYPE, nodeType).getVerticesByProperty(propName, propValue).hasNext();
+ }
+
+ /**
+ * This method starts from the top of the tree object and checks each nested tree.
+ * If that tree does not contain a node (or nodes) that match the filterHash, remove it
+ *
+ * @param tree
+ * @param filterHash
+ * @throws AAIException
+ */
+ private void filterOutResultTrees(Tree<Vertex> tree, Map<String,Object> filterHash) throws AAIException {
+ Set<Vertex> topLevelKeys = new LinkedHashSet<>(tree.keySet());
+ for (Vertex topLevel : topLevelKeys) {
+ if (!this.checkVertexWithFilters(topLevel, filterHash)) {
+ if (!filterOutResultTreesHelper(tree.get(topLevel), filterHash)) {
+ //if we never found anything to satisfy our filter, remove the entire result tree
+ tree.remove(topLevel);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks all vertices of a tree with the provided filterHash
+ *
+ * @param tree
+ * @param filterHash
+ * @return
+ * @throws AAIException
+ */
+ private boolean filterOutResultTreesHelper(Tree<Vertex> tree, Map<String,Object> filterHash) throws AAIException {
+
+ Set<Vertex> keys = tree.keySet();
+
+ for (Vertex v : keys) {
+ if (checkVertexWithFilters(v, filterHash)) {
+ return true;
+ } else {
+ if (filterOutResultTreesHelper(tree.get(v), filterHash)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+ /**
+ * Checks whether a vertex matches the filterHash provided
+ *
+ * @param v
+ * @param filterHash
+ * @return
+ * @throws AAIException
+ */
+ private boolean checkVertexWithFilters(Vertex v, Map<String,Object> filterHash) throws AAIException {
+ Iterator <?> it = filterHash.entrySet().iterator();
+
+ while( it.hasNext() ){
+ Map.Entry<?,?> filtEntry = (Map.Entry<?,?>) it.next();
+ String propNodeTypeDotName = (filtEntry.getKey()).toString();
+ String value = (filtEntry.getValue()).toString();
+
+ int periodLoc = propNodeTypeDotName.indexOf(".");
+ if( periodLoc <= 0 ){
+ throw new AAIException("AAI_6120", "Bad filter param key passed in: [" + propNodeTypeDotName + "]. Expected format = [nodeName.paramName]\n");
+ }
+ else {
+ String nodeType = propNodeTypeDotName.substring(0,periodLoc);
+ String propertyName = propNodeTypeDotName.substring(periodLoc + 1);
+ String nt = v.<String>property("aai-node-type").orElse(null);
+ if( nt.equals( nodeType ) ){
+ if( propertyName.equals("vertex-id") ){
+ // vertex-id can't be gotten the same way as other properties
+ String thisVtxId = v.id().toString();
+ if( thisVtxId.equals(value) ){
+ return true;
+ }
+ }
+ else {
+ Object thisValObj = v.property(propertyName).orElse(null);
+ if( thisValObj != null ){
+ String thisVal = thisValObj.toString();
+ if( thisVal.equals(value) ){
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Removes every other tree from the originalTree provided.
+ * It is designed to specifically handle removing unwanted edges from the originalTree
+ * @param originalTree
+ * @return
+ */
+ private Tree<Vertex> removeUnwantedItems(Tree<Element> originalTree) {
+
+ Tree<Vertex> newTree = new Tree<>();
+ Set<Element> keys = originalTree.keySet();
+ for (Element element : keys) {
+ newTree.put((Vertex)element, removeUnwantedItemsHelper(originalTree.get(element).getTreesAtDepth(2)));
+ }
+
+ return newTree;
+
+
+ }
+
+ private Tree<Vertex> removeUnwantedItemsHelper(List<Tree<Element>> originalTrees) {
+ Tree<Vertex> newTree = new Tree<>();
+ for (Tree<Element> tree : originalTrees) {
+ newTree.addTree(removeUnwantedItems(tree));
+ }
+
+ return newTree;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/dbmap/AAIGraph.java b/aai-core/src/main/java/org/openecomp/aai/dbmap/AAIGraph.java
new file mode 100644
index 00000000..b4be1a37
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/dbmap/AAIGraph.java
@@ -0,0 +1,187 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.dbmap;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.tinkerpop.gremlin.structure.io.IoCore;
+
+import org.openecomp.aai.dbgen.SchemaGenerator;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.util.AAIConstants;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.thinkaurelius.titan.core.TitanFactory;
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.thinkaurelius.titan.core.TitanTransaction;
+import com.thinkaurelius.titan.core.schema.TitanManagement;
+
+/**
+ * Database Mapping class which acts as the middle man between the REST
+ * interface objects and Titan DB objects. This class provides methods to commit
+ * the objects received on the REST interface into the Titan graph database as
+ * vertices and edges. Transactions are also managed here by using a TitanGraph
+ * object to load, commit/rollback and shutdown for each request. The data model
+ * rules such as keys/required properties are handled by calling DBMeth methods
+ * which are driven by a specification file in json.
+ *
+
+ */
+public class AAIGraph {
+
+ protected Map<String, TitanGraph> graphs = new HashMap<>();
+ protected static final String COMPONENT = "aaidbmap";
+ private final String REALTIME_DB = "realtime";
+ private final String CACHED_DB = "cached";
+ private final EELFLogger logger = EELFManager.getInstance().getLogger(this.getClass().getSimpleName());
+
+
+ /**
+ * Instantiates a new AAI graph.
+ */
+ private AAIGraph() {
+ try {
+ String rtConfig = System.getProperty("realtime.db.config");
+ String cachedConfig = System.getProperty("cached.db.config");
+ if (rtConfig == null) {
+ rtConfig = AAIConstants.REALTIME_DB_CONFIG;
+ }
+ if (cachedConfig == null) {
+ cachedConfig = AAIConstants.CACHED_DB_CONFIG;
+ }
+ this.loadGraph(REALTIME_DB, rtConfig);
+ this.loadGraph(CACHED_DB, cachedConfig);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to instantiate graphs", e);
+ }
+ }
+
+ private static class Helper {
+ private static final AAIGraph INSTANCE = new AAIGraph();
+ }
+
+ /**
+ * Gets the single instance of AAIGraph.
+ *
+ * @return single instance of AAIGraph
+ */
+ public static AAIGraph getInstance() {
+ return Helper.INSTANCE;
+ }
+
+ private void loadGraph(String name, String configPath) throws AAIException {
+ try {
+ final TitanGraph graph = TitanFactory.open(configPath);
+ InputStream is = new FileInputStream(configPath);
+ Properties graphProps = new Properties();
+ graphProps.load(is);
+
+ if (graphProps.get("storage.backend").equals("inmemory")) {
+ // Load the propertyKeys, indexes and edge-Labels into the DB
+ loadSchema(graph);
+ if (graphProps.containsKey("load.snapshot.file")) {
+ String value = graphProps.getProperty("load.snapshot.file");
+ if ("true".equals(value)) {
+ try {
+ String location = System.getProperty("snapshot.location");
+ logAndPrint(logger, "Loading snapshot to inmemory graph.");
+ TitanTransaction transaction = graph.newTransaction();
+ transaction.io(IoCore.graphson()).readGraph(location);
+ transaction.commit();
+ logAndPrint(logger, "Snapshot loaded to inmemory graph.");
+ } catch (IOException e) {
+ graph.close();
+ logAndPrint(logger, "ERROR: Could not load datasnapshot to in memory graph. \n" + ExceptionUtils.getFullStackTrace(e));
+ System.exit(0);
+ }
+ }
+ }
+ }
+
+ if (graph == null) {
+ throw new AAIException("AAI_5102");
+ }
+
+ graphs.put(name, graph);
+ } catch (FileNotFoundException fnfe) {
+ throw new AAIException("AAI_4001");
+ } catch (IOException e) {
+ throw new AAIException("AAI_4002");
+
+ }
+ }
+
+ private void loadSchema(TitanGraph graph) {
+ // Load the propertyKeys, indexes and edge-Labels into the DB
+ TitanManagement graphMgt = graph.openManagement();
+
+ System.out.println("-- loading schema into Titan");
+ SchemaGenerator.loadSchemaIntoTitan( graph, graphMgt );
+ }
+
+ /**
+ * Graph shutdown.
+ */
+ public void graphShutdown() {
+ graphs.get(REALTIME_DB).close();
+ }
+
+ /**
+ * Gets the graph.
+ *
+ * @return the graph
+ */
+ public TitanGraph getGraph() {
+ return graphs.get(REALTIME_DB);
+ }
+
+ public void graphShutdown(DBConnectionType connectionType) {
+
+ graphs.get(this.getGraphName(connectionType)).close();
+ }
+
+ public TitanGraph getGraph(DBConnectionType connectionType) {
+ return graphs.get(this.getGraphName(connectionType));
+ }
+
+ private String getGraphName(DBConnectionType connectionType) {
+ String graphName = "";
+ if (DBConnectionType.CACHED.equals(connectionType)) {
+ graphName = this.CACHED_DB;
+ } else if (DBConnectionType.REALTIME.equals(connectionType)) {
+ graphName = this.REALTIME_DB;
+ }
+
+ return graphName;
+ }
+
+ private void logAndPrint(EELFLogger logger, String msg) {
+ System.out.println(msg);
+ logger.info(msg);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/dbmap/DBConnectionType.java b/aai-core/src/main/java/org/openecomp/aai/dbmap/DBConnectionType.java
new file mode 100644
index 00000000..a2c01e21
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/dbmap/DBConnectionType.java
@@ -0,0 +1,26 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.dbmap;
+
+public enum DBConnectionType {
+ REALTIME,
+ CACHED
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/dbmodel/DbEdgeRules.java b/aai-core/src/main/java/org/openecomp/aai/dbmodel/DbEdgeRules.java
new file mode 100644
index 00000000..9a56fc69
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/dbmodel/DbEdgeRules.java
@@ -0,0 +1,472 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.dbmodel;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Multimap;
+
+public class DbEdgeRules {
+
+ /*
+ * The EdgeRules data is set up as a key (fromNodeTypeA|toNodeTypeB) mapped
+ * to a string which holds the info we need to build an edge from nodeTypeA
+ * to nodeTypeB. Note -- the MultiMap will let us define more than one type
+ * of edge between a given pair of nodeTypes, but for now we never define
+ * more than one.
+ *
+ * The edgeInfo part is comma separated and looks like this:
+ * "edgeLabel,direction,multiplicityRule,isParent,usesResource,hasDelTarget,SVC-INFRA" This
+ * format is encoded into the EdgeInfoMap below.
+ * MultiplicityRule can be either "Many2Many", "Many2One", "One2Many" or "One2One"
+ * The values for the things after multiplicityRule can be either "true", "false" or "reverse". "reverse" is
+ * really saying that this tag does apply, but the edge will be traversed
+ * the opposite way from the same tag that just has "true".
+ */
+ public static final Map<Integer, String> EdgeInfoMap;
+ static {
+ EdgeInfoMap = new HashMap<Integer, String>();
+ EdgeInfoMap.put(0, "edgeLabel");
+ EdgeInfoMap.put(1, "direction");
+ EdgeInfoMap.put(2, "multiplicityRule");
+ EdgeInfoMap.put(3, "isParent");
+ EdgeInfoMap.put(4, "usesResource");
+ EdgeInfoMap.put(5, "hasDelTarget");
+ EdgeInfoMap.put(6, "SVC-INFRA");
+ }
+
+ public static Integer firstTagIndex = 3;
+
+ public static final Multimap<String, String> EdgeRules = new ImmutableSetMultimap.Builder<String, String>()
+ .putAll("availability-zone|complex",
+ "groupsResourcesIn,OUT,Many2Many,false,false,false,false")
+ .putAll("availability-zone|service-capability",
+ "supportsServiceCapability,OUT,Many2Many,false,false,false,false")
+ .putAll("cloud-region|complex",
+ "locatedIn,OUT,Many2One,false,false,false,false")
+ .putAll("cloud-region|l3-network",
+ "uses,OUT,Many2Many,false,false,false,false")
+ .putAll("cloud-region|tenant",
+ "has,OUT,One2Many,true,false,false,reverse")
+ .putAll("cloud-region|image",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|flavor",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|availability-zone",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|oam-network",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|dvs-switch",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|volume-group",
+ "has,OUT,One2Many,true,true,false,false")
+ .putAll("cloud-region|group-assignment",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|snapshot",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|zone",
+ "isMemberOf,OUT,Many2One,false,false,false,false")
+ .putAll("complex|ctag-pool",
+ "hasCtagPool,OUT,Many2Many,true,false,false,false")
+ .putAll("complex|l3-network",
+ "usesL3Network,OUT,Many2Many,false,false,false,true")
+ .putAll("ctag-pool|availability-zone",
+ "supportsAvailabilityZone,OUT,Many2Many,false,false,false,false")
+ .putAll("customer|service-subscription",
+ "subscribesTo,OUT,Many2Many,true,false,false,reverse")
+ .putAll("dvs-switch|availability-zone",
+ "existsIn,OUT,Many2Many,false,false,false,false")
+ .putAll("generic-vnf|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("generic-vnf|availability-zone",
+ "hasAvailabilityZone,OUT,Many2Many,false,false,false,true")
+ .putAll("generic-vnf|lag-interface",
+ "hasLAGInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("generic-vnf|l3-network",
+ "usesL3Network,OUT,Many2Many,false,true,false,true")
+ .putAll("generic-vnf|pserver",
+ "runsOnPserver,OUT,Many2Many,false,true,false,true")
+ .putAll("generic-vnf|vnf-image",
+ "usesVnfImage,OUT,Many2One,false,false,false,true")
+ .putAll("generic-vnf|vserver",
+ "runsOnVserver,OUT,One2Many,false,true,false,true")
+ .putAll("generic-vnf|service-instance",
+ "hasInstance,OUT,Many2Many,false,true,false,true")
+ .putAll("generic-vnf|site-pair-set",
+ "hasSitePairSet,OUT,Many2Many,false,false,false,false")
+ .putAll("generic-vnf|network-profile",
+ "hasNetworkProfile,OUT,Many2Many,false,false,false,false")
+ .putAll("group-assignment|tenant",
+ "has,OUT,Many2Many,false,false,false,false")
+ .putAll("group-assignment|pserver",
+ "has,OUT,One2Many,false,false,false,false")
+ .putAll("image|metadata", "hasMetaData,OUT,Many2Many,true,false,false,false")
+ .putAll("image|metadatum",
+ "hasMetaDatum,OUT,Many2Many,true,false,false,false")
+ .putAll("l-interface|instance-group",
+ "isMemberOf,OUT,Many2Many,false,false,false,false")
+ .putAll("l-interface|l3-interface-ipv4-address-list",
+ "hasIpAddress,OUT,Many2Many,true,false,false,true")
+ .putAll("l-interface|l3-interface-ipv6-address-list",
+ "hasIpAddress,OUT,Many2Many,true,false,false,true")
+ .putAll("l-interface|l-interface",
+ "has,OUT,One2Many,true,false,false,true")
+ .putAll("l-interface|logical-link",
+ "usesLogicalLink,OUT,Many2Many,false,false,true,true")
+ .putAll("lag-interface|logical-link",
+ "uses,OUT,Many2Many,false,false,true,true")
+ .putAll("l-interface|vlan","hasVlan,OUT,Many2Many,true,false,false,false")
+ .putAll("l-interface|sriov-vf","has,OUT,One2One,true,false,false,false")
+ .putAll("l3-interface-ipv4-address-list|instance-group",
+ "isMemberOf,OUT,Many2Many,false,false,false,false")
+ .putAll("l3-interface-ipv6-address-list|instance-group",
+ "isMemberOf,OUT,Many2Many,false,false,false,false")
+ .putAll("l3-interface-ipv4-address-list|l3-network",
+ "isMemberOf,OUT,Many2Many,false,false,false,true")
+ .putAll("l3-interface-ipv6-address-list|l3-network",
+ "isMemberOf,OUT,Many2Many,false,false,false,true")
+ .putAll("l3-interface-ipv4-address-list|subnet",
+ "isMemberOf,OUT,Many2Many,false,false,false,true")
+ .putAll("l3-interface-ipv6-address-list|subnet",
+ "isMemberOf,OUT,Many2Many,false,false,false,true")
+ .putAll("l3-network|vpn-binding",
+ "usesVpnBinding,OUT,Many2Many,false,false,false,false")
+ .putAll("l3-network|subnet",
+ "hasSubnet,OUT,Many2Many,true,false,false,reverse")
+ .putAll("l3-network|service-instance",
+ "hasInstance,OUT,Many2Many,false,false,false,reverse")
+ .putAll("l3-network|ctag-assignment",
+ "hasCtagAssignment,OUT,Many2Many,true,false,false,true")
+ .putAll("l3-network|network-policy",
+ "uses,OUT,Many2Many,false,false,false,true")
+ .putAll("l3-network|segmentation-assignment",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("l3-network|route-table-reference",
+ "uses,OUT,Many2Many,false,false,false,false")
+ .putAll("lag-interface|lag-link",
+ "usesLAGLink,OUT,Many2Many,false,true,true,true")
+ .putAll("lag-interface|p-interface",
+ "usesPInterface,OUT,Many2Many,false,true,false,true")
+ .putAll("lag-interface|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("logical-link|lag-link",
+ "usesLAGLink,OUT,Many2Many,false,true,false,true")
+ .putAll("logical-link|pnf",
+ "bridgedTo,OUT,Many2Many,false,false,false,false")
+ .putAll("logical-link|logical-link",
+ "uses,OUT,One2Many,false,false,false,true")
+ .putAll("model|model-ver",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("model-ver|model-element",
+ "startsWith,OUT,One2Many,true,false,false,false")
+ .putAll("model-element|model-ver",
+ "isA,OUT,Many2One,false,false,false,false")
+ .putAll("model-ver|metadatum",
+ "hasMetaData,OUT,One2Many,true,false,false,false")
+ .putAll("model-element|model-element",
+ "connectsTo,OUT,One2Many,true,false,false,false")
+ .putAll("model-element|model-constraint",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("model-element|constrained-element-set",
+ "connectsTo,OUT,One2Many,true,false,false,false")
+ .putAll("model-constraint|constrained-element-set",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("constrained-element-set|element-choice-set",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("element-choice-set|model-element",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("named-query|model",
+ "relatedTo,OUT,One2Many,false,false,false,false")
+ .putAll("named-query|named-query-element",
+ "startsWith,OUT,One2One,true,false,false,false")
+ .putAll("named-query-element|named-query-element",
+ "connectsTo,OUT,Many2Many,true,false,false,false")
+ .putAll("named-query-element|model",
+ "isA,OUT,Many2One,false,false,false,false")
+ .putAll("named-query-element|property-constraint",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("named-query-element|related-lookup",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("instance-group|model",
+ "targets,OUT,Many2Many,false,false,false,false")
+ .putAll("newvce|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,false")
+ .putAll("oam-network|complex",
+ "definedFor,OUT,Many2Many,false,false,false,false")
+ .putAll("oam-network|service-capability",
+ "supportsServiceCapability,OUT,Many2Many,false,false,false,false")
+ .putAll("p-interface|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("p-interface|physical-link",
+ "usesPhysicalLink,OUT,Many2Many,false,false,true,false")
+ .putAll("p-interface|logical-link",
+ "usesLogicalLink,OUT,Many2One,false,false,false,true")
+ .putAll("port-group|cvlan-tag", "hasCTag,OUT,Many2Many,true,true,false,true")
+ .putAll("pserver|complex", "locatedIn,OUT,Many2One,false,false,false,true")
+ .putAll("pserver|cloud-region","locatedIn,OUT,Many2One,false,false,false,true")
+ .putAll("pserver|availability-zone","existsIn,OUT,Many2One,false,false,false,true")
+ .putAll("pserver|lag-interface",
+ "hasLAGInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("pserver|p-interface",
+ "hasPinterface,OUT,Many2Many,true,true,false,true")
+ .putAll("pserver|zone",
+ "isMemberOf,OUT,Many2One,false,false,false,false")
+ .putAll("pnf|p-interface",
+ "hasPinterface,OUT,Many2Many,true,true,false,true")
+ .putAll("pnf|lag-interface",
+ "has,OUT,One2Many,true,false,false,true")
+ .putAll("pnf|complex",
+ "locatedIn,OUT,Many2One,false,false,false,false")
+ .putAll("pnf|instance-group",
+ "isMemberOf,OUT,Many2Many,false,false,false,false")
+ .putAll("pnf|zone",
+ "isMemberOf,OUT,Many2One,false,false,false,false")
+ .putAll("service-instance|cvlan-tag",
+ "hasIPAGFacingVLAN,OUT,Many2Many,false,true,false,false")
+ .putAll("service-instance|pnf",
+ "uses,OUT,One2Many,false,true,false,false")
+ .putAll("service-subscription|service-instance",
+ "hasInstance,OUT,Many2Many,true,false,false,reverse")
+ .putAll("site-pair-set|routing-instance",
+ "hasRoutingInstance,OUT,Many2Many,true,false,false,false")
+ .putAll("routing-instance|site-pair",
+ "hasSitePair,OUT,Many2Many,true,false,false,false")
+ .putAll("site-pair|class-of-service",
+ "hasClassOfService,OUT,Many2Many,true,false,false,false")
+ .putAll("tenant|l3-network",
+ "usesL3Network,OUT,Many2Many,false,false,false,false")
+ .putAll("tenant|service-subscription",
+ "relatedTo,OUT,Many2Many,false,false,false,false")
+ .putAll("tenant|vserver", "owns,OUT,One2Many,true,false,false,reverse")
+ .putAll("vce|availability-zone",
+ "hasAvailabilityZone,OUT,Many2Many,false,false,false,false")
+ .putAll("vce|complex", "locatedIn,OUT,Many2Many,false,false,false,true")
+ .putAll("vce|port-group", "hasPortGroup,OUT,Many2Many,true,true,false,true")
+ .putAll("vce|vserver", "runsOnVserver,OUT,Many2Many,false,true,false,true")
+ .putAll("vce|service-instance",
+ "hasServiceInstance,OUT,Many2Many,false,false,false,reverse")
+ .putAll("virtual-data-center|generic-vnf",
+ "hasVNF,OUT,Many2Many,false,false,false,reverse")
+ .putAll("vlan|l3-interface-ipv4-address-list",
+ "hasIpAddress,OUT,Many2Many,true,false,false,true")
+ .putAll("vlan|l3-interface-ipv6-address-list",
+ "hasIpAddress,OUT,Many2Many,true,false,false,true")
+ .putAll("vpe|complex", "locatedIn,OUT,Many2Many,false,false,false,false")
+ .putAll("vpe|ctag-pool", "usesCtagPool,OUT,Many2Many,false,false,false,false")
+ .putAll("vpe|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,false")
+ .putAll("vpe|lag-interface",
+ "hasLAGInterface,OUT,Many2Many,true,false,false,false")
+ .putAll("vpe|vserver", "runsOnVserver,OUT,Many2Many,false,true,false,false")
+ .putAll("vpls-pe|complex", "locatedIn,OUT,Many2Many,false,false,false,false")
+ .putAll("vpls-pe|ctag-pool",
+ "usesCtagPool,OUT,Many2Many,false,false,false,false")
+ .putAll("vpls-pe|p-interface",
+ "hasPinterface,OUT,Many2Many,true,false,false,false")
+ .putAll("vpls-pe|lag-interface",
+ "hasLAGinterface,OUT,Many2Many,true,false,false,false")
+ .putAll("vserver|flavor", "hasFlavor,OUT,Many2One,false,false,false,true")
+ .putAll("vserver|image", "hasImage,OUT,Many2One,false,false,false,true")
+ .putAll("vserver|ipaddress",
+ "hasIpAddress,OUT,Many2Many,true,true,false,false")
+ .putAll("vserver|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("vserver|pserver",
+ "runsOnPserver,OUT,Many2One,false,true,false,true")
+ .putAll("vserver|volume", "hasVolume,OUT,Many2Many,true,true,false,true")
+ .putAll("vserver|vnfc", "hosts,OUT,Many2Many,false,true,false,true")
+ .putAll("vserver|snapshot", "uses,OUT,One2One,false,false,false,true")
+ .putAll("service-instance|connector", "uses,OUT,Many2Many,false,true,false,false")
+ .putAll("service-instance|metadatum", "hasMetaData,OUT,Many2Many,true,false,false,false")
+ .putAll("service-instance|logical-link", "uses,OUT,Many2Many,false,false,true,false")
+ .putAll("service-instance|vlan", "dependsOn,OUT,One2Many,false,true,false,false")
+ .putAll("service-instance|service-instance", "dependsOn,OUT,One2Many,false,true,false,false")
+ .putAll("connector|virtual-data-center", "contains,OUT,Many2Many,false,false,false,false")
+ .putAll("connector|metadatum", "hasMetaData,OUT,Many2Many,true,false,false,false")
+ .putAll("virtual-data-center|logical-link", "contains,OUT,Many2Many,false,true,false,false")
+ .putAll("logical-link|generic-vnf", "bridgedTo,OUT,Many2Many,false,false,false,false")
+ .putAll("logical-link|pserver", "bridgedTo,OUT,Many2Many,false,false,false,false")
+ .putAll("vlan|multicast-configuration", "uses,OUT,Many2Many,false,true,false,false")
+ .putAll("volume-group|complex", "existsIn,OUT,Many2Many,false,false,false,true")
+ .putAll("volume-group|tenant", "belongsTo,OUT,Many2Many,false,false,false,true")
+ .putAll("ipsec-configuration|vig-server", "hasVigServer,OUT,One2Many,true,true,false,false")
+ .putAll("generic-vnf|ipsec-configuration", "uses,OUT,Many2One,false,true,false,false")
+ .putAll("vf-module|volume-group", "uses,OUT,One2One,false,false,false,true")
+ .putAll("vserver|vf-module", "isPartOf,OUT,Many2One,false,false,false,true")
+ .putAll("vf-module|l3-network", "uses,OUT,Many2Many,false,false,false,true")
+ .putAll("vf-module|vnfc", "uses,OUT,One2Many,false,false,true,true")
+ .putAll("generic-vnf|vf-module", "has,OUT,One2Many,true,false,false,true")
+ .putAll("generic-vnf|volume-group", "uses,OUT,One2Many,false,false,false,true")
+ .putAll("generic-vnf|vnfc", "uses,OUT,One2Many,false,false,true,true")
+ .putAll("vlan|logical-link", "usesLogicalLink,OUT,Many2Many,false,false,true,true")
+ .putAll("vpn-binding|route-target", "has,OUT,One2Many,true,false,false,false")
+ .putAll("service-instance|ctag-assignment","uses,OUT,One2Many,false,false,false,false")
+ // The next edge is needed in 1702 but will be worked in user story AAI-6848
+ //.putAll("service-instance|allotted-resource", "uses,OUT,Many2Many,false,false,false,false")
+ .putAll("allotted-resource|generic-vnf", "isPartOf,OUT,Many2Many,false,false,false,false")
+ .putAll("allotted-resource|l3-network", "isPartOf,OUT,Many2Many,false,false,false,false")
+ .putAll("allotted-resource|instance-group", "isMemberOf,OUT,Many2Many,false,false,false,false")
+ .putAll("allotted-resource|network-policy", "uses,OUT,One2One,false,false,false,false")
+ .putAll("allotted-resource|vlan", "isPartOf,OUT,Many2Many,false,false,false,false")
+ .putAll("generic-vnf|instance-group", "isMemberOf,OUT,Many2Many,false,false,false,false")
+ .putAll("service-instance|instance-group", "isMemberOf,OUT,Many2Many,false,false,false,false")
+ .putAll("allotted-resource|tunnel-xconnect", "has,OUT,One2One,true,false,false,false")
+ .putAll("logical-link|cloud-region", "existsIn,OUT,Many2Many,false,false,false,false")
+ .putAll("logical-link|vpn-binding", "uses,OUT,Many2Many,false,false,false,false")
+ .putAll("generic-vnf|entitlement", "has,OUT,One2Many,true,false,false,false")
+ .putAll("generic-vnf|license", "has,OUT,One2Many,true,false,false,false")
+ .putAll("vce|entitlement", "has,OUT,One2Many,true,false,false,false")
+ .putAll("vce|license", "has,OUT,One2Many,true,false,false,false")
+ .putAll("vpe|entitlement", "has,OUT,One2Many,true,false,false,false")
+ .putAll("vpe|license", "has,OUT,One2Many,true,false,false,false")
+ .putAll("zone|complex", "existsIn,OUT,Many2One,false,false,false,false")
+ .putAll("service-instance|allotted-resource", "has,OUT,Many2Many,true,false,false,false")
+ .putAll("service-instance|allotted-resource", "uses,OUT,Many2Many,false,false,false,false")
+ .build();
+
+ public static final Multimap<String, String> DefaultDeleteScope = new ImmutableSetMultimap.Builder<String, String>()
+ .putAll("customer", "CASCADE_TO_CHILDREN")
+ .putAll("cloud-region", "THIS_NODE_ONLY")
+ .putAll("service-subscription", "CASCADE_TO_CHILDREN")
+ .putAll("service-instance", "CASCADE_TO_CHILDREN")
+ .putAll("vce", "CASCADE_TO_CHILDREN")
+ .putAll("port-group", "CASCADE_TO_CHILDREN")
+ .putAll("cvlan-tag", "THIS_NODE_ONLY")
+ .putAll("tenant", "THIS_NODE_ONLY")
+ .putAll("vserver", "CASCADE_TO_CHILDREN")
+ .putAll("volume", "THIS_NODE_ONLY")
+ .putAll("ipaddress", "THIS_NODE_ONLY")
+ .putAll("image", "ERROR_4_IN_EDGES_OR_CASCADE")
+ .putAll("pserver", "ERROR_4_IN_EDGES_OR_CASCADE")
+ .putAll("availability-zone", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("oam-network", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("dvs-switch", "THIS_NODE_ONLY")
+ .putAll("service-capability", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("complex", "ERROR_4_IN_EDGES_OR_CASCADE")
+ .putAll("flavor", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("metadata", "THIS_NODE_ONLY")
+ .putAll("metadatum", "THIS_NODE_ONLY")
+ .putAll("model", "ERROR_4_IN_EDGES_OR_CASCADE")
+ .putAll("model-ver", "ERROR_4_IN_EDGES_OR_CASCADE")
+ .putAll("model-element", "CASCADE_TO_CHILDREN")
+ .putAll("model-constraint", "CASCADE_TO_CHILDREN")
+ .putAll("property-constraint", "CASCADE_TO_CHILDREN")
+ .putAll("related-lookup", "CASCADE_TO_CHILDREN")
+ .putAll("constrained-element-set", "CASCADE_TO_CHILDREN")
+ .putAll("element-choice-set", "CASCADE_TO_CHILDREN")
+ .putAll("named-query", "CASCADE_TO_CHILDREN")
+ .putAll("named-query-element", "CASCADE_TO_CHILDREN")
+ .putAll("network-policy", "THIS_NODE_ONLY")
+ .putAll("collect-lookup", "THIS_NODE_ONLY")
+ .putAll("service", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("newvce", "CASCADE_TO_CHILDREN")
+ .putAll("vpe", "CASCADE_TO_CHILDREN")
+ .putAll("vpls-pe", "CASCADE_TO_CHILDREN")
+ .putAll("l-interface", "CASCADE_TO_CHILDREN")
+ .putAll("vlan", "CASCADE_TO_CHILDREN")
+ .putAll("p-interface", "CASCADE_TO_CHILDREN")
+ .putAll("l3-interface-ipv6-address-list", "THIS_NODE_ONLY")
+ .putAll("l3-interface-ipv4-address-list", "THIS_NODE_ONLY")
+ .putAll("logical-link", "THIS_NODE_ONLY")
+ .putAll("physical-link", "THIS_NODE_ONLY")
+ .putAll("lag-link", "THIS_NODE_ONLY")
+ .putAll("lag-interface", "CASCADE_TO_CHILDREN")
+ .putAll("virtual-data-center", "CASCADE_TO_CHILDREN")
+ .putAll("generic-vnf", "CASCADE_TO_CHILDREN")
+ .putAll("l3-network", "CASCADE_TO_CHILDREN")
+ .putAll("ctag-pool", "THIS_NODE_ONLY")
+ .putAll("subnet", "THIS_NODE_ONLY")
+ .putAll("sriov-vf", "THIS_NODE_ONLY")
+ .putAll("vpn-binding", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("vnf-image", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("site-pair-set", "CASCADE_TO_CHILDREN")
+ .putAll("routing-instance", "CASCADE_TO_CHILDREN")
+ .putAll("site-pair", "CASCADE_TO_CHILDREN")
+ .putAll("class-of-service", "THIS_NODE_ONLY")
+ .putAll("connector", "CASCADE_TO_CHILDREN")
+ .putAll("vnfc", "THIS_NODE_ONLY")
+ .putAll("multicast-configuration", "THIS_NODE_ONLY")
+ .putAll("volume-group", "THIS_NODE_ONLY")
+ .putAll("ctag-assignment", "THIS_NODE_ONLY")
+ .putAll("pnf", "CASCADE_TO_CHILDREN")
+ .putAll("ipsec-configuration", "CASCADE_TO_CHILDREN")
+ .putAll("vig-server", "THIS_NODE_ONLY")
+ .putAll("vf-module", "THIS_NODE_ONLY")
+ .putAll("snapshot", "THIS_NODE_ONLY")
+ .putAll("group-assignment", "THIS_NODE_ONLY")
+ .putAll("segmentation-assignment", "THIS_NODE_ONLY")
+ .putAll("route-table-reference", "THIS_NODE_ONLY")
+ .putAll("network-profile", "THIS_NODE_ONLY")
+ .putAll("allotted-resource", "CASCADE_TO_CHILDREN")
+ .putAll("tunnel-xconnect", "THIS_NODE_ONLY")
+ .putAll("instance-group","THIS_NODE_ONLY")
+ .putAll("entitlement","THIS_NODE_ONLY")
+ .putAll("license","THIS_NODE_ONLY")
+ .putAll("zone", "THIS_NODE_ONLY")
+ .putAll("route-target", "CASCADE_TO_CHILDREN").build();
+
+ // NOTE -- Sorry, this is ugly, but we are mapping the nodeTypeCategory two
+ // ways just to
+ // make the code a little less bulky. But that means that we need to ensure
+ // that
+ // nodeTypeCategory and nodeTypeCatMap are kept in synch.
+
+ // NodeTypeCategory: key is: nodeTypeCategory, value is:
+ // "nodeTypes,keyProperties,AltKeyProps,depNode4UniquenessFlag"
+ public static final Multimap<String, String> NodeTypeCategory = new ImmutableSetMultimap.Builder<String, String>()
+ .putAll("vnf", "vce|vpe|generic-vnf,vnf-id,,true").build();
+
+ // NodeTypeCatMap: key is nodeType; value is: "nodeTypeCategory"
+ // So -- we're assuming that a nodeType can only be in one nodeTypeCategory.
+ public static final Map<String, String> NodeTypeCatMap;
+ static {
+ NodeTypeCatMap = new HashMap<String, String>();
+ NodeTypeCatMap.put("vpe", "vnf");
+ NodeTypeCatMap.put("vce", "vnf");
+ NodeTypeCatMap.put("generic-vnf", "vnf");
+ }
+
+ // ReservedPropNames: keys are property names of (node) properties that are
+ // common to all nodes and
+ // should not be removed if not passed in on an UPDATE request.
+ public static final Map<String, String> ReservedPropNames;
+ static {
+ ReservedPropNames = new HashMap<String, String>();
+ ReservedPropNames.put("source-of-truth", "");
+ ReservedPropNames.put("last-mod-source-of-truth", "");
+ ReservedPropNames.put("aai-created-ts", "");
+ ReservedPropNames.put("aai-last-mod-ts", "");
+ }
+
+ // This just lists which node types can be connected to themselves recursively.
+ // It's temporary - since DbEdgeRules is going to be overhauled in 16-10, this will
+ // get generated automatically. But for 1607, it can work like this.
+ public static final Map<String, String> CanBeRecursiveNT;
+ static {
+ CanBeRecursiveNT = new HashMap<String, String>();
+ CanBeRecursiveNT.put("model-element", "");
+ CanBeRecursiveNT.put("service-instance", "");
+ CanBeRecursiveNT.put("named-query-element", "");
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/dbmodel/v8/gen/DbEdgeRules.java b/aai-core/src/main/java/org/openecomp/aai/dbmodel/v8/gen/DbEdgeRules.java
new file mode 100644
index 00000000..fac0ae48
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/dbmodel/v8/gen/DbEdgeRules.java
@@ -0,0 +1,300 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.dbmodel.v8.gen;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Multimap;
+
+public class DbEdgeRules {
+
+ /*
+ * The EdgeRules data is set up as a key (fromNodeTypeA|toNodeTypeB) mapped
+ * to a string which holds the info we need to build an edge from nodeTypeA
+ * to nodeTypeB. Note -- the MultiMap will let us define more than one type
+ * of edge between a given pair of nodeTypes, but for now we never define
+ * more than one.
+ *
+ * The edgeInfo part is comma separated and looks like this:
+ * "edgeLabel,direction,multiplicityRule,isParent,usesResource,hasDelTarget,SVC-INFRA" This
+ * format is encoded into the EdgeInfoMap below.
+ * MultiplicityRule can be either "Many2Many", "Many2One", "One2Many" or "One2One"
+ * The values for the things after multiplicityRule can be either "true", "false" or "reverse". "reverse" is
+ * really saying that this tag does apply, but the edge will be traversed
+ * the opposite way from the same tag that just has "true".
+ */
+ public static final Map<Integer, String> EdgeInfoMap;
+ static {
+ EdgeInfoMap = new HashMap<Integer, String>();
+ EdgeInfoMap.put(0, "edgeLabel");
+ EdgeInfoMap.put(1, "direction");
+ EdgeInfoMap.put(2, "multiplicityRule");
+ EdgeInfoMap.put(3, "isParent");
+ EdgeInfoMap.put(4, "usesResource");
+ EdgeInfoMap.put(5, "hasDelTarget");
+ EdgeInfoMap.put(6, "SVC-INFRA");
+ }
+
+ public static Integer firstTagIndex = 3;
+
+ public static final Multimap<String, String> EdgeRules = new ImmutableSetMultimap.Builder<String, String>()
+ .putAll("cloud-region|l3-network",
+ "uses,OUT,Many2Many,false,false,false,false")
+ .putAll("cloud-region|tenant",
+ "has,OUT,One2Many,true,false,false,reverse")
+ .putAll("cloud-region|image",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|flavor",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|availability-zone",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|volume-group",
+ "has,OUT,One2Many,true,true,false,false")
+ .putAll("cloud-region|group-assignment",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|snapshot",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("customer|service-subscription",
+ "subscribesTo,OUT,Many2Many,true,false,false,reverse")
+ .putAll("generic-vnf|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("generic-vnf|availability-zone",
+ "hasAvailabilityZone,OUT,Many2Many,false,false,false,true")
+ .putAll("generic-vnf|lag-interface",
+ "hasLAGInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("generic-vnf|l3-network",
+ "usesL3Network,OUT,Many2Many,false,true,false,true")
+ .putAll("generic-vnf|pserver",
+ "runsOnPserver,OUT,Many2Many,false,true,false,true")
+ .putAll("generic-vnf|vserver",
+ "runsOnVserver,OUT,One2Many,false,true,false,true")
+ .putAll("generic-vnf|service-instance",
+ "hasInstance,OUT,Many2Many,false,true,false,true")
+ .putAll("group-assignment|tenant",
+ "has,OUT,Many2Many,false,false,false,false")
+ .putAll("group-assignment|pserver",
+ "has,OUT,One2Many,false,false,false,false")
+ .putAll("image|metadata", "hasMetaData,OUT,Many2Many,true,false,false,false")
+ .putAll("image|metadatum",
+ "hasMetaDatum,OUT,Many2Many,true,false,false,false")
+ .putAll("l-interface|l3-interface-ipv4-address-list",
+ "hasIpAddress,OUT,Many2Many,true,false,false,true")
+ .putAll("l-interface|l3-interface-ipv6-address-list",
+ "hasIpAddress,OUT,Many2Many,true,false,false,true")
+ .putAll("l-interface|logical-link",
+ "usesLogicalLink,OUT,Many2Many,false,false,true,true")
+ .putAll("l-interface|vlan","hasVlan,OUT,Many2Many,true,false,false,false")
+ .putAll("l3-interface-ipv4-address-list|l3-network",
+ "isMemberOf,OUT,Many2Many,false,false,false,true")
+ .putAll("l3-interface-ipv6-address-list|l3-network",
+ "isMemberOf,OUT,Many2Many,false,false,false,true")
+ .putAll("l3-interface-ipv4-address-list|subnet",
+ "isMemberOf,OUT,Many2Many,false,false,false,true")
+ .putAll("l3-interface-ipv6-address-list|subnet",
+ "isMemberOf,OUT,Many2Many,false,false,false,true")
+ .putAll("l3-network|subnet",
+ "hasSubnet,OUT,Many2Many,true,false,false,reverse")
+ .putAll("l3-network|service-instance",
+ "hasInstance,OUT,Many2Many,false,false,false,reverse")
+ .putAll("l3-network|ctag-assignment",
+ "hasCtagAssignment,OUT,Many2Many,true,false,false,true")
+ .putAll("l3-network|segmentation-assignment",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("lag-interface|p-interface",
+ "usesPInterface,OUT,Many2Many,false,true,false,true")
+ .putAll("lag-interface|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("logical-link|pnf",
+ "bridgedTo,OUT,Many2Many,false,false,false,false")
+ .putAll("logical-link|logical-link",
+ "uses,OUT,One2Many,false,false,false,true")
+ .putAll("model|model-element",
+ "startsWith,OUT,One2Many,true,false,false,false")
+ .putAll("model-element|model",
+ "isA,OUT,Many2One,false,false,false,false")
+ .putAll("model|metadatum",
+ "hasMetaData,OUT,One2Many,true,false,false,false")
+ .putAll("model-element|model-element",
+ "connectsTo,OUT,One2Many,true,false,false,false")
+ .putAll("model-element|model-constraint",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("model-element|constrained-element-set",
+ "connectsTo,OUT,One2Many,true,false,false,false")
+ .putAll("model-constraint|constrained-element-set",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("constrained-element-set|element-choice-set",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("element-choice-set|model-element",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("named-query|model",
+ "relatedTo,OUT,One2Many,false,false,false,false")
+ .putAll("named-query|named-query-element",
+ "startsWith,OUT,One2One,true,false,false,false")
+ .putAll("named-query-element|named-query-element",
+ "connectsTo,OUT,Many2Many,true,false,false,false")
+ .putAll("named-query-element|model",
+ "isA,OUT,Many2One,false,false,false,false")
+ .putAll("named-query-element|property-constraint",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("named-query-element|related-lookup",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("p-interface|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("p-interface|physical-link",
+ "usesPhysicalLink,OUT,Many2Many,false,false,true,false")
+ .putAll("p-interface|logical-link",
+ "usesLogicalLink,OUT,Many2One,false,false,false,true")
+ .putAll("pserver|cloud-region","locatedIn,OUT,Many2One,false,false,false,true")
+ .putAll("pserver|availability-zone","existsIn,OUT,Many2One,false,false,false,true")
+ .putAll("pserver|lag-interface",
+ "hasLAGInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("pserver|p-interface",
+ "hasPinterface,OUT,Many2Many,true,true,false,true")
+ .putAll("pnf|p-interface",
+ "hasPinterface,OUT,Many2Many,true,true,false,true")
+ .putAll("pnf|lag-interface",
+ "has,OUT,One2Many,true,false,false,true")
+ .putAll("service-instance|pnf",
+ "uses,OUT,One2Many,false,true,false,false")
+ .putAll("service-subscription|service-instance",
+ "hasInstance,OUT,Many2Many,true,false,false,reverse")
+ .putAll("tenant|l3-network",
+ "usesL3Network,OUT,Many2Many,false,false,false,false")
+ .putAll("tenant|service-subscription",
+ "relatedTo,OUT,Many2Many,false,false,false,false")
+ .putAll("tenant|vserver", "owns,OUT,One2Many,true,false,false,reverse")
+ .putAll("vlan|l3-interface-ipv4-address-list",
+ "hasIpAddress,OUT,Many2Many,true,false,false,true")
+ .putAll("vlan|l3-interface-ipv6-address-list",
+ "hasIpAddress,OUT,Many2Many,true,false,false,true")
+ .putAll("vserver|flavor", "hasFlavor,OUT,Many2One,false,false,false,true")
+ .putAll("vserver|image", "hasImage,OUT,Many2One,false,false,false,true")
+ .putAll("vserver|ipaddress",
+ "hasIpAddress,OUT,Many2Many,true,true,false,false")
+ .putAll("vserver|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("vserver|pserver",
+ "runsOnPserver,OUT,Many2One,false,true,false,true")
+ .putAll("vserver|volume", "hasVolume,OUT,Many2Many,true,true,false,true")
+ .putAll("vserver|vnfc", "hosts,OUT,Many2Many,false,true,false,true")
+ .putAll("vserver|snapshot", "uses,OUT,One2One,false,false,false,true")
+ .putAll("service-instance|metadatum", "hasMetaData,OUT,Many2Many,true,false,false,false")
+ .putAll("service-instance|logical-link", "uses,OUT,Many2Many,false,false,true,false")
+ .putAll("service-instance|vlan", "dependsOn,OUT,One2Many,false,true,false,false")
+ .putAll("service-instance|service-instance", "dependsOn,OUT,One2Many,false,true,false,false")
+ .putAll("logical-link|generic-vnf", "bridgedTo,OUT,Many2Many,false,false,false,false")
+ .putAll("logical-link|pserver", "bridgedTo,OUT,Many2Many,false,false,false,false")
+ .putAll("volume-group|tenant", "belongsTo,OUT,Many2Many,false,false,false,true")
+ .putAll("vf-module|volume-group", "uses,OUT,One2One,false,false,false,true")
+ .putAll("vserver|vf-module", "isPartOf,OUT,Many2One,false,false,false,true")
+ .putAll("vf-module|l3-network", "uses,OUT,Many2Many,false,false,false,true")
+ .putAll("vf-module|vnfc", "uses,OUT,One2Many,false,false,true,true")
+ .putAll("generic-vnf|vf-module", "has,OUT,One2Many,true,false,false,true")
+ .putAll("generic-vnf|volume-group", "uses,OUT,One2Many,false,false,false,true")
+ .putAll("generic-vnf|vnfc", "uses,OUT,One2Many,false,false,true,true")
+ .putAll("vlan|logical-link", "usesLogicalLink,OUT,One2One,false,false,true,true")
+ .build();
+
+ public static final Multimap<String, String> DefaultDeleteScope = new ImmutableSetMultimap.Builder<String, String>()
+ .putAll("customer", "CASCADE_TO_CHILDREN")
+ .putAll("cloud-region", "THIS_NODE_ONLY")
+ .putAll("service-subscription", "CASCADE_TO_CHILDREN")
+ .putAll("service-instance", "CASCADE_TO_CHILDREN")
+ .putAll("tenant", "CASCADE_TO_CHILDREN")
+ .putAll("vserver", "CASCADE_TO_CHILDREN")
+ .putAll("volume", "THIS_NODE_ONLY")
+ .putAll("ipaddress", "THIS_NODE_ONLY")
+ .putAll("image", "ERROR_4_IN_EDGES_OR_CASCADE")
+ .putAll("pserver", "ERROR_4_IN_EDGES_OR_CASCADE")
+ .putAll("availability-zone", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("flavor", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("metadata", "THIS_NODE_ONLY")
+ .putAll("metadatum", "THIS_NODE_ONLY")
+ .putAll("model", "ERROR_4_IN_EDGES_OR_CASCADE")
+ .putAll("model-element", "CASCADE_TO_CHILDREN")
+ .putAll("named-query", "CASCADE_TO_CHILDREN")
+ .putAll("named-query-element", "CASCADE_TO_CHILDREN")
+ .putAll("collect-lookup", "THIS_NODE_ONLY")
+ .putAll("service", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("l-interface", "CASCADE_TO_CHILDREN")
+ .putAll("vlan", "CASCADE_TO_CHILDREN")
+ .putAll("p-interface", "CASCADE_TO_CHILDREN")
+ .putAll("l3-interface-ipv6-address-list", "THIS_NODE_ONLY")
+ .putAll("l3-interface-ipv4-address-list", "THIS_NODE_ONLY")
+ .putAll("logical-link", "THIS_NODE_ONLY")
+ .putAll("physical-link", "THIS_NODE_ONLY")
+ .putAll("lag-interface", "CASCADE_TO_CHILDREN")
+ .putAll("l3-network", "CASCADE_TO_CHILDREN")
+ .putAll("subnet", "THIS_NODE_ONLY")
+ .putAll("vnfc", "THIS_NODE_ONLY")
+ .putAll("volume-group", "THIS_NODE_ONLY")
+ .putAll("ctag-assignment", "THIS_NODE_ONLY")
+ .putAll("pnf", "CASCADE_TO_CHILDREN")
+ .putAll("vf-module", "THIS_NODE_ONLY")
+ .putAll("snapshot", "THIS_NODE_ONLY")
+ .putAll("group-assignment", "THIS_NODE_ONLY")
+ .putAll("segmentation-assignment", "THIS_NODE_ONLY")
+ .putAll("generic-vnf", "CASCADE_TO_CHILDREN").build();
+
+ // NOTE -- Sorry, this is ugly, but we are mapping the nodeTypeCategory two
+ // ways just to
+ // make the code a little less bulky. But that means that we need to ensure
+ // that
+ // nodeTypeCategory and nodeTypeCatMap are kept in synch.
+
+ // NodeTypeCategory: key is: nodeTypeCategory, value is:
+ // "nodeTypes,keyProperties,AltKeyProps,depNode4UniquenessFlag"
+ public static final Multimap<String, String> NodeTypeCategory = new ImmutableSetMultimap.Builder<String, String>()
+ .putAll("vnf", "generic-vnf,vnf-id,,true").build();
+
+ // NodeTypeCatMap: key is nodeType; value is: "nodeTypeCategory"
+ // So -- we're assuming that a nodeType can only be in one nodeTypeCategory.
+ public static final Map<String, String> NodeTypeCatMap;
+ static {
+ NodeTypeCatMap = new HashMap<String, String>();
+ NodeTypeCatMap.put("generic-vnf", "vnf");
+ }
+
+ // ReservedPropNames: keys are property names of (node) properties that are
+ // common to all nodes and
+ // should not be removed if not passed in on an UPDATE request.
+ public static final Map<String, String> ReservedPropNames;
+ static {
+ ReservedPropNames = new HashMap<String, String>();
+ ReservedPropNames.put("source-of-truth", "");
+ ReservedPropNames.put("last-mod-source-of-truth", "");
+ ReservedPropNames.put("aai-created-ts", "");
+ ReservedPropNames.put("aai-last-mod-ts", "");
+ }
+
+ // This just lists which node types can be connected to themselves recursively.
+ // It's temporary - since DbEdgeRules is going to be overhauled in 16-10, this will
+ // get generated automatically. But for 1607, it can work like this.
+ public static final Map<String, String> CanBeRecursiveNT;
+ static {
+ CanBeRecursiveNT = new HashMap<String, String>();
+ CanBeRecursiveNT.put("model-element", "");
+ CanBeRecursiveNT.put("named-query-element", "");
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/dbmodel/v9/gen/DbEdgeRules.java b/aai-core/src/main/java/org/openecomp/aai/dbmodel/v9/gen/DbEdgeRules.java
new file mode 100644
index 00000000..3787bc80
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/dbmodel/v9/gen/DbEdgeRules.java
@@ -0,0 +1,459 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.dbmodel.v9.gen;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Multimap;
+
+public class DbEdgeRules {
+
+ /*
+ * The EdgeRules data is set up as a key (fromNodeTypeA|toNodeTypeB) mapped
+ * to a string which holds the info we need to build an edge from nodeTypeA
+ * to nodeTypeB. Note -- the MultiMap will let us define more than one type
+ * of edge between a given pair of nodeTypes, but for now we never define
+ * more than one.
+ *
+ * The edgeInfo part is comma separated and looks like this:
+ * "edgeLabel,direction,multiplicityRule,isParent,usesResource,hasDelTarget,SVC-INFRA" This
+ * format is encoded into the EdgeInfoMap below.
+ * MultiplicityRule can be either "Many2Many", "Many2One", "One2Many" or "One2One"
+ * The values for the things after multiplicityRule can be either "true", "false" or "reverse". "reverse" is
+ * really saying that this tag does apply, but the edge will be traversed
+ * the opposite way from the same tag that just has "true".
+ */
+ public static final Map<Integer, String> EdgeInfoMap;
+ static {
+ EdgeInfoMap = new HashMap<Integer, String>();
+ EdgeInfoMap.put(0, "edgeLabel");
+ EdgeInfoMap.put(1, "direction");
+ EdgeInfoMap.put(2, "multiplicityRule");
+ EdgeInfoMap.put(3, "isParent");
+ EdgeInfoMap.put(4, "usesResource");
+ EdgeInfoMap.put(5, "hasDelTarget");
+ EdgeInfoMap.put(6, "SVC-INFRA");
+ }
+
+ public static Integer firstTagIndex = 3;
+
+ public static final Multimap<String, String> EdgeRules = new ImmutableSetMultimap.Builder<String, String>()
+ .putAll("availability-zone|complex",
+ "groupsResourcesIn,OUT,Many2Many,false,false,false,false")
+ .putAll("availability-zone|service-capability",
+ "supportsServiceCapability,OUT,Many2Many,false,false,false,false")
+ .putAll("cloud-region|complex",
+ "locatedIn,OUT,Many2One,false,false,false,false")
+ .putAll("cloud-region|l3-network",
+ "uses,OUT,Many2Many,false,false,false,false")
+ .putAll("cloud-region|tenant",
+ "has,OUT,One2Many,true,false,false,reverse")
+ .putAll("cloud-region|image",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|flavor",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|availability-zone",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|oam-network",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|dvs-switch",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|volume-group",
+ "has,OUT,One2Many,true,true,false,false")
+ .putAll("cloud-region|group-assignment",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|snapshot",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("cloud-region|zone",
+ "isMemberOf,OUT,Many2One,false,false,false,false")
+ .putAll("complex|ctag-pool",
+ "hasCtagPool,OUT,Many2Many,true,false,false,false")
+ .putAll("complex|l3-network",
+ "usesL3Network,OUT,Many2Many,false,false,false,true")
+ .putAll("ctag-pool|availability-zone",
+ "supportsAvailabilityZone,OUT,Many2Many,false,false,false,false")
+ .putAll("customer|service-subscription",
+ "subscribesTo,OUT,Many2Many,true,false,false,reverse")
+ .putAll("dvs-switch|availability-zone",
+ "existsIn,OUT,Many2Many,false,false,false,false")
+ .putAll("generic-vnf|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("generic-vnf|availability-zone",
+ "hasAvailabilityZone,OUT,Many2Many,false,false,false,true")
+ .putAll("generic-vnf|lag-interface",
+ "hasLAGInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("generic-vnf|l3-network",
+ "usesL3Network,OUT,Many2Many,false,true,false,true")
+ .putAll("generic-vnf|pserver",
+ "runsOnPserver,OUT,Many2Many,false,true,false,true")
+ .putAll("generic-vnf|vnf-image",
+ "usesVnfImage,OUT,Many2One,false,false,false,true")
+ .putAll("generic-vnf|vserver",
+ "runsOnVserver,OUT,One2Many,false,true,false,true")
+ .putAll("generic-vnf|service-instance",
+ "hasInstance,OUT,Many2Many,false,true,false,true")
+ .putAll("generic-vnf|site-pair-set",
+ "hasSitePairSet,OUT,Many2Many,false,false,false,false")
+ .putAll("generic-vnf|network-profile",
+ "hasNetworkProfile,OUT,Many2Many,false,false,false,false")
+ .putAll("group-assignment|tenant",
+ "has,OUT,Many2Many,false,false,false,false")
+ .putAll("group-assignment|pserver",
+ "has,OUT,One2Many,false,false,false,false")
+ .putAll("image|metadata", "hasMetaData,OUT,Many2Many,true,false,false,false")
+ .putAll("image|metadatum",
+ "hasMetaDatum,OUT,Many2Many,true,false,false,false")
+ .putAll("l-interface|l3-interface-ipv4-address-list",
+ "hasIpAddress,OUT,Many2Many,true,false,false,true")
+ .putAll("l-interface|l3-interface-ipv6-address-list",
+ "hasIpAddress,OUT,Many2Many,true,false,false,true")
+ .putAll("l-interface|logical-link",
+ "usesLogicalLink,OUT,Many2Many,false,false,true,true")
+ .putAll("l-interface|vlan","hasVlan,OUT,Many2Many,true,false,false,false")
+ .putAll("l-interface|sriov-vf","has,OUT,One2One,true,false,false,false")
+ .putAll("l3-interface-ipv4-address-list|l3-network",
+ "isMemberOf,OUT,Many2Many,false,false,false,true")
+ .putAll("l3-interface-ipv6-address-list|l3-network",
+ "isMemberOf,OUT,Many2Many,false,false,false,true")
+ .putAll("l3-interface-ipv4-address-list|subnet",
+ "isMemberOf,OUT,Many2Many,false,false,false,true")
+ .putAll("l3-interface-ipv6-address-list|subnet",
+ "isMemberOf,OUT,Many2Many,false,false,false,true")
+ .putAll("l3-network|vpn-binding",
+ "usesVpnBinding,OUT,Many2Many,false,false,false,false")
+ .putAll("l3-network|subnet",
+ "hasSubnet,OUT,Many2Many,true,false,false,reverse")
+ .putAll("l3-network|service-instance",
+ "hasInstance,OUT,Many2Many,false,false,false,reverse")
+ .putAll("l3-network|ctag-assignment",
+ "hasCtagAssignment,OUT,Many2Many,true,false,false,true")
+ .putAll("l3-network|network-policy",
+ "uses,OUT,Many2Many,false,false,false,true")
+ .putAll("l3-network|segmentation-assignment",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("l3-network|route-table-reference",
+ "uses,OUT,Many2Many,false,false,false,false")
+ .putAll("lag-interface|lag-link",
+ "usesLAGLink,OUT,Many2Many,false,true,true,true")
+ .putAll("lag-interface|p-interface",
+ "usesPInterface,OUT,Many2Many,false,true,false,true")
+ .putAll("lag-interface|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("logical-link|lag-link",
+ "usesLAGLink,OUT,Many2Many,false,true,false,true")
+ .putAll("logical-link|pnf",
+ "bridgedTo,OUT,Many2Many,false,false,false,false")
+ .putAll("logical-link|logical-link",
+ "uses,OUT,One2Many,false,false,false,true")
+ .putAll("model|model-ver",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("model-ver|model-element",
+ "startsWith,OUT,One2Many,true,false,false,false")
+ .putAll("model-element|model-ver",
+ "isA,OUT,Many2One,false,false,false,false")
+ .putAll("model-ver|metadatum",
+ "hasMetaData,OUT,One2Many,true,false,false,false")
+ .putAll("model-element|model-element",
+ "connectsTo,OUT,One2Many,true,false,false,false")
+ .putAll("model-element|model-constraint",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("model-element|constrained-element-set",
+ "connectsTo,OUT,One2Many,true,false,false,false")
+ .putAll("model-constraint|constrained-element-set",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("constrained-element-set|element-choice-set",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("element-choice-set|model-element",
+ "has,OUT,One2Many,true,false,false,false")
+ .putAll("named-query|model",
+ "relatedTo,OUT,One2Many,false,false,false,false")
+ .putAll("named-query|named-query-element",
+ "startsWith,OUT,One2One,true,false,false,false")
+ .putAll("named-query-element|named-query-element",
+ "connectsTo,OUT,Many2Many,true,false,false,false")
+ .putAll("named-query-element|model",
+ "isA,OUT,Many2One,false,false,false,false")
+ .putAll("named-query-element|property-constraint",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("named-query-element|related-lookup",
+ "uses,OUT,One2Many,true,false,false,false")
+ .putAll("instance-group|model",
+ "targets,OUT,Many2Many,false,false,false,false")
+ .putAll("newvce|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,false")
+ .putAll("oam-network|complex",
+ "definedFor,OUT,Many2Many,false,false,false,false")
+ .putAll("oam-network|service-capability",
+ "supportsServiceCapability,OUT,Many2Many,false,false,false,false")
+ .putAll("p-interface|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("p-interface|physical-link",
+ "usesPhysicalLink,OUT,Many2Many,false,false,true,false")
+ .putAll("p-interface|logical-link",
+ "usesLogicalLink,OUT,Many2One,false,false,false,true")
+ .putAll("port-group|cvlan-tag", "hasCTag,OUT,Many2Many,true,true,false,true")
+ .putAll("pserver|complex", "locatedIn,OUT,Many2One,false,false,false,true")
+ .putAll("pserver|cloud-region","locatedIn,OUT,Many2One,false,false,false,true")
+ .putAll("pserver|availability-zone","existsIn,OUT,Many2One,false,false,false,true")
+ .putAll("pserver|lag-interface",
+ "hasLAGInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("pserver|p-interface",
+ "hasPinterface,OUT,Many2Many,true,true,false,true")
+ .putAll("pserver|zone",
+ "isMemberOf,OUT,Many2One,false,false,false,false")
+ .putAll("pnf|p-interface",
+ "hasPinterface,OUT,Many2Many,true,true,false,true")
+ .putAll("pnf|lag-interface",
+ "has,OUT,One2Many,true,false,false,true")
+ .putAll("pnf|complex",
+ "locatedIn,OUT,Many2One,false,false,false,false")
+ .putAll("pnf|instance-group",
+ "isMemberOf,OUT,Many2Many,false,false,false,false")
+ .putAll("pnf|zone",
+ "isMemberOf,OUT,Many2One,false,false,false,false")
+ .putAll("service-instance|cvlan-tag",
+ "hasIPAGFacingVLAN,OUT,Many2Many,false,true,false,false")
+ .putAll("service-instance|pnf",
+ "uses,OUT,One2Many,false,true,false,false")
+ .putAll("service-subscription|service-instance",
+ "hasInstance,OUT,Many2Many,true,false,false,reverse")
+ .putAll("site-pair-set|routing-instance",
+ "hasRoutingInstance,OUT,Many2Many,true,false,false,false")
+ .putAll("routing-instance|site-pair",
+ "hasSitePair,OUT,Many2Many,true,false,false,false")
+ .putAll("site-pair|class-of-service",
+ "hasClassOfService,OUT,Many2Many,true,false,false,false")
+ .putAll("tenant|l3-network",
+ "usesL3Network,OUT,Many2Many,false,false,false,false")
+ .putAll("tenant|service-subscription",
+ "relatedTo,OUT,Many2Many,false,false,false,false")
+ .putAll("tenant|vserver", "owns,OUT,One2Many,true,false,false,reverse")
+ .putAll("vce|availability-zone",
+ "hasAvailabilityZone,OUT,Many2Many,false,false,false,false")
+ .putAll("vce|complex", "locatedIn,OUT,Many2Many,false,false,false,true")
+ .putAll("vce|port-group", "hasPortGroup,OUT,Many2Many,true,true,false,true")
+ .putAll("vce|vserver", "runsOnVserver,OUT,Many2Many,false,true,false,true")
+ .putAll("vce|service-instance",
+ "hasServiceInstance,OUT,Many2Many,false,false,false,reverse")
+ .putAll("virtual-data-center|generic-vnf",
+ "hasVNF,OUT,Many2Many,false,false,false,reverse")
+ .putAll("vlan|l3-interface-ipv4-address-list",
+ "hasIpAddress,OUT,Many2Many,true,false,false,true")
+ .putAll("vlan|l3-interface-ipv6-address-list",
+ "hasIpAddress,OUT,Many2Many,true,false,false,true")
+ .putAll("vpe|complex", "locatedIn,OUT,Many2Many,false,false,false,false")
+ .putAll("vpe|ctag-pool", "usesCtagPool,OUT,Many2Many,false,false,false,false")
+ .putAll("vpe|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,false")
+ .putAll("vpe|lag-interface",
+ "hasLAGInterface,OUT,Many2Many,true,false,false,false")
+ .putAll("vpe|vserver", "runsOnVserver,OUT,Many2Many,false,true,false,false")
+ .putAll("vpls-pe|complex", "locatedIn,OUT,Many2Many,false,false,false,false")
+ .putAll("vpls-pe|ctag-pool",
+ "usesCtagPool,OUT,Many2Many,false,false,false,false")
+ .putAll("vpls-pe|p-interface",
+ "hasPinterface,OUT,Many2Many,true,false,false,false")
+ .putAll("vpls-pe|lag-interface",
+ "hasLAGinterface,OUT,Many2Many,true,false,false,false")
+ .putAll("vserver|flavor", "hasFlavor,OUT,Many2One,false,false,false,true")
+ .putAll("vserver|image", "hasImage,OUT,Many2One,false,false,false,true")
+ .putAll("vserver|ipaddress",
+ "hasIpAddress,OUT,Many2Many,true,true,false,false")
+ .putAll("vserver|l-interface",
+ "hasLInterface,OUT,Many2Many,true,false,false,true")
+ .putAll("vserver|pserver",
+ "runsOnPserver,OUT,Many2One,false,true,false,true")
+ .putAll("vserver|volume", "hasVolume,OUT,Many2Many,true,true,false,true")
+ .putAll("vserver|vnfc", "hosts,OUT,Many2Many,false,true,false,true")
+ .putAll("vserver|snapshot", "uses,OUT,One2One,false,false,false,true")
+ .putAll("service-instance|connector", "uses,OUT,Many2Many,false,true,false,false")
+ .putAll("service-instance|metadatum", "hasMetaData,OUT,Many2Many,true,false,false,false")
+ .putAll("service-instance|logical-link", "uses,OUT,Many2Many,false,false,true,false")
+ .putAll("service-instance|vlan", "dependsOn,OUT,One2Many,false,true,false,false")
+ .putAll("service-instance|service-instance", "dependsOn,OUT,One2Many,false,true,false,false")
+ .putAll("connector|virtual-data-center", "contains,OUT,Many2Many,false,false,false,false")
+ .putAll("connector|metadatum", "hasMetaData,OUT,Many2Many,true,false,false,false")
+ .putAll("virtual-data-center|logical-link", "contains,OUT,Many2Many,false,true,false,false")
+ .putAll("logical-link|generic-vnf", "bridgedTo,OUT,Many2Many,false,false,false,false")
+ .putAll("logical-link|pserver", "bridgedTo,OUT,Many2Many,false,false,false,false")
+ .putAll("vlan|multicast-configuration", "uses,OUT,Many2Many,false,true,false,false")
+ .putAll("volume-group|complex", "existsIn,OUT,Many2Many,false,false,false,true")
+ .putAll("volume-group|tenant", "belongsTo,OUT,Many2Many,false,false,false,true")
+ .putAll("ipsec-configuration|vig-server", "hasVigServer,OUT,One2Many,true,true,false,false")
+ .putAll("generic-vnf|ipsec-configuration", "uses,OUT,Many2One,false,true,false,false")
+ .putAll("vf-module|volume-group", "uses,OUT,One2One,false,false,false,true")
+ .putAll("vserver|vf-module", "isPartOf,OUT,Many2One,false,false,false,true")
+ .putAll("vf-module|l3-network", "uses,OUT,Many2Many,false,false,false,true")
+ .putAll("vf-module|vnfc", "uses,OUT,One2Many,false,false,true,true")
+ .putAll("generic-vnf|vf-module", "has,OUT,One2Many,true,false,false,true")
+ .putAll("generic-vnf|volume-group", "uses,OUT,One2Many,false,false,false,true")
+ .putAll("generic-vnf|vnfc", "uses,OUT,One2Many,false,false,true,true")
+ .putAll("vlan|logical-link", "usesLogicalLink,OUT,Many2Many,false,false,true,true")
+ .putAll("service-instance|ctag-assignment","uses,OUT,One2Many,false,false,false,false")
+ // The next edge is needed in 1702 but will be worked in user story AAI-6848
+ //.putAll("service-instance|allotted-resource", "uses,OUT,Many2Many,false,false,false,false")
+ .putAll("allotted-resource|generic-vnf", "isPartOf,OUT,Many2Many,false,false,false,false")
+ .putAll("allotted-resource|l3-network", "isPartOf,OUT,Many2Many,false,false,false,false")
+ .putAll("allotted-resource|instance-group", "isMemberOf,OUT,Many2Many,false,false,false,false")
+ .putAll("allotted-resource|vlan", "isPartOf,OUT,Many2Many,false,false,false,false")
+ .putAll("generic-vnf|instance-group", "isMemberOf,OUT,Many2Many,false,false,false,false")
+ .putAll("service-instance|instance-group", "isMemberOf,OUT,Many2Many,false,false,false,false")
+ .putAll("allotted-resource|tunnel-xconnect", "has,OUT,One2One,true,false,false,false")
+ .putAll("logical-link|cloud-region", "existsIn,OUT,Many2Many,false,false,false,false")
+ .putAll("logical-link|vpn-binding", "uses,OUT,Many2Many,false,false,false,false")
+ .putAll("generic-vnf|entitlement", "has,OUT,One2Many,true,false,false,false")
+ .putAll("generic-vnf|license", "has,OUT,One2Many,true,false,false,false")
+ .putAll("vce|entitlement", "has,OUT,One2Many,true,false,false,false")
+ .putAll("vce|license", "has,OUT,One2Many,true,false,false,false")
+ .putAll("vpe|entitlement", "has,OUT,One2Many,true,false,false,false")
+ .putAll("vpe|license", "has,OUT,One2Many,true,false,false,false")
+ .putAll("zone|complex", "existsIn,OUT,Many2One,false,false,false,false")
+ .putAll("service-instance|allotted-resource", "has,OUT,Many2Many,true,false,false,false")
+ .putAll("service-instance|allotted-resource", "uses,OUT,Many2Many,false,false,false,false")
+ .build();
+
+ public static final Multimap<String, String> DefaultDeleteScope = new ImmutableSetMultimap.Builder<String, String>()
+ .putAll("customer", "CASCADE_TO_CHILDREN")
+ .putAll("cloud-region", "THIS_NODE_ONLY")
+ .putAll("service-subscription", "CASCADE_TO_CHILDREN")
+ .putAll("service-instance", "CASCADE_TO_CHILDREN")
+ .putAll("vce", "CASCADE_TO_CHILDREN")
+ .putAll("port-group", "CASCADE_TO_CHILDREN")
+ .putAll("cvlan-tag", "THIS_NODE_ONLY")
+ .putAll("tenant", "THIS_NODE_ONLY")
+ .putAll("vserver", "CASCADE_TO_CHILDREN")
+ .putAll("volume", "THIS_NODE_ONLY")
+ .putAll("ipaddress", "THIS_NODE_ONLY")
+ .putAll("image", "ERROR_4_IN_EDGES_OR_CASCADE")
+ .putAll("pserver", "ERROR_4_IN_EDGES_OR_CASCADE")
+ .putAll("availability-zone", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("oam-network", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("dvs-switch", "THIS_NODE_ONLY")
+ .putAll("service-capability", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("complex", "ERROR_4_IN_EDGES_OR_CASCADE")
+ .putAll("flavor", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("metadata", "THIS_NODE_ONLY")
+ .putAll("metadatum", "THIS_NODE_ONLY")
+ .putAll("model", "ERROR_4_IN_EDGES_OR_CASCADE")
+ .putAll("model-ver", "ERROR_4_IN_EDGES_OR_CASCADE")
+ .putAll("model-element", "CASCADE_TO_CHILDREN")
+ .putAll("model-constraint", "CASCADE_TO_CHILDREN")
+ .putAll("property-constraint", "CASCADE_TO_CHILDREN")
+ .putAll("related-lookup", "CASCADE_TO_CHILDREN")
+ .putAll("constrained-element-set", "CASCADE_TO_CHILDREN")
+ .putAll("element-choice-set", "CASCADE_TO_CHILDREN")
+ .putAll("named-query", "CASCADE_TO_CHILDREN")
+ .putAll("named-query-element", "CASCADE_TO_CHILDREN")
+ .putAll("network-policy", "THIS_NODE_ONLY")
+ .putAll("collect-lookup", "THIS_NODE_ONLY")
+ .putAll("service", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("newvce", "CASCADE_TO_CHILDREN")
+ .putAll("vpe", "CASCADE_TO_CHILDREN")
+ .putAll("vpls-pe", "CASCADE_TO_CHILDREN")
+ .putAll("l-interface", "CASCADE_TO_CHILDREN")
+ .putAll("vlan", "CASCADE_TO_CHILDREN")
+ .putAll("p-interface", "CASCADE_TO_CHILDREN")
+ .putAll("l3-interface-ipv6-address-list", "THIS_NODE_ONLY")
+ .putAll("l3-interface-ipv4-address-list", "THIS_NODE_ONLY")
+ .putAll("logical-link", "THIS_NODE_ONLY")
+ .putAll("physical-link", "THIS_NODE_ONLY")
+ .putAll("lag-link", "THIS_NODE_ONLY")
+ .putAll("lag-interface", "CASCADE_TO_CHILDREN")
+ .putAll("virtual-data-center", "CASCADE_TO_CHILDREN")
+ .putAll("generic-vnf", "CASCADE_TO_CHILDREN")
+ .putAll("l3-network", "CASCADE_TO_CHILDREN")
+ .putAll("ctag-pool", "THIS_NODE_ONLY")
+ .putAll("subnet", "THIS_NODE_ONLY")
+ .putAll("sriov-vf", "THIS_NODE_ONLY")
+ .putAll("vpn-binding", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("vnf-image", "ERROR_IF_ANY_IN_EDGES")
+ .putAll("site-pair-set", "CASCADE_TO_CHILDREN")
+ .putAll("routing-instance", "CASCADE_TO_CHILDREN")
+ .putAll("site-pair", "CASCADE_TO_CHILDREN")
+ .putAll("class-of-service", "THIS_NODE_ONLY")
+ .putAll("connector", "CASCADE_TO_CHILDREN")
+ .putAll("vnfc", "THIS_NODE_ONLY")
+ .putAll("multicast-configuration", "THIS_NODE_ONLY")
+ .putAll("volume-group", "THIS_NODE_ONLY")
+ .putAll("ctag-assignment", "THIS_NODE_ONLY")
+ .putAll("pnf", "CASCADE_TO_CHILDREN")
+ .putAll("ipsec-configuration", "CASCADE_TO_CHILDREN")
+ .putAll("vig-server", "THIS_NODE_ONLY")
+ .putAll("vf-module", "THIS_NODE_ONLY")
+ .putAll("snapshot", "THIS_NODE_ONLY")
+ .putAll("group-assignment", "THIS_NODE_ONLY")
+ .putAll("segmentation-assignment", "THIS_NODE_ONLY")
+ .putAll("route-table-reference", "THIS_NODE_ONLY")
+ .putAll("network-profile", "THIS_NODE_ONLY")
+ .putAll("allotted-resource", "CASCADE_TO_CHILDREN")
+ .putAll("tunnel-xconnect", "THIS_NODE_ONLY")
+ .putAll("instance-group","THIS_NODE_ONLY")
+ .putAll("entitlement","THIS_NODE_ONLY")
+ .putAll("license","THIS_NODE_ONLY")
+ .putAll("zone", "THIS_NODE_ONLY").build();
+
+ // NOTE -- Sorry, this is ugly, but we are mapping the nodeTypeCategory two
+ // ways just to
+ // make the code a little less bulky. But that means that we need to ensure
+ // that
+ // nodeTypeCategory and nodeTypeCatMap are kept in synch.
+
+ // NodeTypeCategory: key is: nodeTypeCategory, value is:
+ // "nodeTypes,keyProperties,AltKeyProps,depNode4UniquenessFlag"
+ public static final Multimap<String, String> NodeTypeCategory = new ImmutableSetMultimap.Builder<String, String>()
+ .putAll("vnf", "vce|vpe|generic-vnf,vnf-id,,true").build();
+
+ // NodeTypeCatMap: key is nodeType; value is: "nodeTypeCategory"
+ // So -- we're assuming that a nodeType can only be in one nodeTypeCategory.
+ public static final Map<String, String> NodeTypeCatMap;
+ static {
+ NodeTypeCatMap = new HashMap<String, String>();
+ NodeTypeCatMap.put("vpe", "vnf");
+ NodeTypeCatMap.put("vce", "vnf");
+ NodeTypeCatMap.put("generic-vnf", "vnf");
+ }
+
+ // ReservedPropNames: keys are property names of (node) properties that are
+ // common to all nodes and
+ // should not be removed if not passed in on an UPDATE request.
+ public static final Map<String, String> ReservedPropNames;
+ static {
+ ReservedPropNames = new HashMap<String, String>();
+ ReservedPropNames.put("source-of-truth", "");
+ ReservedPropNames.put("last-mod-source-of-truth", "");
+ ReservedPropNames.put("aai-created-ts", "");
+ ReservedPropNames.put("aai-last-mod-ts", "");
+ }
+
+ // This just lists which node types can be connected to themselves recursively.
+ // It's temporary - since DbEdgeRules is going to be overhauled in 16-10, this will
+ // get generated automatically. But for 1607, it can work like this.
+ public static final Map<String, String> CanBeRecursiveNT;
+ static {
+ CanBeRecursiveNT = new HashMap<String, String>();
+ CanBeRecursiveNT.put("model-element", "");
+ CanBeRecursiveNT.put("service-instance", "");
+ CanBeRecursiveNT.put("named-query-element", "");
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResource.java b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResource.java
new file mode 100644
index 00000000..7fc1f7a3
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResource.java
@@ -0,0 +1,675 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.model;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import com.google.common.collect.Multimap;
+
+
+public class AAIResource {
+ private AAIResource parent;
+ private AAIResources children;
+
+ private AAIResourceKeys aaiResourceKeys;
+
+ private String namespace; // /Network/Vces/Vce/PortGroups/PortGroup/CvlanTags/CvlanTag -> "Network"
+
+ private String resourceType; // node or container
+ private String resourceClassName;
+ private String simpleName; // Vce
+ private String fullName; // /Network/Vces/Vce/PortGroups/PortGroup/CvlanTags/CvlanTag
+ private String uri; // /network/vces/vce/{vnf-id}/port-groups/port-group/{interface-name}/cvlan-tags/cvlan-tag/{cvlan-tag}
+ private String apiVersion;
+ private String relationshipListClass;
+ private String relationshipUtils;
+
+ private Map<String, String> PropertyDataTypeMap;
+ private Multimap<String, String> NodeMapIndexedProps;
+ private Multimap<String, String> NodeAltKey1Props;
+ private Multimap<String, String> NodeDependencies;
+ private Multimap<String, String> NodeKeyProps;
+ private Multimap<String, String> NodeReqProps;
+ private Multimap<String, String> NodeNameProps;
+ private Multimap<String, String> NodeUniqueProps;
+
+ // if new dataTypes are added - make sure to update getAllFields() method below
+ private ArrayList<String> stringFields;
+ private ArrayList<String> stringListFields;
+ private ArrayList<String> longFields;
+ private ArrayList<String> intFields;
+ private ArrayList<String> shortFields;
+ private ArrayList<String> booleanFields;
+
+ private ArrayList<String> requiredFields;
+ private ArrayList<String> orderedFields;
+ private AAIResource recurseToResource;
+ private boolean allowDirectWrite;
+ private boolean allowDirectRead;
+ private ArrayList<String> autoGenUuidFields;
+
+ /**
+ * Gets the parent.
+ *
+ * @return the parent
+ */
+ public AAIResource getParent() {
+ return parent;
+ }
+
+ /**
+ * Sets the parent.
+ *
+ * @param parent the new parent
+ */
+ public void setParent(AAIResource parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Gets the children.
+ *
+ * @return the children
+ */
+ public AAIResources getChildren() {
+ if (this.children == null) {
+ this.children = new AAIResources();
+ }
+ return this.children;
+ }
+
+ /**
+ * Gets the aai resource keys.
+ *
+ * @return the aai resource keys
+ */
+ public AAIResourceKeys getAaiResourceKeys() {
+ if (aaiResourceKeys == null) {
+ aaiResourceKeys = new AAIResourceKeys();
+ }
+ return aaiResourceKeys;
+ }
+
+ /**
+ * Gets the namespace.
+ *
+ * @return the namespace
+ */
+ public String getNamespace() {
+ return namespace;
+ }
+
+ /**
+ * Sets the namespace.
+ *
+ * @param namespace the new namespace
+ */
+ public void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ /**
+ * Gets the resource type.
+ *
+ * @return the resource type
+ */
+ public String getResourceType() {
+ return resourceType;
+ }
+
+ /**
+ * Sets the resource type.
+ *
+ * @param resourceType the new resource type
+ */
+ public void setResourceType(String resourceType) {
+ this.resourceType = resourceType;
+ }
+
+ /**
+ * Gets the simple name.
+ *
+ * @return the simple name
+ */
+ public String getSimpleName() {
+ return simpleName;
+ }
+
+ /**
+ * Sets the simple name.
+ *
+ * @param simpleName the new simple name
+ */
+ public void setSimpleName(String simpleName) {
+ this.simpleName = simpleName;
+ }
+
+ /**
+ * Gets the full name.
+ *
+ * @return the full name
+ */
+ public String getFullName() {
+ return fullName;
+ }
+
+ /**
+ * Sets the full name.
+ *
+ * @param fullName the new full name
+ */
+ public void setFullName(String fullName) {
+ this.fullName = fullName;
+ }
+
+ /**
+ * Gets the uri.
+ *
+ * @return the uri
+ */
+ public String getUri() {
+ return uri;
+ }
+
+ /**
+ * Sets the uri.
+ *
+ * @param uri the new uri
+ */
+ public void setUri(String uri) {
+ this.uri = uri;
+ }
+
+ /**
+ * Gets the resource class name.
+ *
+ * @return the resource class name
+ */
+ public String getResourceClassName() {
+ return resourceClassName;
+ }
+
+ /**
+ * Sets the resource class name.
+ *
+ * @param resourceClassName the new resource class name
+ */
+ public void setResourceClassName(String resourceClassName) {
+ this.resourceClassName = resourceClassName;
+ }
+
+ /**
+ * Gets the property data type map.
+ *
+ * @return the property data type map
+ */
+ public Map<String, String> getPropertyDataTypeMap() {
+ return PropertyDataTypeMap;
+ }
+
+ /**
+ * Sets the property data type map.
+ *
+ * @param propertyDataTypeMap the property data type map
+ */
+ public void setPropertyDataTypeMap(Map<String, String> propertyDataTypeMap) {
+ PropertyDataTypeMap = propertyDataTypeMap;
+ }
+
+ /**
+ * Gets the node map indexed props.
+ *
+ * @return the node map indexed props
+ */
+ public Multimap<String, String> getNodeMapIndexedProps() {
+ return NodeMapIndexedProps;
+ }
+
+ /**
+ * Sets the node map indexed props.
+ *
+ * @param nodeMapIndexedProps the node map indexed props
+ */
+ public void setNodeMapIndexedProps(Multimap<String, String> nodeMapIndexedProps) {
+ NodeMapIndexedProps = nodeMapIndexedProps;
+ }
+
+ /**
+ * Gets the node key props.
+ *
+ * @return the node key props
+ */
+ public Multimap<String, String> getNodeKeyProps() {
+ return NodeKeyProps;
+ }
+
+ /**
+ * Sets the node key props.
+ *
+ * @param nodeKeyProps the node key props
+ */
+ public void setNodeKeyProps(Multimap<String, String> nodeKeyProps) {
+ this.NodeKeyProps = nodeKeyProps;
+ }
+
+ /**
+ * Gets the node name props.
+ *
+ * @return the node name props
+ */
+ public Multimap<String, String> getNodeNameProps() {
+ return NodeNameProps;
+ }
+
+ /**
+ * Sets the node name props.
+ *
+ * @param nodeNameProps the node name props
+ */
+ public void setNodeNameProps(Multimap<String, String> nodeNameProps) {
+
+ NodeNameProps = nodeNameProps;
+ }
+
+ /**
+ * Gets the node unique props.
+ *
+ * @return the node unique props
+ */
+ public Multimap<String, String> getNodeUniqueProps() {
+ return NodeUniqueProps;
+ }
+
+ /**
+ * Sets the node unique props.
+ *
+ * @param nodeUniqueProps the node unique props
+ */
+ public void setNodeUniqueProps(Multimap<String, String> nodeUniqueProps) {
+ NodeUniqueProps = nodeUniqueProps;
+ }
+
+ /**
+ * Gets the node req props.
+ *
+ * @return the node req props
+ */
+ public Multimap<String, String> getNodeReqProps() {
+ return NodeReqProps;
+ }
+
+ /**
+ * Sets the node req props.
+ *
+ * @param nodeReqProps the node req props
+ */
+ public void setNodeReqProps(Multimap<String, String> nodeReqProps) {
+ NodeReqProps = nodeReqProps;
+ }
+
+ /**
+ * Gets the api version.
+ *
+ * @return the api version
+ */
+ public String getApiVersion() {
+ return apiVersion;
+ }
+
+ /**
+ * Sets the api version.
+ *
+ * @param apiVersion the new api version
+ */
+ public void setApiVersion(String apiVersion) {
+ this.apiVersion = apiVersion;
+ }
+
+ /**
+ * Gets the relationship list class.
+ *
+ * @return the relationship list class
+ */
+ public String getRelationshipListClass() {
+ return relationshipListClass;
+ }
+
+ /**
+ * Sets the relationship list class.
+ *
+ * @param relationshipListClass the new relationship list class
+ */
+ public void setRelationshipListClass(String relationshipListClass) {
+ this.relationshipListClass = relationshipListClass;
+ }
+
+ /**
+ * Gets the relationship utils.
+ *
+ * @return the relationship utils
+ */
+ public String getRelationshipUtils() {
+ return relationshipUtils;
+ }
+
+ /**
+ * Sets the relationship utils.
+ *
+ * @param relationshipUtils the new relationship utils
+ */
+ public void setRelationshipUtils(String relationshipUtils) {
+ this.relationshipUtils = relationshipUtils;
+ }
+
+ /**
+ * Gets the string fields.
+ *
+ * @return the string fields
+ */
+ public ArrayList<String> getStringFields() {
+ if (this.stringFields == null) {
+ this.stringFields = new ArrayList<String>();
+ }
+ return this.stringFields;
+ }
+
+ /**
+ * Sets the string fields.
+ *
+ * @param stringFields the new string fields
+ */
+ public void setStringFields(ArrayList<String> stringFields) {
+ this.stringFields = stringFields;
+ }
+
+ /**
+ * Gets the string list fields.
+ *
+ * @return the string list fields
+ */
+ public ArrayList<String> getStringListFields() {
+ if (this.stringListFields == null) {
+ this.stringListFields = new ArrayList<String>();
+ }
+ return this.stringListFields;
+ }
+
+ /**
+ * Sets the string list fields.
+ *
+ * @param stringListFields the new string list fields
+ */
+ public void setStringListFields(ArrayList<String> stringListFields) {
+ this.stringListFields = stringListFields;
+ }
+
+ /**
+ * Gets the long fields.
+ *
+ * @return the long fields
+ */
+ public ArrayList<String> getLongFields() {
+ if (this.longFields == null) {
+ this.longFields = new ArrayList<String>();
+ }
+ return longFields;
+ }
+
+ /**
+ * Sets the long fields.
+ *
+ * @param longFields the new long fields
+ */
+ public void setLongFields(ArrayList<String> longFields) {
+ this.longFields = longFields;
+ }
+
+ /**
+ * Gets the int fields.
+ *
+ * @return the int fields
+ */
+ public ArrayList<String> getIntFields() {
+ if (this.intFields == null) {
+ this.intFields = new ArrayList<String>();
+ }
+ return intFields;
+ }
+
+ /**
+ * Sets the int fields.
+ *
+ * @param intFields the new int fields
+ */
+ public void setIntFields(ArrayList<String> intFields) {
+ this.intFields = intFields;
+ }
+
+ /**
+ * Gets the short fields.
+ *
+ * @return the short fields
+ */
+ public ArrayList<String> getShortFields() {
+ if (this.shortFields == null) {
+ this.shortFields = new ArrayList<String>();
+ }
+ return shortFields;
+ }
+
+ /**
+ * Sets the short fields.
+ *
+ * @param shortFields the new short fields
+ */
+ public void setShortFields(ArrayList<String> shortFields) {
+ this.shortFields = shortFields;
+ }
+
+ /**
+ * Gets the boolean fields.
+ *
+ * @return the boolean fields
+ */
+ public ArrayList<String> getBooleanFields() {
+ if (this.booleanFields == null) {
+ this.booleanFields = new ArrayList<String>();
+ }
+ return booleanFields;
+ }
+
+ /**
+ * Sets the boolean fields.
+ *
+ * @param booleanFields the new boolean fields
+ */
+ public void setBooleanFields(ArrayList<String> booleanFields) {
+ this.booleanFields = booleanFields;
+ }
+
+ /**
+ * Gets the required fields.
+ *
+ * @return the required fields
+ */
+ public ArrayList<String> getRequiredFields() {
+ if (this.requiredFields == null) {
+ this.requiredFields = new ArrayList<String>();
+ }
+ return requiredFields;
+ }
+
+ /**
+ * Sets the required fields.
+ *
+ * @param requiredFields the new required fields
+ */
+ public void setRequiredFields(ArrayList<String> requiredFields) {
+ this.requiredFields = requiredFields;
+ }
+
+ /**
+ * Gets the ordered fields.
+ *
+ * @return the ordered fields
+ */
+ public ArrayList<String> getOrderedFields() {
+ if (this.orderedFields == null) {
+ this.orderedFields = new ArrayList<String>();
+ }
+ return this.orderedFields;
+ }
+
+ /**
+ * Gets the all fields.
+ *
+ * @return the all fields
+ */
+ public ArrayList<String> getAllFields() {
+
+ ArrayList<String> allFields = new ArrayList<String>();
+ allFields.addAll(getBooleanFields());
+ allFields.addAll(getStringListFields());
+ allFields.addAll(getStringFields());
+ allFields.addAll(getIntFields());
+ allFields.addAll(getLongFields());
+ allFields.addAll(getShortFields());
+
+ return allFields;
+ }
+
+ /**
+ * Gets the plural name.
+ *
+ * @return the plural name
+ */
+ public String getPluralName() {
+
+ if (simpleName.contains("List") || simpleName.contains("-list") )
+ return "";
+ String[] fullNameList = getFullName().split("/");
+ return fullNameList[fullNameList.length - 2];
+ }
+
+ /**
+ * Sets the node alt key 1 props.
+ *
+ * @param _dbRulesNodeAltKey1Props the db rules node alt key 1 props
+ */
+ public void setNodeAltKey1Props(Multimap<String, String> _dbRulesNodeAltKey1Props) {
+ this.NodeAltKey1Props = _dbRulesNodeAltKey1Props;
+ }
+
+ /**
+ * Gets the node alt key 1 props.
+ *
+ * @return the node alt key 1 props
+ */
+ public Multimap<String,String> getNodeAltKey1Props() {
+ return this.NodeAltKey1Props;
+ }
+
+ /**
+ * Sets the node dependencies.
+ *
+ * @param _dbRulesNodeDependencies the db rules node dependencies
+ */
+ public void setNodeDependencies(Multimap<String, String> _dbRulesNodeDependencies) {
+ this.NodeDependencies = _dbRulesNodeDependencies;
+ }
+
+ /**
+ * Gets the node dependencies.
+ *
+ * @return the node dependencies
+ */
+ public Multimap<String,String> getNodeDependencies() {
+ return this.NodeDependencies;
+ }
+
+ /**
+ * Gets the recurse to resource.
+ *
+ * @return the recurse to resource
+ */
+ public AAIResource getRecurseToResource() {
+ return this.recurseToResource;
+ }
+
+ /**
+ * Sets the recurse to resource.
+ *
+ * @param ancestor the new recurse to resource
+ */
+ public void setRecurseToResource(AAIResource ancestor) {
+ this.recurseToResource = ancestor;
+
+ }
+
+ /**
+ * Sets the allow direct write.
+ *
+ * @param allowDirectWrite the new allow direct write
+ */
+ public void setAllowDirectWrite(boolean allowDirectWrite) {
+ this.allowDirectWrite = allowDirectWrite;
+ }
+
+ /**
+ * Checks if is allow direct write.
+ *
+ * @return true, if is allow direct write
+ */
+ public boolean isAllowDirectWrite() {
+ return this.allowDirectWrite;
+ }
+
+ /**
+ * Sets the allow direct read.
+ *
+ * @param allowDirectRead the new allow direct read
+ */
+ public void setAllowDirectRead(boolean allowDirectRead) {
+ this.allowDirectRead = allowDirectRead;
+ }
+
+ /**
+ * Checks if is allow direct read.
+ *
+ * @return true, if is allow direct read
+ */
+ public boolean isAllowDirectRead() {
+ return this.allowDirectRead;
+ }
+
+ /**
+ * Gets the auto gen uuid fields.
+ *
+ * @return the auto gen uuid fields
+ */
+ public ArrayList<String> getAutoGenUuidFields() {
+ if (this.autoGenUuidFields == null) {
+ this.autoGenUuidFields = new ArrayList<String>();
+ }
+ return this.autoGenUuidFields;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResourceKey.java b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResourceKey.java
new file mode 100644
index 00000000..5129992b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResourceKey.java
@@ -0,0 +1,103 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.model;
+
+import com.google.common.base.CaseFormat;
+
+public class AAIResourceKey {
+ private String keyName;
+ private String keyType;
+ private String pathParamName;
+ private String dnCamKeyName;
+
+ /**
+ * Gets the key name.
+ *
+ * @return the key name
+ */
+ public String getKeyName() {
+ return keyName;
+ }
+
+ /**
+ * Sets the key name.
+ *
+ * @param keyName the new key name
+ */
+ public void setKeyName(String keyName) {
+ this.keyName = keyName;
+ }
+
+ /**
+ * Gets the key type.
+ *
+ * @return the key type
+ */
+ public String getKeyType() {
+ return keyType;
+ }
+
+ /**
+ * Sets the key type.
+ *
+ * @param t the new key type
+ */
+ public void setKeyType(String t) {
+ this.keyType = t;
+ }
+
+ /**
+ * Gets the path param name.
+ *
+ * @return the path param name
+ */
+ public String getPathParamName() {
+ return pathParamName;
+ }
+
+ /**
+ * Sets the path param name.
+ *
+ * @param pathParamName the new path param name
+ */
+ public void setPathParamName(String pathParamName) {
+ this.pathParamName = pathParamName;
+ }
+
+ /**
+ * Gets the dn cam key name.
+ *
+ * @return the dn cam key name
+ */
+ public String getDnCamKeyName() {
+ return dnCamKeyName;
+ }
+
+ /**
+ * Sets the dn cam key name.
+ *
+ * @param dnCamKeyName the new dn cam key name
+ */
+ public void setDnCamKeyName(String dnCamKeyName) {
+ this.dnCamKeyName = dnCamKeyName;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResourceKeys.java b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResourceKeys.java
new file mode 100644
index 00000000..2aa752c8
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResourceKeys.java
@@ -0,0 +1,40 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AAIResourceKeys {
+ private List<AAIResourceKey> aaiResourceKey;
+
+ /**
+ * Gets the aai resource key.
+ *
+ * @return the aai resource key
+ */
+ public List<AAIResourceKey> getAaiResourceKey() {
+ if (aaiResourceKey == null) {
+ aaiResourceKey = new ArrayList<AAIResourceKey>();
+ }
+ return aaiResourceKey;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResources.java b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResources.java
new file mode 100644
index 00000000..6aff26e8
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/model/AAIResources.java
@@ -0,0 +1,86 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.model;
+
+import java.util.HashMap;
+
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+
+public class AAIResources {
+
+ private DynamicJAXBContext jaxbContext;
+
+ private HashMap<String, AAIResource> aaiResources;
+ private HashMap<String, AAIResource> resourceLookup;
+
+
+ /**
+ * Gets the aai resources.
+ *
+ * @return the aai resources
+ */
+ public HashMap<String, AAIResource> getAaiResources() {
+ if (aaiResources == null) {
+ aaiResources = new HashMap<String, AAIResource>();
+ }
+ return aaiResources;
+ }
+
+ /**
+ * Gets the jaxb context.
+ *
+ * @return the jaxb context
+ */
+ public DynamicJAXBContext getJaxbContext() {
+ return jaxbContext;
+ }
+
+ /**
+ * Sets the jaxb context.
+ *
+ * @param jaxbContext the new jaxb context
+ */
+ public void setJaxbContext(DynamicJAXBContext jaxbContext) {
+ this.jaxbContext = jaxbContext;
+ }
+
+ /**
+ * Gets the resource lookup.
+ *
+ * @return the resource lookup
+ */
+ public HashMap<String, AAIResource> getResourceLookup() {
+ if (resourceLookup == null) {
+ resourceLookup = new HashMap<String, AAIResource>();
+ }
+ return resourceLookup;
+ }
+
+ /**
+ * Sets the resource lookup.
+ *
+ * @param resourceLookup the resource lookup
+ */
+ public void setResourceLookup(HashMap<String, AAIResource> resourceLookup) {
+ this.resourceLookup = resourceLookup;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/notificationEvent/NotificationEvent.java b/aai-core/src/main/java/org/openecomp/aai/domain/notificationEvent/NotificationEvent.java
new file mode 100644
index 00000000..18585518
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/notificationEvent/NotificationEvent.java
@@ -0,0 +1,564 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2016.01.06 at 05:38:00 PM EST
+//
+
+
+package org.openecomp.aai.domain.notificationEvent;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAnyElement;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.w3c.dom.Element;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="cambria.partition" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="event-header" minOccurs="0">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="id" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="timestamp" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="source-name" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="domain" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="sequence-number" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="severity" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="event-type" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="version" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="action" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="entity-type" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="top-entity-type" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="entity-link" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="status" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;any processContents='lax' namespace='##other' minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "cambriaPartition",
+ "eventHeader",
+ "entity"
+})
+@XmlRootElement(name = "NotificationEvent")
+public class NotificationEvent {
+
+ @XmlElement(name = "cambria.partition")
+ protected String cambriaPartition;
+ @XmlElement(name = "event-header")
+ protected NotificationEvent.EventHeader eventHeader;
+ @XmlAnyElement(lax = true)
+ protected Object entity;
+
+ /**
+ * Gets the value of the eventHeader property.
+ *
+ * @return
+ * possible object is
+ * {@link NotificationEvent.EventHeader }
+ *
+ */
+ public NotificationEvent.EventHeader getEventHeader() {
+ return eventHeader;
+ }
+
+ /**
+ * Sets the value of the eventHeader property.
+ *
+ * @param value
+ * allowed object is
+ * {@link NotificationEvent.EventHeader }
+ *
+ */
+ public void setEventHeader(NotificationEvent.EventHeader value) {
+ this.eventHeader = value;
+ }
+
+ /**
+ * Gets the value of the any property.
+ *
+ * @return
+ * possible object is
+ * {@link Object }
+ * {@link Element }
+ *
+ */
+ public Object getEntity() {
+ return entity;
+ }
+
+ /**
+ * Sets the value of the any property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Object }
+ * {@link Element }
+ *
+ */
+ public void setEntity(Object value) {
+ this.entity = value;
+ }
+
+ /**
+ * Gets the value of the cambriaPartition property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getCambriaPartition() {
+ return cambriaPartition;
+ }
+
+ /**
+ * Sets the value of the cambriaPartition property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setCambriaPartition(String value) {
+ this.cambriaPartition = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="id" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="timestamp" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="source-name" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="domain" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="sequence-number" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="severity" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="event-type" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="version" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="action" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="entity-type" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="top-entity-type" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="entity-link" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="status" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "id",
+ "timestamp",
+ "sourceName",
+ "domain",
+ "sequenceNumber",
+ "severity",
+ "eventType",
+ "version",
+ "action",
+ "entityType",
+ "topEntityType",
+ "entityLink",
+ "status"
+ })
+ public static class EventHeader {
+
+ @XmlElement(required = true)
+ protected String id;
+ @XmlElement(required = true)
+ protected String timestamp;
+ @XmlElement(name = "source-name", required = true)
+ protected String sourceName;
+ @XmlElement(required = true)
+ protected String domain;
+ @XmlElement(name = "sequence-number", required = true)
+ protected String sequenceNumber;
+ @XmlElement(required = true)
+ protected String severity;
+ @XmlElement(name = "event-type", required = true)
+ protected String eventType;
+ @XmlElement(required = true)
+ protected String version;
+ @XmlElement(required = true)
+ protected String action;
+ @XmlElement(name = "entity-type", required = true)
+ protected String entityType;
+ @XmlElement(name = "top-entity-type", required = true)
+ protected String topEntityType;
+ @XmlElement(name = "entity-link", required = true)
+ protected String entityLink;
+ @XmlElement(required = true)
+ protected String status;
+
+ /**
+ * Gets the value of the id property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+ /**
+ * Gets the value of the timestamp property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getTimestamp() {
+ return timestamp;
+ }
+
+ /**
+ * Sets the value of the timestamp property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setTimestamp(String value) {
+ this.timestamp = value;
+ }
+
+ /**
+ * Gets the value of the sourceName property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getSourceName() {
+ return sourceName;
+ }
+
+ /**
+ * Sets the value of the sourceName property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setSourceName(String value) {
+ this.sourceName = value;
+ }
+
+ /**
+ * Gets the value of the domain property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getDomain() {
+ return domain;
+ }
+
+ /**
+ * Sets the value of the domain property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setDomain(String value) {
+ this.domain = value;
+ }
+
+ /**
+ * Gets the value of the sequenceNumber property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getSequenceNumber() {
+ return sequenceNumber;
+ }
+
+ /**
+ * Sets the value of the sequenceNumber property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setSequenceNumber(String value) {
+ this.sequenceNumber = value;
+ }
+
+ /**
+ * Gets the value of the severity property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getSeverity() {
+ return severity;
+ }
+
+ /**
+ * Sets the value of the severity property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setSeverity(String value) {
+ this.severity = value;
+ }
+
+ /**
+ * Gets the value of the eventType property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getEventType() {
+ return eventType;
+ }
+
+ /**
+ * Sets the value of the eventType property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setEventType(String value) {
+ this.eventType = value;
+ }
+
+ /**
+ * Gets the value of the version property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * Sets the value of the version property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setVersion(String value) {
+ this.version = value;
+ }
+
+ /**
+ * Gets the value of the action property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getAction() {
+ return action;
+ }
+
+ /**
+ * Sets the value of the action property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setAction(String value) {
+ this.action = value;
+ }
+
+ /**
+ * Gets the value of the entityType property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getEntityType() {
+ return entityType;
+ }
+
+ /**
+ * Sets the value of the entityType property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setEntityType(String value) {
+ this.entityType = value;
+ }
+
+ /**
+ * Gets the value of the topEntityType property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getTopEntityType() {
+ return topEntityType;
+ }
+
+ /**
+ * Sets the value of the topEntityType property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setTopEntityType(String value) {
+ this.topEntityType = value;
+ }
+
+ /**
+ * Gets the value of the entityLink property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getEntityLink() {
+ return entityLink;
+ }
+
+ /**
+ * Sets the value of the entityLink property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setEntityLink(String value) {
+ this.entityLink = value;
+ }
+
+ /**
+ * Gets the value of the status property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getStatus() {
+ return status;
+ }
+
+ /**
+ * Sets the value of the status property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setStatus(String value) {
+ this.status = value;
+ }
+
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/notificationEvent/ObjectFactory.java b/aai-core/src/main/java/org/openecomp/aai/domain/notificationEvent/ObjectFactory.java
new file mode 100644
index 00000000..c8bfab89
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/notificationEvent/ObjectFactory.java
@@ -0,0 +1,77 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2016.01.06 at 05:38:00 PM EST
+//
+
+
+package org.openecomp.aai.domain.notificationEvent;
+
+import javax.xml.bind.annotation.XmlRegistry;
+
+
+/**
+ * This object contains factory methods for each
+ * Java content interface and Java element interface
+ * generated in the org.openecomp.aai.domain.notificationEvent package.
+ * <p>An ObjectFactory allows you to programatically
+ * construct new instances of the Java representation
+ * for XML content. The Java representation of XML
+ * content can consist of schema derived interfaces
+ * and classes representing the binding of schema
+ * type definitions, element declarations and model
+ * groups. Factory methods for each of these are
+ * provided in this class.
+ *
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.openecomp.aai.domain.notificationEvent
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link NotificationEvent }.
+ *
+ * @return the notification event
+ */
+ public NotificationEvent createNotificationEvent() {
+ return new NotificationEvent();
+ }
+
+ /**
+ * Create an instance of {@link NotificationEvent.EventHeader }
+ *
+ * @return the event header
+ */
+ public NotificationEvent.EventHeader createNotificationEventEventHeader() {
+ return new NotificationEvent.EventHeader();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessage.java b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessage.java
new file mode 100644
index 00000000..5cbe3167
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessage.java
@@ -0,0 +1,125 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.responseMessage;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "aaiResponseMessageCode",
+ "aaiResponseMessageResourceType",
+ "aaiResponseMessageDescription",
+ "aaiResponseMessageData",
+})
+@XmlRootElement(name = "aai-response-message", namespace = "http://org.openecomp.aai.inventory")
+public class AAIResponseMessage {
+
+ @XmlElement(name = "aai-response-message-code", required = true)
+ protected String aaiResponseMessageCode;
+ @XmlElement(name = "aai-response-message-resource-type")
+ protected String aaiResponseMessageResourceType;
+ @XmlElement(name = "aai-response-message-description")
+ protected String aaiResponseMessageDescription;
+ @XmlElement(name = "aai-response-message-data")
+ protected AAIResponseMessageData aaiResponseMessageData;
+
+ /**
+ * Gets the aai response message code.
+ *
+ * @return the aai response message code
+ */
+ public String getAaiResponseMessageCode() {
+ return aaiResponseMessageCode;
+ }
+
+ /**
+ * Sets the aai response message code.
+ *
+ * @param aaiResponseMessageCode the new aai response message code
+ */
+ public void setAaiResponseMessageCode(String aaiResponseMessageCode) {
+ this.aaiResponseMessageCode = aaiResponseMessageCode;
+ }
+
+ /**
+ * Gets the aai response message resource type.
+ *
+ * @return the aai response message resource type
+ */
+ public String getAaiResponseMessageResourceType() {
+ return aaiResponseMessageResourceType;
+ }
+
+ /**
+ * Sets the aai response message resource type.
+ *
+ * @param aaiResponseMessageResourceType the new aai response message resource type
+ */
+ public void setAaiResponseMessageResourceType(
+ String aaiResponseMessageResourceType) {
+ this.aaiResponseMessageResourceType = aaiResponseMessageResourceType;
+ }
+
+ /**
+ * Gets the aai response message description.
+ *
+ * @return the aai response message description
+ */
+ public String getAaiResponseMessageDescription() {
+ return aaiResponseMessageDescription;
+ }
+
+ /**
+ * Sets the aai response message description.
+ *
+ * @param aaiResponseMessageDescription the new aai response message description
+ */
+ public void setAaiResponseMessageDescription(
+ String aaiResponseMessageDescription) {
+ this.aaiResponseMessageDescription = aaiResponseMessageDescription;
+ }
+
+ /**
+ * Gets the aai response message data.
+ *
+ * @return the aai response message data
+ */
+ public AAIResponseMessageData getAaiResponseMessageData() {
+ if (aaiResponseMessageData == null) {
+ aaiResponseMessageData = new AAIResponseMessageData();
+ }
+ return aaiResponseMessageData;
+ }
+
+ /**
+ * Sets the AAI response message data.
+ *
+ * @param aaiResponseMessageData the new AAI response message data
+ */
+ public void setAAIResponseMessageData(
+ AAIResponseMessageData aaiResponseMessageData) {
+ this.aaiResponseMessageData = aaiResponseMessageData;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessageData.java b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessageData.java
new file mode 100644
index 00000000..2f16b98a
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessageData.java
@@ -0,0 +1,78 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.responseMessage;
+
+
+//
+//This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+//See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
+//Any modifications to this file will be lost upon recompilation of the source schema.
+//Generated on: 2015.09.11 at 11:53:27 AM EDT
+//
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAnyElement;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "aaiResponseMessageDatum",
+ "any"
+})
+@XmlRootElement(name = "aai-response-message-data", namespace = "http://org.openecomp.aai.inventory")
+public class AAIResponseMessageData {
+
+ @XmlElement(name = "aai-response-message-datum")
+ protected List<AAIResponseMessageDatum> aaiResponseMessageDatum;
+ @XmlAnyElement(lax = true)
+ protected List<Object> any;
+
+ /**
+ * Gets the AAI response message datum.
+ *
+ * @return the AAI response message datum
+ */
+ public List<AAIResponseMessageDatum> getAAIResponseMessageDatum() {
+ if (aaiResponseMessageDatum == null) {
+ aaiResponseMessageDatum = new ArrayList<AAIResponseMessageDatum>();
+ }
+ return this.aaiResponseMessageDatum;
+ }
+
+ /**
+ * Gets the any.
+ *
+ * @return the any
+ */
+ public List<Object> getAny() {
+ if (any == null) {
+ any = new ArrayList<Object>();
+ }
+ return this.any;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessageDatum.java b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessageDatum.java
new file mode 100644
index 00000000..9e56333d
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessageDatum.java
@@ -0,0 +1,81 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.responseMessage;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "aaiResponseMessageDatumKey",
+ "aaiResponseMessageDatumValue",
+
+})
+
+@XmlRootElement(name = "aai-response-message-datum", namespace = "http://org.openecomp.aai.inventory")
+public class AAIResponseMessageDatum {
+
+ @XmlElement(name = "aai-response-message-datum-key", required = true)
+ protected String aaiResponseMessageDatumKey;
+ @XmlElement(name = "aai-response-message-datum-value", required = true)
+ protected String aaiResponseMessageDatumValue;
+
+ /**
+ * Gets the aai response message datum key.
+ *
+ * @return the aai response message datum key
+ */
+ public String getAaiResponseMessageDatumKey() {
+ return aaiResponseMessageDatumKey;
+ }
+
+ /**
+ * Sets the aai response message datum key.
+ *
+ * @param aaiResponseMessageDatumKey the new aai response message datum key
+ */
+ public void setAaiResponseMessageDatumKey(String aaiResponseMessageDatumKey) {
+ this.aaiResponseMessageDatumKey = aaiResponseMessageDatumKey;
+ }
+
+ /**
+ * Gets the aai response message datum value.
+ *
+ * @return the aai response message datum value
+ */
+ public String getAaiResponseMessageDatumValue() {
+ return aaiResponseMessageDatumValue;
+ }
+
+ /**
+ * Sets the aai response message datum value.
+ *
+ * @param aaiResponseMessageDatumValue the new aai response message datum value
+ */
+ public void setAaiResponseMessageDatumValue(String aaiResponseMessageDatumValue) {
+ this.aaiResponseMessageDatumValue = aaiResponseMessageDatumValue;
+ }
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessages.java b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessages.java
new file mode 100644
index 00000000..ec6d645d
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/AAIResponseMessages.java
@@ -0,0 +1,118 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.responseMessage;
+
+
+//
+//This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+//See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
+//Any modifications to this file will be lost upon recompilation of the source schema.
+//Generated on: 2015.09.11 at 11:53:27 AM EDT
+//
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAnyElement;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="flavor" maxOccurs="unbounded" minOccurs="0">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="flavor-id" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="flavor-name" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ * &lt;element name="flavor-vcpus" type="{http://www.w3.org/2001/XMLSchema}short" minOccurs="0"/>
+ * &lt;element name="flavor-ram" type="{http://www.w3.org/2001/XMLSchema}short" minOccurs="0"/>
+ * &lt;element name="flavor-disk" type="{http://www.w3.org/2001/XMLSchema}short" minOccurs="0"/>
+ * &lt;element name="flavor-ephemeral" type="{http://www.w3.org/2001/XMLSchema}short" minOccurs="0"/>
+ * &lt;element name="flavor-swap" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ * &lt;element name="flavor-is-public" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/>
+ * &lt;element name="flavor-selflink" type="{urn:ietf:params:xml:ns:yang:ietf-inet-types}uri" minOccurs="0"/>
+ * &lt;element name="flavor-disabled" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/>
+ * &lt;any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;element ref="{http://org.openecomp.aai.inventory/v3}relationship-list" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "aaiResponseMessage",
+ "any"
+})
+@XmlRootElement(name = "aai-response-messages", namespace = "http://org.openecomp.aai.inventory")
+public class AAIResponseMessages {
+ @XmlElement(name = "aai-response-message")
+ protected List<AAIResponseMessage> aaiResponseMessage;
+ @XmlAnyElement(lax = true)
+ protected List<Object> any;
+
+ /**
+ * Gets the AAI response message.
+ *
+ * @return the AAI response message
+ */
+ public List<AAIResponseMessage> getAAIResponseMessage() {
+ if (aaiResponseMessage == null) {
+ aaiResponseMessage = new ArrayList<AAIResponseMessage>();
+ }
+ return this.aaiResponseMessage;
+ }
+
+ /**
+ * Gets the any.
+ *
+ * @return the any
+ */
+ public List<Object> getAny() {
+ if (any == null) {
+ any = new ArrayList<Object>();
+ }
+ return this.any;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/package-info.java b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/package-info.java
new file mode 100644
index 00000000..0c024ff2
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/responseMessage/package-info.java
@@ -0,0 +1,32 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2015.06.15 at 03:03:58 PM EDT
+//
+
+@javax.xml.bind.annotation.XmlSchema(
+ namespace = "http://org.openecomp.aai.inventory",
+ elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+package org.openecomp.aai.domain.responseMessage;
+
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/Fault.java b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/Fault.java
new file mode 100644
index 00000000..68281cf6
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/Fault.java
@@ -0,0 +1,382 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2015.02.11 at 04:54:39 PM EST
+//
+
+
+package org.openecomp.aai.domain.restPolicyException;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="requestError">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="policyException">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="variables">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "requestError"
+})
+@XmlRootElement(name = "Fault")
+public class Fault {
+
+ @XmlElement(required = true)
+ protected Fault.RequestError requestError;
+
+ /**
+ * Gets the value of the requestError property.
+ *
+ * @return
+ * possible object is
+ * {@link Fault.RequestError }
+ *
+ */
+ public Fault.RequestError getRequestError() {
+ return requestError;
+ }
+
+ /**
+ * Sets the value of the requestError property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Fault.RequestError }
+ *
+ */
+ public void setRequestError(Fault.RequestError value) {
+ this.requestError = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="policyException">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="variables">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "policyException"
+ })
+ public static class RequestError {
+
+ @XmlElement(required = true)
+ protected Fault.RequestError.PolicyException policyException;
+
+ /**
+ * Gets the value of the policyException property.
+ *
+ * @return
+ * possible object is
+ * {@link Fault.RequestError.PolicyException }
+ *
+ */
+ public Fault.RequestError.PolicyException getPolicyException() {
+ return policyException;
+ }
+
+ /**
+ * Sets the value of the policyException property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Fault.RequestError.PolicyException }
+ *
+ */
+ public void setPolicyException(Fault.RequestError.PolicyException value) {
+ this.policyException = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="variables">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "messageId",
+ "text",
+ "variables"
+ })
+ public static class PolicyException {
+
+ @XmlElement(required = true)
+ protected String messageId;
+ @XmlElement(required = true)
+ protected String text;
+ @XmlElement(required = true)
+ protected Fault.RequestError.PolicyException.Variables variables;
+
+ /**
+ * Gets the value of the messageId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getMessageId() {
+ return messageId;
+ }
+
+ /**
+ * Sets the value of the messageId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setMessageId(String value) {
+ this.messageId = value;
+ }
+
+ /**
+ * Gets the value of the text property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * Sets the value of the text property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setText(String value) {
+ this.text = value;
+ }
+
+ /**
+ * Gets the value of the variables property.
+ *
+ * @return
+ * possible object is
+ * {@link Fault.RequestError.PolicyException.Variables }
+ *
+ */
+ public Fault.RequestError.PolicyException.Variables getVariables() {
+ return variables;
+ }
+
+ /**
+ * Sets the value of the variables property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Fault.RequestError.PolicyException.Variables }
+ *
+ */
+ public void setVariables(Fault.RequestError.PolicyException.Variables value) {
+ this.variables = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "variable"
+ })
+ public static class Variables {
+
+ protected List<String> variable;
+
+ /**
+ * Gets the value of the variable property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the variable property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getVariable().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link String }
+ *
+ * @return the variable
+ */
+ public List<String> getVariable() {
+ if (variable == null) {
+ variable = new ArrayList<String>();
+ }
+ return this.variable;
+ }
+
+ }
+
+ }
+
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/ObjectFactory.java b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/ObjectFactory.java
new file mode 100644
index 00000000..3d3cffe2
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/ObjectFactory.java
@@ -0,0 +1,95 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2015.02.11 at 04:54:39 PM EST
+//
+
+
+package org.openecomp.aai.domain.restPolicyException;
+
+import javax.xml.bind.annotation.XmlRegistry;
+
+
+/**
+ * This object contains factory methods for each
+ * Java content interface and Java element interface
+ * generated in the org.openecomp.aai.domain.restPolicyException package.
+ * <p>An ObjectFactory allows you to programatically
+ * construct new instances of the Java representation
+ * for XML content. The Java representation of XML
+ * content can consist of schema derived interfaces
+ * and classes representing the binding of schema
+ * type definitions, element declarations and model
+ * groups. Factory methods for each of these are
+ * provided in this class.
+ *
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.openecomp.aai.domain.restPolicyException
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link Fault }.
+ *
+ * @return the fault
+ */
+ public Fault createFault() {
+ return new Fault();
+ }
+
+ /**
+ * Create an instance of {@link Fault.RequestError }
+ *
+ * @return the request error
+ */
+ public Fault.RequestError createFaultRequestError() {
+ return new Fault.RequestError();
+ }
+
+ /**
+ * Create an instance of {@link Fault.RequestError.PolicyException }
+ *
+ * @return the policy exception
+ */
+ public Fault.RequestError.PolicyException createFaultRequestErrorPolicyException() {
+ return new Fault.RequestError.PolicyException();
+ }
+
+ /**
+ * Create an instance of {@link Fault.RequestError.PolicyException.Variables }
+ *
+ * @return the variables
+ */
+ public Fault.RequestError.PolicyException.Variables createFaultRequestErrorPolicyExceptionVariables() {
+ return new Fault.RequestError.PolicyException.Variables();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/PolicyException.java b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/PolicyException.java
new file mode 100644
index 00000000..b0e427bb
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/PolicyException.java
@@ -0,0 +1,134 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.restPolicyException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Generated;
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Generated("org.jsonschema2pojo")
+@JsonPropertyOrder({
+ "messageId",
+ "text",
+ "variables"
+})
+public class PolicyException {
+
+ @JsonProperty("messageId")
+ private String messageId;
+ @JsonProperty("text")
+ private String text;
+ @JsonProperty("variables")
+ private List<String> variables = new ArrayList<String>();
+ @JsonIgnore
+ private Map<String, Object> additionalProperties = new HashMap<String, Object>();
+
+ /**
+ * Gets the message id.
+ *
+ * @return The messageId
+ */
+ @JsonProperty("messageId")
+ public String getMessageId() {
+ return messageId;
+ }
+
+ /**
+ * Sets the message id.
+ *
+ * @param messageId The messageId
+ */
+ @JsonProperty("messageId")
+ public void setMessageId(String messageId) {
+ this.messageId = messageId;
+ }
+
+ /**
+ * Gets the text.
+ *
+ * @return The text
+ */
+ @JsonProperty("text")
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * Sets the text.
+ *
+ * @param text The text
+ */
+ @JsonProperty("text")
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ /**
+ * Gets the variables.
+ *
+ * @return The variables
+ */
+ @JsonProperty("variables")
+ public List<String> getVariables() {
+ return variables;
+ }
+
+ /**
+ * Sets the variables.
+ *
+ * @param variables The variables
+ */
+ @JsonProperty("variables")
+ public void setVariables(List<String> variables) {
+ this.variables = variables;
+ }
+
+ /**
+ * Gets the additional properties.
+ *
+ * @return the additional properties
+ */
+ @JsonAnyGetter
+ public Map<String, Object> getAdditionalProperties() {
+ return this.additionalProperties;
+ }
+
+ /**
+ * Sets the additional property.
+ *
+ * @param name the name
+ * @param value the value
+ */
+ @JsonAnySetter
+ public void setAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/RESTResponse.java b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/RESTResponse.java
new file mode 100644
index 00000000..bf929e8c
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/RESTResponse.java
@@ -0,0 +1,86 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.restPolicyException;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Generated;
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Generated("org.jsonschema2pojo")
+@JsonPropertyOrder({
+ "requestError"
+})
+public class RESTResponse {
+
+ @JsonProperty("requestError")
+ private RequestError requestError;
+ @JsonIgnore
+ private Map<String, Object> additionalProperties = new HashMap<String, Object>();
+
+ /**
+ * Gets the request error.
+ *
+ * @return The requestError
+ */
+ @JsonProperty("requestError")
+ public RequestError getRequestError() {
+ return requestError;
+ }
+
+ /**
+ * Sets the request error.
+ *
+ * @param requestError The requestError
+ */
+ @JsonProperty("requestError")
+ public void setRequestError(RequestError requestError) {
+ this.requestError = requestError;
+ }
+
+ /**
+ * Gets the additional properties.
+ *
+ * @return the additional properties
+ */
+ @JsonAnyGetter
+ public Map<String, Object> getAdditionalProperties() {
+ return this.additionalProperties;
+ }
+
+ /**
+ * Sets the additional property.
+ *
+ * @param name the name
+ * @param value the value
+ */
+ @JsonAnySetter
+ public void setAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/RequestError.java b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/RequestError.java
new file mode 100644
index 00000000..ebbb8984
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/restPolicyException/RequestError.java
@@ -0,0 +1,87 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.restPolicyException;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Generated;
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Generated("org.jsonschema2pojo")
+@JsonPropertyOrder({
+ "policyException"
+})
+public class RequestError {
+
+ @JsonProperty("policyException")
+ private PolicyException policyException;
+ @JsonIgnore
+ private Map<String, Object> additionalProperties = new HashMap<String, Object>();
+
+ /**
+ * Gets the policy exception.
+ *
+ * @return The policyException
+ */
+ @JsonProperty("policyException")
+ public PolicyException getPolicyException() {
+ return policyException;
+ }
+
+ /**
+ * Sets the policy exception.
+ *
+ * @param policyException The policyException
+ */
+ @JsonProperty("policyException")
+ public void setPolicyException(PolicyException policyException) {
+ this.policyException = policyException;
+ }
+
+ /**
+ * Gets the additional properties.
+ *
+ * @return the additional properties
+ */
+ @JsonAnyGetter
+ public Map<String, Object> getAdditionalProperties() {
+ return this.additionalProperties;
+ }
+
+ /**
+ * Sets the additional property.
+ *
+ * @param name the name
+ * @param value the value
+ */
+ @JsonAnySetter
+ public void setAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ }
+
+}
+
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restResponseInfo/Info.java b/aai-core/src/main/java/org/openecomp/aai/domain/restResponseInfo/Info.java
new file mode 100644
index 00000000..a91fdb5b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/restResponseInfo/Info.java
@@ -0,0 +1,385 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2015.10.28 at 05:53:17 PM EDT
+//
+
+
+package org.openecomp.aai.domain.restResponseInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="responseMessages" minOccurs="0">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="responseMessage" maxOccurs="unbounded" minOccurs="0">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="variables">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "responseMessages"
+})
+@XmlRootElement(name = "Info")
+public class Info {
+
+ protected Info.ResponseMessages responseMessages;
+
+ /**
+ * Gets the value of the responseMessages property.
+ *
+ * @return
+ * possible object is
+ * {@link Info.ResponseMessages }
+ *
+ */
+ public Info.ResponseMessages getResponseMessages() {
+ return responseMessages;
+ }
+
+ /**
+ * Sets the value of the responseMessages property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Info.ResponseMessages }
+ *
+ */
+ public void setResponseMessages(Info.ResponseMessages value) {
+ this.responseMessages = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="responseMessage" maxOccurs="unbounded" minOccurs="0">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="variables">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "responseMessage"
+ })
+ public static class ResponseMessages {
+
+ protected List<Info.ResponseMessages.ResponseMessage> responseMessage;
+
+ /**
+ * Gets the value of the responseMessage property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the responseMessage property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getResponseMessage().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link Info.ResponseMessages.ResponseMessage }
+ *
+ * @return the response message
+ */
+ public List<Info.ResponseMessages.ResponseMessage> getResponseMessage() {
+ if (responseMessage == null) {
+ responseMessage = new ArrayList<Info.ResponseMessages.ResponseMessage>();
+ }
+ return this.responseMessage;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="variables">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "messageId",
+ "text",
+ "variables"
+ })
+ public static class ResponseMessage {
+
+ @XmlElement(required = true)
+ protected String messageId;
+ @XmlElement(required = true)
+ protected String text;
+ @XmlElement(required = true)
+ protected Info.ResponseMessages.ResponseMessage.Variables variables;
+
+ /**
+ * Gets the value of the messageId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getMessageId() {
+ return messageId;
+ }
+
+ /**
+ * Sets the value of the messageId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setMessageId(String value) {
+ this.messageId = value;
+ }
+
+ /**
+ * Gets the value of the text property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * Sets the value of the text property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setText(String value) {
+ this.text = value;
+ }
+
+ /**
+ * Gets the value of the variables property.
+ *
+ * @return
+ * possible object is
+ * {@link Info.ResponseMessages.ResponseMessage.Variables }
+ *
+ */
+ public Info.ResponseMessages.ResponseMessage.Variables getVariables() {
+ return variables;
+ }
+
+ /**
+ * Sets the value of the variables property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Info.ResponseMessages.ResponseMessage.Variables }
+ *
+ */
+ public void setVariables(Info.ResponseMessages.ResponseMessage.Variables value) {
+ this.variables = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "variable"
+ })
+ public static class Variables {
+
+ protected List<String> variable;
+
+ /**
+ * Gets the value of the variable property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the variable property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getVariable().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link String }
+ *
+ * @return the variable
+ */
+ public List<String> getVariable() {
+ if (variable == null) {
+ variable = new ArrayList<String>();
+ }
+ return this.variable;
+ }
+
+ }
+
+ }
+
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restResponseInfo/ObjectFactory.java b/aai-core/src/main/java/org/openecomp/aai/domain/restResponseInfo/ObjectFactory.java
new file mode 100644
index 00000000..c964cd59
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/restResponseInfo/ObjectFactory.java
@@ -0,0 +1,95 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2015.10.28 at 05:53:17 PM EDT
+//
+
+
+package org.openecomp.aai.domain.restResponseInfo;
+
+import javax.xml.bind.annotation.XmlRegistry;
+
+
+/**
+ * This object contains factory methods for each
+ * Java content interface and Java element interface
+ * generated in the org.openecomp.aai.domain.restResponseInfo package.
+ * <p>An ObjectFactory allows you to programatically
+ * construct new instances of the Java representation
+ * for XML content. The Java representation of XML
+ * content can consist of schema derived interfaces
+ * and classes representing the binding of schema
+ * type definitions, element declarations and model
+ * groups. Factory methods for each of these are
+ * provided in this class.
+ *
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.openecomp.aai.domain.restResponseInfo
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link Info }.
+ *
+ * @return the info
+ */
+ public Info createInfo() {
+ return new Info();
+ }
+
+ /**
+ * Create an instance of {@link Info.ResponseMessages }
+ *
+ * @return the response messages
+ */
+ public Info.ResponseMessages createInfoResponseMessages() {
+ return new Info.ResponseMessages();
+ }
+
+ /**
+ * Create an instance of {@link Info.ResponseMessages.ResponseMessage }
+ *
+ * @return the response message
+ */
+ public Info.ResponseMessages.ResponseMessage createInfoResponseMessagesResponseMessage() {
+ return new Info.ResponseMessages.ResponseMessage();
+ }
+
+ /**
+ * Create an instance of {@link Info.ResponseMessages.ResponseMessage.Variables }
+ *
+ * @return the variables
+ */
+ public Info.ResponseMessages.ResponseMessage.Variables createInfoResponseMessagesResponseMessageVariables() {
+ return new Info.ResponseMessages.ResponseMessage.Variables();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/Fault.java b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/Fault.java
new file mode 100644
index 00000000..639a5cff
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/Fault.java
@@ -0,0 +1,382 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2015.02.11 at 04:54:29 PM EST
+//
+
+
+package org.openecomp.aai.domain.restServiceException;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="requestError">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="serviceException">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="variables">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "requestError"
+})
+@XmlRootElement(name = "Fault")
+public class Fault {
+
+ @XmlElement(required = true)
+ protected Fault.RequestError requestError;
+
+ /**
+ * Gets the value of the requestError property.
+ *
+ * @return
+ * possible object is
+ * {@link Fault.RequestError }
+ *
+ */
+ public Fault.RequestError getRequestError() {
+ return requestError;
+ }
+
+ /**
+ * Sets the value of the requestError property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Fault.RequestError }
+ *
+ */
+ public void setRequestError(Fault.RequestError value) {
+ this.requestError = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="serviceException">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="variables">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "serviceException"
+ })
+ public static class RequestError {
+
+ @XmlElement(required = true)
+ protected Fault.RequestError.ServiceException serviceException;
+
+ /**
+ * Gets the value of the serviceException property.
+ *
+ * @return
+ * possible object is
+ * {@link Fault.RequestError.ServiceException }
+ *
+ */
+ public Fault.RequestError.ServiceException getServiceException() {
+ return serviceException;
+ }
+
+ /**
+ * Sets the value of the serviceException property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Fault.RequestError.ServiceException }
+ *
+ */
+ public void setServiceException(Fault.RequestError.ServiceException value) {
+ this.serviceException = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="variables">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "messageId",
+ "text",
+ "variables"
+ })
+ public static class ServiceException {
+
+ @XmlElement(required = true)
+ protected String messageId;
+ @XmlElement(required = true)
+ protected String text;
+ @XmlElement(required = true)
+ protected Fault.RequestError.ServiceException.Variables variables;
+
+ /**
+ * Gets the value of the messageId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getMessageId() {
+ return messageId;
+ }
+
+ /**
+ * Sets the value of the messageId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setMessageId(String value) {
+ this.messageId = value;
+ }
+
+ /**
+ * Gets the value of the text property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * Sets the value of the text property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setText(String value) {
+ this.text = value;
+ }
+
+ /**
+ * Gets the value of the variables property.
+ *
+ * @return
+ * possible object is
+ * {@link Fault.RequestError.ServiceException.Variables }
+ *
+ */
+ public Fault.RequestError.ServiceException.Variables getVariables() {
+ return variables;
+ }
+
+ /**
+ * Sets the value of the variables property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Fault.RequestError.ServiceException.Variables }
+ *
+ */
+ public void setVariables(Fault.RequestError.ServiceException.Variables value) {
+ this.variables = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="variable" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "variable"
+ })
+ public static class Variables {
+
+ protected List<String> variable;
+
+ /**
+ * Gets the value of the variable property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the variable property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getVariable().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link String }
+ *
+ * @return the variable
+ */
+ public List<String> getVariable() {
+ if (variable == null) {
+ variable = new ArrayList<String>();
+ }
+ return this.variable;
+ }
+
+ }
+
+ }
+
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/ObjectFactory.java b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/ObjectFactory.java
new file mode 100644
index 00000000..c6c06766
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/ObjectFactory.java
@@ -0,0 +1,95 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2015.02.11 at 04:54:29 PM EST
+//
+
+
+package org.openecomp.aai.domain.restServiceException;
+
+import javax.xml.bind.annotation.XmlRegistry;
+
+
+/**
+ * This object contains factory methods for each
+ * Java content interface and Java element interface
+ * generated in the org.openecomp.aai.domain.restServiceException package.
+ * <p>An ObjectFactory allows you to programatically
+ * construct new instances of the Java representation
+ * for XML content. The Java representation of XML
+ * content can consist of schema derived interfaces
+ * and classes representing the binding of schema
+ * type definitions, element declarations and model
+ * groups. Factory methods for each of these are
+ * provided in this class.
+ *
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.openecomp.aai.domain.restServiceException
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link Fault }.
+ *
+ * @return the fault
+ */
+ public Fault createFault() {
+ return new Fault();
+ }
+
+ /**
+ * Create an instance of {@link Fault.RequestError }
+ *
+ * @return the request error
+ */
+ public Fault.RequestError createFaultRequestError() {
+ return new Fault.RequestError();
+ }
+
+ /**
+ * Create an instance of {@link Fault.RequestError.ServiceException }
+ *
+ * @return the service exception
+ */
+ public Fault.RequestError.ServiceException createFaultRequestErrorServiceException() {
+ return new Fault.RequestError.ServiceException();
+ }
+
+ /**
+ * Create an instance of {@link Fault.RequestError.ServiceException.Variables }
+ *
+ * @return the variables
+ */
+ public Fault.RequestError.ServiceException.Variables createFaultRequestErrorServiceExceptionVariables() {
+ return new Fault.RequestError.ServiceException.Variables();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/RESTResponse.java b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/RESTResponse.java
new file mode 100644
index 00000000..bef20f79
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/RESTResponse.java
@@ -0,0 +1,86 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.restServiceException;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Generated;
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Generated("org.jsonschema2pojo")
+@JsonPropertyOrder({
+ "requestError"
+})
+public class RESTResponse {
+
+ @JsonProperty("requestError")
+ private RequestError requestError;
+ @JsonIgnore
+ private Map<String, Object> additionalProperties = new HashMap<String, Object>();
+
+ /**
+ * Gets the request error.
+ *
+ * @return The requestError
+ */
+ @JsonProperty("requestError")
+ public RequestError getRequestError() {
+ return requestError;
+ }
+
+ /**
+ * Sets the request error.
+ *
+ * @param requestError The requestError
+ */
+ @JsonProperty("requestError")
+ public void setRequestError(RequestError requestError) {
+ this.requestError = requestError;
+ }
+
+ /**
+ * Gets the additional properties.
+ *
+ * @return the additional properties
+ */
+ @JsonAnyGetter
+ public Map<String, Object> getAdditionalProperties() {
+ return this.additionalProperties;
+ }
+
+ /**
+ * Sets the additional property.
+ *
+ * @param name the name
+ * @param value the value
+ */
+ @JsonAnySetter
+ public void setAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/RequestError.java b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/RequestError.java
new file mode 100644
index 00000000..9a076908
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/RequestError.java
@@ -0,0 +1,86 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.restServiceException;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Generated;
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Generated("org.jsonschema2pojo")
+@JsonPropertyOrder({
+ "serviceException"
+})
+public class RequestError {
+
+ @JsonProperty("serviceException")
+ private ServiceException serviceException;
+ @JsonIgnore
+ private Map<String, Object> additionalProperties = new HashMap<String, Object>();
+
+ /**
+ * Gets the service exception.
+ *
+ * @return The serviceException
+ */
+ @JsonProperty("serviceException")
+ public ServiceException getServiceException() {
+ return serviceException;
+ }
+
+ /**
+ * Sets the service exception.
+ *
+ * @param serviceException The serviceException
+ */
+ @JsonProperty("serviceException")
+ public void setServiceException(ServiceException serviceException) {
+ this.serviceException = serviceException;
+ }
+
+ /**
+ * Gets the additional properties.
+ *
+ * @return the additional properties
+ */
+ @JsonAnyGetter
+ public Map<String, Object> getAdditionalProperties() {
+ return this.additionalProperties;
+ }
+
+ /**
+ * Sets the additional property.
+ *
+ * @param name the name
+ * @param value the value
+ */
+ @JsonAnySetter
+ public void setAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/ServiceException.java b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/ServiceException.java
new file mode 100644
index 00000000..86b21de3
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/restServiceException/ServiceException.java
@@ -0,0 +1,134 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.restServiceException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Generated;
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Generated("org.jsonschema2pojo")
+@JsonPropertyOrder({
+ "messageId",
+ "text",
+ "variables"
+})
+public class ServiceException {
+
+ @JsonProperty("messageId")
+ private String messageId;
+ @JsonProperty("text")
+ private String text;
+ @JsonProperty("variables")
+ private List<String> variables = new ArrayList<String>();
+ @JsonIgnore
+ private Map<String, Object> additionalProperties = new HashMap<String, Object>();
+
+ /**
+ * Gets the message id.
+ *
+ * @return The messageId
+ */
+ @JsonProperty("messageId")
+ public String getMessageId() {
+ return messageId;
+ }
+
+ /**
+ * Sets the message id.
+ *
+ * @param messageId The messageId
+ */
+ @JsonProperty("messageId")
+ public void setMessageId(String messageId) {
+ this.messageId = messageId;
+ }
+
+ /**
+ * Gets the text.
+ *
+ * @return The text
+ */
+ @JsonProperty("text")
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * Sets the text.
+ *
+ * @param text The text
+ */
+ @JsonProperty("text")
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ /**
+ * Gets the variables.
+ *
+ * @return The variables
+ */
+ @JsonProperty("variables")
+ public List<String> getVariables() {
+ return variables;
+ }
+
+ /**
+ * Sets the variables.
+ *
+ * @param variables The variables
+ */
+ @JsonProperty("variables")
+ public void setVariables(List<String> variables) {
+ this.variables = variables;
+ }
+
+ /**
+ * Gets the additional properties.
+ *
+ * @return the additional properties
+ */
+ @JsonAnyGetter
+ public Map<String, Object> getAdditionalProperties() {
+ return this.additionalProperties;
+ }
+
+ /**
+ * Sets the additional property.
+ *
+ * @param name the name
+ * @param value the value
+ */
+ @JsonAnySetter
+ public void setAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/translog/TransactionLogEntries.java b/aai-core/src/main/java/org/openecomp/aai/domain/translog/TransactionLogEntries.java
new file mode 100644
index 00000000..0497da42
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/translog/TransactionLogEntries.java
@@ -0,0 +1,131 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2015.03.20 at 09:46:47 AM CDT
+//
+
+
+package org.openecomp.aai.domain.translog;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="update" minOccurs="0">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="update-node-type" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="update-node-key" maxOccurs="unbounded" minOccurs="0">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="key-name" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="key-value" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;element name="action" maxOccurs="unbounded" minOccurs="0">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="action-type" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="action-data" maxOccurs="unbounded" minOccurs="0">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="property-name" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="property-value" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "transactionLogEntries"
+})
+@XmlRootElement(name = "transaction-log-entries", namespace = "http://org.openecomp.aai.inventory")
+public class TransactionLogEntries {
+
+ protected List<TransactionLogEntry> transactionLogEntries;
+
+ /**
+ * Gets the transaction log entries.
+ *
+ * @return the transaction log entries
+ */
+ public List<TransactionLogEntry> getTransactionLogEntries() {
+ if (transactionLogEntries == null) {
+ transactionLogEntries = new ArrayList<TransactionLogEntry>();
+ }
+ return this.transactionLogEntries;
+ }
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/domain/translog/TransactionLogEntry.java b/aai-core/src/main/java/org/openecomp/aai/domain/translog/TransactionLogEntry.java
new file mode 100644
index 00000000..6c2f815b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/domain/translog/TransactionLogEntry.java
@@ -0,0 +1,438 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.domain.translog;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import com.sun.xml.txw2.annotation.XmlCDATA;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "transactionLogEntryId",
+ "status",
+ "rqstDate",
+ "respDate",
+ "sourceId",
+ "resourceId",
+ "resourceType",
+ "rqstBuf",
+ "respBuf",
+ "notificationPayload",
+ "notificationId",
+ "notificationStatus",
+ "notificationTopic",
+ "notificationEntityLink",
+ "notificationAction"
+})
+@XmlRootElement(name = "transaction-log-entry", namespace = "http://org.openecomp.aai.inventory")
+public class TransactionLogEntry {
+
+ @XmlElement(name = "transaction-log-entry-id", required = true)
+ protected String transactionLogEntryId;
+ @XmlElement(name = "status")
+ protected String status;
+ @XmlElement(name = "rqst-date")
+ protected String rqstDate;
+ @XmlElement(name = "resp-date")
+ protected String respDate;
+ @XmlElement(name = "source-id")
+ protected String sourceId;
+ @XmlElement(name = "resource-id")
+ protected String resourceId;
+ @XmlElement(name = "resource-type")
+ protected String resourceType;
+ @XmlElement(name = "rqst-buf")
+ protected String rqstBuf;
+ @XmlElement(name = "resp-buf")
+ protected String respBuf;
+ @XmlElement(name = "notification-payload")
+ protected String notificationPayload;
+ @XmlElement(name = "notification-id")
+ protected String notificationId;
+ @XmlElement(name = "notification-status")
+ protected String notificationStatus;
+ @XmlElement(name = "notification-topic")
+ private String notificationTopic;
+ @XmlElement(name = "notification-entity-link")
+ private String notificationEntityLink;
+ @XmlElement(name = "notification-action")
+ private String notificationAction;
+
+ /**
+ * Gets the value of the transcationLogEntryId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getTransactionLogEntryId() {
+ return transactionLogEntryId;
+ }
+
+ /**
+ * Sets the value of the transactionLogEntryId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setTransactionLogEntryId(String value) {
+ this.transactionLogEntryId = value;
+ }
+
+ /**
+ * Gets the value of the status property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getStatus() {
+ return status;
+ }
+
+ /**
+ * Sets the value of the status property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setStatus(String value) {
+ this.status = value;
+ }
+
+ /**
+ * Gets the value of the rqstDate property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+
+ public String getRqstDate() {
+ return rqstDate;
+ }
+
+ /**
+ * Sets the value of the rqstDate property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setRqstDate(String value) {
+ this.rqstDate = value;
+ }
+
+
+ /**
+ * Gets the value of the respDate property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+
+ public String getRespDate() {
+ return respDate;
+ }
+
+ /**
+ * Sets the value of the respDate property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setRespDate(String value) {
+ this.respDate = value;
+ }
+ /**
+ * Gets the value of the sourceId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getSourceId() {
+ return sourceId;
+ }
+
+ /**
+ * Sets the value of the sourceId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setSourceId(String value) {
+ this.sourceId = value;
+ }
+
+ /**
+ * Gets the value of the resourceId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getResourceId() {
+ return resourceId;
+ }
+
+ /**
+ * Sets the value of the resourceId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setResourceId(String value) {
+ this.resourceId = value;
+ }
+
+ /**
+ * Gets the value of the resourceType property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getResourceType() {
+ return resourceType;
+ }
+
+ /**
+ * Sets the value of the resourceType property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setResourceType(String value) {
+ this.resourceType = value;
+ }
+
+ /**
+ * Gets the value of the rqstBuf property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getRqstBuf() {
+ return rqstBuf;
+ }
+
+ /**
+ * Sets the value of the rqstBuf property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ @XmlCDATA
+ public void setRqstBuf(String value) {
+ this.rqstBuf = value;
+ }
+
+ /**
+ * Gets the value of the respBuf property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getrespBuf() {
+ return respBuf;
+ }
+
+ /**
+ * Sets the value of the respBuf property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ @XmlCDATA
+ public void setrespBuf(String value) {
+ this.respBuf = value;
+ }
+
+ /**
+ * Gets the value of the notificationPayload property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getNotificationPayload() {
+ return notificationPayload;
+ }
+
+ /**
+ * Sets the value of the notificationPayload property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ @XmlCDATA
+ public void setNotificationPayload(String value) {
+ this.notificationPayload = value;
+ }
+
+
+ /**
+ * Gets the value of the notificationId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getNotificationId() {
+ return notificationId;
+ }
+
+ /**
+ * Sets the value of the notificationId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setNotificationId(String value) {
+ this.notificationId = value;
+ }
+
+ /**
+ * Gets the value of the notificationId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getNotificationStatus() {
+ return notificationStatus;
+ }
+
+ /**
+ * Sets the value of the notificationId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setNotificationStatus(String value) {
+ this.notificationStatus = value;
+ }
+
+ /**
+ * Gets the value of the notificationTopic property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getNotificationTopic() {
+ return notificationTopic;
+ }
+
+ /**
+ * Sets the value of the notificationTopic property.
+ *
+ * @param topic the new notification topic
+ */
+ public void setNotificationTopic(String topic) {
+ this.notificationTopic = topic;
+ }
+
+ /**
+ * Gets the value of the notificationEntityLink property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getNotificationEntityLink() {
+ return notificationEntityLink;
+ }
+
+ /**
+ * Sets the value of the notificationEntityLink property.
+ *
+ * @param entityLink the new notification entity link
+ */
+ public void setNotificationEntityLink(String entityLink) {
+ this.notificationEntityLink = entityLink;
+ }
+
+ /**
+ * Sets the value of the notificationAction property.
+ *
+ * @return the notification action
+ */
+ public String getNotificationAction() {
+ return notificationAction;
+ }
+
+ /**
+ * Sets the value of the notificationAction property.
+ *
+ * @param action the new notification action
+ */
+ public void setNotificationAction(String action) {
+ this.notificationAction = action;
+ }
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/exceptions/AAIException.java b/aai-core/src/main/java/org/openecomp/aai/exceptions/AAIException.java
new file mode 100644
index 00000000..75ee12f2
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/exceptions/AAIException.java
@@ -0,0 +1,146 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.exceptions;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.logging.ErrorObject;
+import org.openecomp.aai.logging.ErrorObjectNotFoundException;
+
+public class AAIException extends Exception {
+
+ public static final String DEFAULT_EXCEPTION_CODE = "AAI_4000";
+ private static final long serialVersionUID = 1L;
+
+ private final String code;
+ private final ErrorObject errorObject;
+ private final Collection<String> templateVars;
+
+ /**
+ * Instantiates a new AAI exception.
+ */
+ public AAIException() {
+ super();
+ this.code = DEFAULT_EXCEPTION_CODE;
+ this.templateVars = new LinkedList<String> ();
+
+ try {
+ this.errorObject = ErrorLogHelper.getErrorObject(getCode());
+ } catch (ErrorObjectNotFoundException e) {
+ throw new RuntimeException("Failed to instantiate AAIException with code=" + getCode()
+ + " - update error.properties before using this exception code");
+ }
+ }
+
+ /**
+ * Instantiates a new AAI exception.
+ *
+ * @param code the code
+ */
+ public AAIException(String code) {
+ super();
+
+ this.code = code;
+ this.templateVars = new LinkedList<String> ();
+
+ try {
+ this.errorObject = ErrorLogHelper.getErrorObject(getCode());
+ } catch (ErrorObjectNotFoundException e) {
+ throw new RuntimeException("Failed to instantiate AAIException with code=" + getCode()
+ + " - update error.properties before using this exception code");
+ }
+ }
+
+ /**
+ * Instantiates a new AAI exception.
+ *
+ * @param code the code
+ * @param details the details
+ */
+ public AAIException(String code, String details) {
+ super(details);
+
+ this.code = code;
+ this.templateVars = new LinkedList<String> ();
+
+ try {
+ this.errorObject = ErrorLogHelper.getErrorObject(getCode());
+ } catch (ErrorObjectNotFoundException e) {
+ throw new RuntimeException("Failed to instantiate AAIException with code=" + getCode()
+ + " - update error.properties before using this exception code");
+ }
+ }
+
+ /**
+ * Instantiates a new AAI exception.
+ *
+ * @param code the code
+ * @param cause the cause
+ */
+ public AAIException(String code, Throwable cause) {
+ super(cause);
+
+ this.code = code;
+ this.templateVars = new LinkedList<String> ();
+
+ try {
+ this.errorObject = ErrorLogHelper.getErrorObject(getCode());
+ } catch (ErrorObjectNotFoundException e) {
+ throw new RuntimeException("Failed to instantiate AAIException with code=" + getCode()
+ + " - update error.properties before using this exception code");
+ }
+ }
+
+ /**
+ * Instantiates a new AAI exception.
+ *
+ * @param code the code
+ * @param cause the cause
+ * @param details the details
+ */
+ public AAIException(String code, Throwable cause, String details) {
+ super(details, cause);
+
+ this.code = code;
+ this.templateVars = new LinkedList<String> ();
+
+ try {
+ this.errorObject = ErrorLogHelper.getErrorObject(getCode());
+ } catch (ErrorObjectNotFoundException e) {
+ throw new RuntimeException("Failed to instantiate AAIException with code=" + getCode()
+ + " - update error.properties before using this exception code");
+ }
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public ErrorObject getErrorObject() {
+ return errorObject;
+ }
+
+ public Collection<String> getTemplateVars() {
+ return templateVars;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/exceptions/AAIExceptionWithInfo.java b/aai-core/src/main/java/org/openecomp/aai/exceptions/AAIExceptionWithInfo.java
new file mode 100644
index 00000000..5065612e
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/exceptions/AAIExceptionWithInfo.java
@@ -0,0 +1,134 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.exceptions;
+
+import java.util.HashMap;
+
+public class AAIExceptionWithInfo extends AAIException {
+
+ HashMap<String, Object> infoHash;
+ String info;
+
+ /**
+ * Instantiates a new AAI exception with info.
+ *
+ * @param infoHash the info hash
+ * @param info the info
+ */
+ public AAIExceptionWithInfo(HashMap<String, Object> infoHash, String info) {
+ super();
+ setInfoHash(infoHash);
+ setInfo(info);
+ }
+
+ /**
+ * Instantiates a new AAI exception with info.
+ *
+ * @param code the code
+ * @param infoHash the info hash
+ * @param info the info
+ */
+ public AAIExceptionWithInfo(String code, HashMap<String, Object> infoHash, String info) {
+ super(code);
+ setInfoHash(infoHash);
+ setInfo(info);
+ }
+
+ /**
+ * Instantiates a new AAI exception with info.
+ *
+ * @param code the code
+ * @param details the details
+ * @param infoHash the info hash
+ * @param info the info
+ */
+ public AAIExceptionWithInfo(String code, String details, HashMap<String, Object> infoHash, String info) {
+ super(code, details);
+ setInfoHash(infoHash);
+ setInfo(info);
+ }
+
+ /**
+ * Instantiates a new AAI exception with info.
+ *
+ * @param code the code
+ * @param cause the cause
+ * @param infoHash the info hash
+ * @param info the info
+ */
+ public AAIExceptionWithInfo(String code, Throwable cause, HashMap<String, Object> infoHash, String info) {
+ super(code, cause);
+ setInfoHash(infoHash);
+ setInfo(info);
+ }
+
+ /**
+ * Instantiates a new AAI exception with info.
+ *
+ * @param code the code
+ * @param cause the cause
+ * @param details the details
+ * @param infoHash the info hash
+ * @param info the info
+ */
+ public AAIExceptionWithInfo(String code, Throwable cause, String details, HashMap<String, Object> infoHash, String info) {
+ super(code, cause, details);
+ setInfoHash(infoHash);
+ setInfo(info);
+ }
+
+ /**
+ * Gets the info hash.
+ *
+ * @return the info hash
+ */
+ public HashMap<String, Object> getInfoHash() {
+ return infoHash;
+ }
+
+ /**
+ * Sets the info hash.
+ *
+ * @param infoHash the info hash
+ */
+ public void setInfoHash(HashMap<String, Object> infoHash) {
+ this.infoHash = infoHash;
+ }
+
+ /**
+ * Gets the info.
+ *
+ * @return the info
+ */
+ public String getInfo() {
+ return info;
+ }
+
+ /**
+ * Sets the info.
+ *
+ * @param info the new info
+ */
+ public void setInfo(String info) {
+ this.info = info;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/ingestModel/ConvertXmlToJsonMoxyOxm.java b/aai-core/src/main/java/org/openecomp/aai/ingestModel/ConvertXmlToJsonMoxyOxm.java
new file mode 100644
index 00000000..1af2df31
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/ingestModel/ConvertXmlToJsonMoxyOxm.java
@@ -0,0 +1,105 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.ingestModel;
+
+import java.io.File;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import javax.xml.transform.stream.StreamSource;
+
+import org.eclipse.persistence.dynamic.DynamicEntity;
+import org.eclipse.persistence.jaxb.JAXBMarshaller;
+import org.eclipse.persistence.jaxb.JAXBUnmarshaller;
+import org.eclipse.persistence.jaxb.MarshallerProperties;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+
+/**
+ * The Class ConvertXmlToJsonMoxyOxm.
+ */
+public class ConvertXmlToJsonMoxyOxm
+{
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ * @throws Exception the exception
+ */
+ public static void main(String[] args) throws Exception {
+
+ String _apiVersion = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+ String fileName = null;
+ String dynamicType = null;
+ if (args.length > 0) {
+ if (args[0] != null) {
+ _apiVersion = args[0];
+ }
+ if (args[1] != null) {
+ fileName = args[1];
+ }
+ if (args[2] != null) {
+ dynamicType = args[2];
+ }
+ }
+
+ if (fileName == null) {
+ System.err.println("You must specify a fileName");
+ System.exit(0);
+ }
+ if (dynamicType == null) {
+ System.err.println("You must specify a dynamic Type");
+ System.exit(0);
+ }
+
+ ArrayList<String> apiVersions = new ArrayList<String>();
+ apiVersions.add(_apiVersion);
+ final IngestModelMoxyOxm m = new IngestModelMoxyOxm();
+ m.init(apiVersions, false);
+
+ DynamicJAXBContext jaxbContext = IngestModelMoxyOxm.aaiResourceContainer.get(_apiVersion).getJaxbContext();
+
+ JAXBUnmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+
+ Class<? extends DynamicEntity> resultClass = jaxbContext.newDynamicEntity(dynamicType).getClass();
+
+ DynamicEntity meObject = (DynamicEntity) unmarshaller.unmarshal(new StreamSource(new File(fileName)), resultClass).getValue();
+
+ // put it out as JSON
+
+ JAXBMarshaller marshaller = jaxbContext.createMarshaller();
+ marshaller.setProperty(JAXBMarshaller.JAXB_FORMATTED_OUTPUT, true);
+
+ marshaller.setProperty("eclipselink.media-type", "application/json");
+ marshaller.setProperty("eclipselink.json.include-root", false);
+ marshaller.setProperty(MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, Boolean.FALSE) ;
+
+ StringWriter writer = new StringWriter();
+ marshaller.marshal(meObject, writer);
+
+ System.out.println(writer.toString());
+
+ System.exit(0);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/ingestModel/CreateWidgetModels.java b/aai-core/src/main/java/org/openecomp/aai/ingestModel/CreateWidgetModels.java
new file mode 100644
index 00000000..549bff00
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/ingestModel/CreateWidgetModels.java
@@ -0,0 +1,168 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.ingestModel;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.xml.transform.stream.StreamSource;
+
+import org.eclipse.persistence.dynamic.DynamicEntity;
+import org.eclipse.persistence.jaxb.JAXBMarshaller;
+import org.eclipse.persistence.jaxb.JAXBUnmarshaller;
+import org.eclipse.persistence.jaxb.MarshallerProperties;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+
+import org.openecomp.aai.domain.model.AAIResource;
+import org.openecomp.aai.domain.model.AAIResources;
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+import com.google.common.base.CaseFormat;
+
+/**
+ * The Class CreateWidgetModels.
+ */
+public class CreateWidgetModels
+{
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ * @throws Exception the exception
+ */
+ public static void main(String[] args) throws Exception {
+
+ String _apiVersion = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+ String widgetJsonDir = null;
+ String modelVersion = null;
+ if (args.length > 0) {
+ if (args[0] != null) {
+ _apiVersion = args[0];
+ }
+ if (args[1] != null) {
+ widgetJsonDir = args[1];
+ }
+ if (args[2] != null) {
+ modelVersion = args[2];
+ }
+ }
+
+ if (widgetJsonDir == null) {
+ System.err.println("You must specify a directory for widgetModelJson");
+ System.exit(0);
+ }
+ if (modelVersion == null) {
+ System.err.println("You must specify a modelVersion");
+ System.exit(0);
+ }
+
+ ArrayList<String> apiVersions = new ArrayList<String>();
+ apiVersions.add(_apiVersion);
+ final IngestModelMoxyOxm m = new IngestModelMoxyOxm();
+ m.init(apiVersions, false);
+
+ AAIResources aaiResources = IngestModelMoxyOxm.aaiResourceContainer.get(_apiVersion);
+
+ DynamicJAXBContext jaxbContext = aaiResources.getJaxbContext();
+
+ // iterate the collection of resources
+
+ ArrayList<String> processedWidgets = new ArrayList<String>();
+ for (Map.Entry<String, AAIResource> aaiResEnt : aaiResources.getAaiResources().entrySet()) {
+ DynamicEntity meObject = jaxbContext.newDynamicEntity("inventory.aai.openecomp.org." + _apiVersion + ".Model");
+ // no need for a ModelVers DynamicEntity
+
+ AAIResource aaiRes = aaiResEnt.getValue();
+
+ if (aaiRes.getResourceType().equals("node")) {
+ String resource = aaiRes.getSimpleName();
+
+ if (processedWidgets.contains(resource)) {
+ continue;
+ }
+ processedWidgets.add(resource);
+
+ String widgetName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, resource);
+ String filePathString = widgetJsonDir + "/" + widgetName + "-" + modelVersion + ".json";
+ File f = new File(filePathString);
+
+ String filePathString2 = widgetJsonDir + "/../widget-model-json-old/" + widgetName + "-" + modelVersion + ".json";
+ File f2 = new File(filePathString2);
+
+ if(!f.exists() && !f.isDirectory()) {
+
+ if (f2.exists()) {
+ System.out.println("Using old file for " + resource + ".");
+
+ JAXBUnmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ unmarshaller.setProperty("eclipselink.media-type", "application/json");
+ unmarshaller.setProperty("eclipselink.json.include-root", false);
+ Class<? extends DynamicEntity> resultClass = meObject.getClass();
+ meObject = (DynamicEntity) unmarshaller.unmarshal(new StreamSource(f2), resultClass).getValue();
+ // override, some of them are wrong
+ meObject.set("modelVersion", modelVersion);
+ } else {
+
+ System.out.println("Making new file for " + resource + ".");
+ meObject.set("modelInvariantId", UUID.randomUUID().toString());
+ meObject.set("modelType", "widget");
+ DynamicEntity mevObject = jaxbContext.newDynamicEntity("inventory.aai.openecomp.org." + _apiVersion + ".ModelVer");
+ DynamicEntity mevsObject = jaxbContext.newDynamicEntity("inventory.aai.openecomp.org." + _apiVersion + ".ModelVers");
+ mevObject.set("modelVersionId", UUID.randomUUID().toString());
+ mevObject.set("modelVersion", modelVersion);
+ mevObject.set("modelName", widgetName);
+ // make a list of dynamic Entities
+ ArrayList<DynamicEntity> mevsList = new ArrayList<DynamicEntity>();
+ // add this one, it will be the only one in the list in this case
+ mevsList.add(mevObject);
+ mevsObject.set("modelVer", mevsList);
+ // Have to figure out how to add my mev object to the mevsObject,
+ // the modelVers is a list of dynamic entities so we can just attach the array here
+ meObject.set("modelVers",mevsObject);
+ }
+
+ // put it out as JSON
+
+ JAXBMarshaller marshaller = jaxbContext.createMarshaller();
+ marshaller.setProperty(JAXBMarshaller.JAXB_FORMATTED_OUTPUT, true);
+
+ marshaller.setProperty("eclipselink.media-type", "application/json");
+ marshaller.setProperty("eclipselink.json.include-root", false);
+ marshaller.setProperty(MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, Boolean.FALSE) ;
+
+ StringWriter writer = new StringWriter();
+ marshaller.marshal(meObject, writer);
+ PrintWriter out = new PrintWriter(f);
+ out.println(writer.toString());
+ out.close();
+
+ } else {
+ System.out.println("File already exists for " + resource + ". Skipping.");
+ }
+ }
+ }
+ System.exit(0);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/ingestModel/DbMaps.java b/aai-core/src/main/java/org/openecomp/aai/ingestModel/DbMaps.java
new file mode 100644
index 00000000..9d7fa4dc
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/ingestModel/DbMaps.java
@@ -0,0 +1,64 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.ingestModel;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+
+/**
+ * The Class DbMaps.
+ */
+public class DbMaps {
+
+ // from oxm file
+ public Multimap<String, String> NodeAltKey1Props = ArrayListMultimap.create();
+
+ public Multimap<String, String> NodeDependencies = ArrayListMultimap.create();
+
+ public Multimap<String, String> NodeNameProps = ArrayListMultimap.create();
+
+ public Multimap<String, String> NodeMapIndexedProps = ArrayListMultimap.create();
+
+ public Multimap<String, String> NodeMapUniqueProps = ArrayListMultimap.create();
+
+ public Map<Integer, String> EdgeInfoMap = new LinkedHashMap<Integer, String>();
+
+ public Map<String, String> ReservedPropNames = new HashMap<String, String>();
+
+ // from AAIResources
+ public Multimap<String, String> NodeProps = ArrayListMultimap.create();
+
+ public Multimap<String, String> NodeKeyProps = ArrayListMultimap.create();
+
+ public Map<String, String> NodePlural = new HashMap<String, String>();
+
+ public Map<String, String> NodeNamespace = new HashMap<String, String>();
+
+ public Map<String, String> PropertyVersionInfoMap = new HashMap<String, String>();
+
+ public Map<String, String> NodeVersionInfoMap = new HashMap<String, String>();
+
+ public Map<String, String> PropertyDataTypeMap = new HashMap<String, String>();
+
+ }
diff --git a/aai-core/src/main/java/org/openecomp/aai/ingestModel/IngestModelListener.java b/aai-core/src/main/java/org/openecomp/aai/ingestModel/IngestModelListener.java
new file mode 100644
index 00000000..914e5a3b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/ingestModel/IngestModelListener.java
@@ -0,0 +1,83 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.ingestModel;
+
+import java.util.ArrayList;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+/**
+ * The listener interface for receiving ingestModel events.
+ * The class that is interested in processing a ingestModel
+ * event implements this interface, and the object created
+ * with that class is registered with a component using the
+ * component's <code>addIngestModelListener<code> method. When
+ * the ingestModel event occurs, that object's appropriate
+ * method is invoked.
+ *
+ * @see IngestModelEvent
+ */
+public class IngestModelListener implements ServletContextListener {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(IngestModelListener.class);
+
+/**
+ * Destroys context.
+ *
+ * @param arg0 the ServletContextEvent
+ */
+//@Override
+ public void contextDestroyed(ServletContextEvent arg0) {
+ IngestModelMoxyOxm m = new IngestModelMoxyOxm();
+ m.cleanup();
+ LOGGER.info("AAI Auth Listener contextDestroyed() complete.");
+ }
+
+//Run this before web application is started
+ /**
+ * Initializaes the context.
+ *
+ * @param arg0 the ServletContextEvent
+ */
+//@Override
+ public void contextInitialized(ServletContextEvent arg0) {
+
+ LOGGER.info("IngestModel starts initialization...");
+ try {
+ ArrayList<String> apiVersions = new ArrayList<String>();
+ apiVersions.add("v10");
+ apiVersions.add("v9");
+ apiVersions.add("v8");
+ apiVersions.add("v7");
+ apiVersions.add("v2");
+ IngestModelMoxyOxm m = new IngestModelMoxyOxm();
+ m.init(apiVersions);
+ } catch (AAIException e) {
+ ErrorLogHelper.logException(e);
+ }
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/ingestModel/IngestModelMoxyOxm.java b/aai-core/src/main/java/org/openecomp/aai/ingestModel/IngestModelMoxyOxm.java
new file mode 100644
index 00000000..1fa11c1b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/ingestModel/IngestModelMoxyOxm.java
@@ -0,0 +1,862 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.ingestModel;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.Vector;
+
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.eclipse.persistence.internal.dynamic.DynamicTypeImpl;
+import org.eclipse.persistence.internal.helper.DatabaseField;
+import org.eclipse.persistence.jaxb.JAXBContextProperties;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
+import org.eclipse.persistence.mappings.DatabaseMapping;
+import org.eclipse.persistence.oxm.XMLField;
+import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping;
+import org.eclipse.persistence.oxm.mappings.XMLCompositeDirectCollectionMapping;
+
+import org.openecomp.aai.domain.model.AAIResource;
+import org.openecomp.aai.domain.model.AAIResourceKey;
+import org.openecomp.aai.domain.model.AAIResourceKeys;
+import org.openecomp.aai.domain.model.AAIResources;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+import org.openecomp.aai.util.FileWatcher;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Multimap;
+
+/**
+ * The Class IngestModelMoxyOxm.
+ */
+public class IngestModelMoxyOxm
+{
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(IngestModelMoxyOxm.class);
+
+ public static HashMap<String, AAIResources> aaiResourceContainer;
+ public static HashMap<String, DbMaps> dbMapsContainer;
+
+ private static HashMap<String, Timer> timers = new HashMap<String,Timer>();
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ * @throws Exception the exception
+ */
+ public static void main(String[] args) throws Exception {
+
+ String _apiVersion = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+
+ if (args.length > 0) {
+ if (args[0] != null) {
+ _apiVersion = args[0];
+ }
+ }
+ ArrayList<String> apiVersions = new ArrayList<String>();
+ apiVersions.add(_apiVersion);
+ final IngestModelMoxyOxm m = new IngestModelMoxyOxm();
+ m.init(apiVersions, false);
+
+ ArrayList<String> endpoints = new ArrayList<String>();
+
+ for (Map.Entry<String, AAIResources> ent: aaiResourceContainer.entrySet()) {
+
+ AAIResources aaiResources = ent.getValue();
+ DynamicJAXBContext jaxbContext = aaiResources.getJaxbContext();
+ for (Map.Entry<String, AAIResource> aaiResEnt : aaiResources.getAaiResources().entrySet()) {
+ AAIResource aaiRes = aaiResEnt.getValue();
+
+ String uri = aaiRes.getUri();
+ if (uri != null) {
+ endpoints.add(uri);
+ DynamicType dt = jaxbContext.getDynamicType(aaiRes.getResourceClassName());
+ if (dt.containsProperty("relationshipList")) {
+ endpoints.add(uri + "/relationship-list/relationship");
+ }
+ }
+ }
+ Collections.sort(endpoints);
+ for (String endpoint : endpoints) {
+ if (!endpoint.contains("/aai-internal/")) {
+ System.out.println(endpoint);
+ }
+ }
+ }
+
+ System.exit(0);
+ }
+
+ /**
+ * Inits the.
+ *
+ * @param apiVersions the api versions
+ * @throws Exception the exception
+ */
+ public synchronized void init(ArrayList<String> apiVersions) throws AAIException {
+ final IngestModelMoxyOxm m = new IngestModelMoxyOxm();
+ m.init(apiVersions, true);
+ }
+
+ /**
+ * Inits the.
+ *
+ * @param apiVersions the api versions
+ * @param setTimer the set timer
+ * @throws AAIException If AAIConfig is missing necessary properties
+ * @throws Exception the exception
+ */
+ public synchronized void init(ArrayList<String> apiVersions, Boolean setTimer) throws AAIException {
+
+ aaiResourceContainer = new HashMap<String, AAIResources>();
+ dbMapsContainer = new HashMap<String, DbMaps>();
+
+ final IngestModelMoxyOxm m = new IngestModelMoxyOxm();
+
+ for (String apiVersion : apiVersions) {
+
+ String relationshipUtils = "org.openecomp.aai.dbmap.RelationshipUtils";
+ final String thisRelationshipUtils = relationshipUtils;
+
+ final String thisApiVersion = apiVersion;
+ final String schemaFile = AAIConstants.AAI_HOME_ETC_OXM + "aai_oxm_" + apiVersion + ".xml";
+
+ m.loadSchema(apiVersion, schemaFile, relationshipUtils);
+
+ if (!setTimer) continue;
+
+ TimerTask task = null;
+ task = new FileWatcher ( new File(schemaFile)) {
+ protected void onChange( File file ) {
+ m.loadSchema(thisApiVersion, schemaFile, thisRelationshipUtils);
+ }
+ };
+
+ if (!timers.containsKey(apiVersion)) {
+ Timer timer = new Timer();
+ timer.schedule( task , new Date(), 10000 );
+ timers.put(apiVersion, timer);
+
+ }
+ }
+ if (apiVersions.contains(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP))) {
+ m.createPropertyAndNodeVersionInfoMapFromDbMaps();
+
+ for (Map.Entry<String, AAIResources> ent: aaiResourceContainer.entrySet()) {
+ String apiVersion = ent.getKey();
+ AAIResources aaiResources = ent.getValue();
+
+ DbMaps dbMap = dbMapsContainer.get(apiVersion);
+
+ for (Map.Entry<String, AAIResource> aaiResEnt : aaiResources.getAaiResources().entrySet()) {
+ AAIResource aaiRes = aaiResEnt.getValue();
+ aaiRes.setPropertyDataTypeMap(dbMap.PropertyDataTypeMap);
+ aaiRes.setNodeKeyProps(dbMap.NodeKeyProps);
+ aaiRes.setNodeNameProps(dbMap.NodeNameProps);
+ aaiRes.setNodeMapIndexedProps(dbMap.NodeMapIndexedProps);
+ }
+ }
+ }
+ }
+
+ /**
+ * Load schema.
+ *
+ * @param apiVersion the api version
+ * @param schemaFile the schema file
+ * @param relationshipUtils the relationship utils
+ * @return the dynamic JAXB context
+ */
+ private DynamicJAXBContext loadSchema(String apiVersion,
+ String schemaFile,
+ String relationshipUtils) {
+
+ AAIResources aaiResources = new AAIResources();
+ DbMaps dbMaps = new DbMaps();
+ DynamicJAXBContext jaxbContext = null;
+
+ try {
+
+ InputStream iStream = new FileInputStream(new File(schemaFile));
+
+ Map<String, Object> properties = new HashMap<String, Object>();
+ properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, iStream);
+
+ jaxbContext =
+ DynamicJAXBContextFactory.createContextFromOXM(IngestModelMoxyOxm.class.getClassLoader(), properties);
+
+ aaiResources.setJaxbContext(jaxbContext);
+ String rootClassName = "inventory.aai.openecomp.org." + apiVersion + ".Inventory";
+
+ if ("v2".equals(apiVersion)) {
+ rootClassName = "inventory.aai.openecomp.org.Inventory";
+ }
+
+ DynamicTypeImpl t = (DynamicTypeImpl)jaxbContext.getDynamicType(rootClassName);
+
+ lookAtDynamicResource("Inventory",
+ "inventory.aai.openecomp.org." + apiVersion,
+ jaxbContext,
+ t,
+ 1, "", "", apiVersion, "/" + apiVersion, false, aaiResources, dbMaps, relationshipUtils);
+
+ } catch (Exception e) {
+ ErrorLogHelper.logException(new AAIException("AAI_3000", e));
+ }
+
+ LOGGER.info("---> Loading " + apiVersion + " in aaiResourceContainer");
+ aaiResourceContainer.put(apiVersion, aaiResources);
+
+ createDbMapsfromAAIResources(aaiResources, dbMaps);
+
+ LOGGER.info("---> Loading " + apiVersion + " in dbMapsContainer");
+ dbMapsContainer.put(apiVersion, dbMaps);
+
+ return jaxbContext;
+ }
+
+ /**
+ * Cleanup.
+ */
+ public void cleanup() {
+ aaiResourceContainer.clear();
+ dbMapsContainer.clear();
+ }
+
+ /**
+ * Look at dynamic resource.
+ *
+ * @param resource the resource
+ * @param pojoBase the pojo base
+ * @param jaxbContext the jaxb context
+ * @param t the t
+ * @param depth the depth
+ * @param parent the parent
+ * @param namespace the namespace
+ * @param apiVersion the api version
+ * @param url the url
+ * @param container the container
+ * @param aaiResources the aai resources
+ * @param dbMaps the db maps
+ * @param relationshipUtils the relationship utils
+ * @throws ClassNotFoundException the class not found exception
+ * @throws NoSuchFieldException the no such field exception
+ * @throws SecurityException the security exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ private void lookAtDynamicResource(String resource,
+ String pojoBase,
+ DynamicJAXBContext jaxbContext,
+ DynamicTypeImpl t,
+ int depth,
+ String parent,
+ String namespace,
+ String apiVersion,
+ String url,
+ boolean container,
+ AAIResources aaiResources,
+ DbMaps dbMaps,
+ String relationshipUtils
+ )
+ throws ClassNotFoundException, NoSuchFieldException, SecurityException, IOException {
+
+ String className = pojoBase + "." + CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL, resource);
+
+ AAIResource parentResource = aaiResources.getAaiResources().get(parent);
+
+ AAIResources siblings = null;
+
+ if (parentResource == null) {
+ String fullName = "/" + resource;
+ AAIResource aaiRes = new AAIResource();
+ aaiRes.setFullName(fullName);
+ aaiRes.setSimpleName(resource);
+ aaiRes.setResourceType("container");
+ aaiRes.setResourceClassName(className);
+ aaiRes.setApiVersion(apiVersion);
+
+ aaiResources.getAaiResources().put(fullName, aaiRes);
+ parentResource = aaiRes;
+ }
+
+ if (depth >= 50) return;
+
+ siblings = parentResource.getChildren();
+
+ if (depth == 2) {
+ namespace = resource;
+ }
+ if (depth >= 50) {
+ return;
+ }
+
+ /* if ("Actions".equals(namespace) || "Search".equals(namespace)) {
+ return;
+ }*/
+
+ ClassDescriptor cd = t.getDescriptor();
+
+ createDbMapsfromOXM(cd.getProperties(), resource, dbMaps);
+
+
+
+ Vector<DatabaseMapping> dm = cd.getMappings();
+
+ for (DatabaseMapping dmInst : dm) {
+ String dmName = dmInst.getAttributeName();
+
+ ClassDescriptor cd2 = dmInst.getReferenceDescriptor();
+ if (cd2 != null) {
+
+ String newClassName = cd2.getJavaClassName();
+ //
+ if (newClassName.contains("RelationshipList")) {
+ continue;
+ }
+
+ DynamicTypeImpl newDt = (DynamicTypeImpl)jaxbContext.getDynamicType(newClassName);
+
+ if (dmInst instanceof XMLCompositeCollectionMapping) {
+ String simpleName = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, dmName);
+ // System.out.println(spaces + "+ List of A&AI Object named " + simpleName);
+
+ String hypName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, simpleName);
+
+ String fullName = parent + "/" + simpleName;
+
+ //Class<?> newClazz = Class.forName(newClassName);
+ AAIResource aaiRes = new AAIResource();
+
+ if ("cvlan-tag-entry".equals(hypName)) {
+ }
+
+ ClassDescriptor cd3 = newDt.getDescriptor();
+
+ boolean allowDirectWrite = true;
+ if (cd3.getProperties().containsKey("allowDirectWrite")) {
+ if (cd3.getProperties().get("allowDirectWrite").equals("false")) {
+ allowDirectWrite = false;
+ }
+ }
+
+
+ boolean allowDirectRead = true;
+ if (cd3.getProperties().containsKey("allowDirectRead")) {
+ if (cd3.getProperties().get("allowDirectRead").equals("false")) {
+ allowDirectRead = false;
+ }
+ }
+
+ List<DatabaseField> dbfList = cd3.getPrimaryKeyFields();
+ ArrayList<String> keyFields = new ArrayList<String>();
+
+ if (dbfList != null) {
+ for (DatabaseField dbf : dbfList) {
+ String name = dbf.getName();
+ name = name.substring(0, name.indexOf('/'));
+ keyFields.add(name);
+ }
+ }
+ Vector<DatabaseMapping> dm2 = cd3.getMappings();
+ for (DatabaseMapping dmInst2 : dm2) {
+ String dmName2= CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmInst2.getAttributeName());
+ DatabaseField xf2 = dmInst2.getField();
+ if (dmInst2.getProperties().containsKey("autoGenerateUuid")) {
+ if (dmInst2.getProperties().get("autoGenerateUuid").equals("true")) {
+ aaiRes.getAutoGenUuidFields().add(dmName2);
+ }
+ }
+ if (xf2 instanceof XMLField) {
+ XMLField x = (XMLField)xf2;
+ if (x != null) {
+ if (x.isRequired()) {
+ aaiRes.getRequiredFields().add(dmName2);
+ }
+ }
+
+ }
+ try {
+ Class<?> xf2Clazz = xf2.getType();
+ if (xf2Clazz.getSimpleName().equals("String")) {
+ if (dmInst2 instanceof XMLCompositeDirectCollectionMapping) {
+ aaiRes.getStringListFields().add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmName2));
+ } else {
+ aaiRes.getStringFields().add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmName2));
+ }
+ } else if (xf2Clazz.getSimpleName().toLowerCase().contains("long")) {
+ aaiRes.getLongFields().add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmName2));
+ } else if (xf2Clazz.getSimpleName().toLowerCase().contains("int")) {
+ aaiRes.getIntFields().add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmName2));
+ } else if (xf2Clazz.getSimpleName().toLowerCase().contains("short")) {
+ aaiRes.getShortFields().add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmName2));
+ } else if (xf2Clazz.getSimpleName().toLowerCase().contains("boolean")) {
+ aaiRes.getBooleanFields().add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmName2));
+ }
+ } catch (Exception e) { // this xf2.getType() throws null pointer when I try to get the type and it doesn't have one
+ ;
+ }
+ }
+
+ // get the key(s) from DbRules
+ String uriKey = "";
+ LinkedHashMap<String, ArrayList<String>> itemKeyList = new LinkedHashMap<String, ArrayList<String>>();
+
+ aaiRes.setApiVersion(apiVersion);
+ itemKeyList.put(hypName, new ArrayList<String>());
+ for (String thisKey : keyFields) {
+ String pathParamName = hypName + "-" + thisKey;
+
+ AAIResourceKey aaiResKey = new AAIResourceKey();
+ aaiResKey.setKeyName(thisKey);
+ aaiResKey.setDnCamKeyName(CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, pathParamName));
+ aaiResKey.setPathParamName(pathParamName);
+
+ for (DatabaseMapping dmInst2 : dm2) {
+ String dmName2= CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,dmInst2.getAttributeName());
+ if (dmName2.equals(thisKey)){
+ DatabaseField xf2 = dmInst2.getField();
+ aaiResKey.setKeyType(xf2.getType().getSimpleName());
+ break;
+ }
+ }
+
+ aaiRes.getAaiResourceKeys().getAaiResourceKey().add(aaiResKey);
+
+ if (siblings != null) {
+ siblings.getAaiResources().put(fullName, aaiRes);
+ }
+
+ uriKey += "/{" + pathParamName + "}";
+ }
+
+ String newUri = url + "/" + hypName + uriKey;
+
+
+ if ("v2".equals(apiVersion)) {
+ aaiRes.setResourceClassName("inventory.aai.openecomp.org." + simpleName);
+ } else {
+ aaiRes.setResourceClassName("inventory.aai.openecomp.org." + apiVersion + "." + simpleName);
+ }
+
+ aaiRes.setAllowDirectWrite(allowDirectWrite);
+ aaiRes.setAllowDirectRead(allowDirectRead);
+ aaiRes.setNamespace(namespace);
+ aaiRes.setSimpleName(simpleName);
+
+ if (!aaiResources.getResourceLookup().containsKey(simpleName)) {
+ aaiResources.getResourceLookup().put(simpleName, aaiRes);
+ }
+
+ aaiRes.setFullName(fullName);
+ aaiRes.setUri(newUri);
+ aaiRes.setResourceType("node");
+ if ("v2".equals(apiVersion)) {
+ aaiRes.setRelationshipListClass("inventory.aai.openecomp.org.RelationshipList");
+ } else {
+ aaiRes.setRelationshipListClass("inventory.aai.openecomp.org." + apiVersion + ".RelationshipList");
+ }
+ aaiRes.setRelationshipUtils(relationshipUtils);
+
+ if (parentResource != null) {
+ aaiRes.setParent(parentResource);
+ } else {
+ aaiRes.setParent(aaiRes);
+ }
+
+ aaiResources.getAaiResources().put(fullName, aaiRes);
+
+ if (siblings != null) {
+ siblings.getAaiResources().put(fullName, aaiRes);
+ }
+// AAIResource ancestor = parentResource;
+//
+// boolean recursiveEntity = false;
+// while (ancestor != null) {
+//
+// if (ancestor.getSimpleName().equals(aaiRes.getSimpleName())) {
+// recursiveEntity = true;
+// // attach it to the container that contains the resource above this one with the same name
+// if (ancestor.getParent() != null && ancestor.getParent().getResourceType().equals("container")) {
+// AAIResource recurseHere = ancestor.getParent();
+// aaiRes.setRecurseToResource(recurseHere);
+// }
+// break;
+// }
+// ancestor = ancestor.getParent();
+//
+// }
+// if (recursiveEntity == false) {
+ lookAtDynamicResource(cd2.getJavaClass().getSimpleName(),
+ pojoBase,
+ jaxbContext,
+ newDt,
+ (depth + 1), fullName, namespace, apiVersion, newUri, false, aaiResources, dbMaps,
+ relationshipUtils);
+// }
+ } else {
+ String simpleName = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, dmName);
+ String fullName = parent + "/" + simpleName;
+ // System.out.println(spaces + "+ Container of A&AI Object named " + simpleName);
+
+ AAIResource aaiRes = new AAIResource();
+ if (parentResource != null) {
+ aaiRes.setParent(parentResource);
+ } else {
+ aaiRes.setParent(aaiRes);
+ }
+ aaiRes.setAllowDirectWrite(true);
+ aaiRes.setAllowDirectRead(true);
+ aaiRes.setFullName(fullName);
+ aaiRes.setSimpleName(simpleName);
+ if (!aaiResources.getResourceLookup().containsKey(simpleName)) {
+ aaiResources.getResourceLookup().put(simpleName, aaiRes);
+ }
+ aaiRes.setResourceType("container");
+
+ if ("v2".equals(apiVersion)) {
+ aaiRes.setResourceClassName("inventory.aai.openecomp.org." + simpleName);
+ aaiRes.setRelationshipListClass("inventory.aai.openecomp.org.RelationshipList");
+ } else {
+ aaiRes.setResourceClassName("inventory.aai.openecomp.org." + apiVersion + "." + simpleName);
+ aaiRes.setRelationshipListClass("inventory.aai.openecomp.org." + apiVersion + ".RelationshipList");
+ }
+ aaiRes.setApiVersion(apiVersion);
+
+ aaiResources.getAaiResources().put(fullName, aaiRes);
+ aaiRes.setRelationshipUtils(relationshipUtils);
+
+ String hypName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, simpleName);
+
+ if (siblings != null) {
+ siblings.getAaiResources().put(fullName, aaiRes);
+ }
+
+ lookAtDynamicResource(cd2.getJavaClass().getSimpleName(),
+ pojoBase,
+ jaxbContext,
+ (DynamicTypeImpl)jaxbContext.getDynamicType(newClassName),
+ (depth + 1), fullName, namespace, apiVersion, url + "/" + hypName, false, aaiResources, dbMaps,
+ relationshipUtils);
+
+
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates the db mapsfrom OXM.
+ *
+ * @param propMap the prop map
+ * @param resource the resource
+ * @param dbMaps the db maps
+ */
+ private void createDbMapsfromOXM(Map<?, ?> propMap, String resource, DbMaps dbMaps) {
+ String nodeType = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, resource);
+ if ("cvlan-tag-entry".equals(nodeType)) {
+ nodeType = "cvlan-tag";
+ }
+
+ // if we have nodes dependent on multiple nodes we might revisit the node again - skip then
+ if (propMap.size() > 1 && !dbMaps.NodeMapIndexedProps.containsKey(nodeType)) {
+
+ if (propMap.containsKey("nameProps"))
+ dbMaps.NodeNameProps.putAll(nodeType,
+ (Iterable<String>) fromCommaSeparatedString(propMap.get("nameProps").toString()));
+
+ if (propMap.containsKey("indexedProps"))
+ dbMaps.NodeMapIndexedProps.putAll(nodeType,
+ (Iterable<String>) fromCommaSeparatedString(propMap.get("indexedProps").toString()));
+
+ if (propMap.containsKey("dependentOn"))
+ dbMaps.NodeDependencies.putAll(nodeType,
+ (Iterable<String>) fromCommaSeparatedString(propMap.get("dependentOn").toString()));
+
+ if (propMap.containsKey("alternateKeys1"))
+ dbMaps.NodeAltKey1Props.putAll(nodeType,
+ (Iterable<String>) fromCommaSeparatedString(propMap.get("alternateKeys1").toString()));
+
+ if (propMap.containsKey("uniqueProps"))
+ dbMaps.NodeMapUniqueProps.putAll(nodeType,
+ (Iterable<String>) fromCommaSeparatedString(propMap.get("uniqueProps").toString()));
+
+ // build EdgeInfoMap
+ if (propMap.containsKey("edgeInfo")) {
+ int i = 0;
+ Iterable<String> edgeInfoIterable = (Iterable<String>) fromCommaSeparatedString(propMap.get("edgeInfo").toString());
+ Iterator<String> edgeInfoIterator = edgeInfoIterable.iterator();
+ while(edgeInfoIterator.hasNext()) {
+ String propName = edgeInfoIterator.next();
+ dbMaps.EdgeInfoMap.put(i++, propName);
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates the db mapsfrom AAI resources.
+ *
+ * @param aaiResources the aai resources
+ * @param dbMaps the db maps
+ */
+ private void createDbMapsfromAAIResources(AAIResources aaiResources, DbMaps dbMaps) {
+
+ for (String resource: aaiResources.getAaiResources().keySet()) {
+
+ AAIResource aaiResource = aaiResources.getAaiResources().get(resource);
+ String nodeType = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,aaiResource.getSimpleName());
+
+ if (nodeType.equals("cvlan-tag-entry"))
+ nodeType = "cvlan-tag";
+
+ // Build NodeNamespace
+ if (aaiResource.getNamespace() != null && !aaiResource.getNamespace().equalsIgnoreCase("search"))
+ // oamNetworks is also defined under the search namespace - do not want that namespace
+ dbMaps.NodeNamespace.put(nodeType, CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, aaiResource.getNamespace()));
+
+ // only process one nodetype once
+ if (dbMaps.NodeProps.containsKey(nodeType))
+ continue;
+
+ // Build NodePlural
+ if (aaiResource.getPluralName() != null && !aaiResource.getPluralName().equals(aaiResource.getNamespace()))
+ // dont want resources which are namespaces themselves in map
+ dbMaps.NodePlural.put(nodeType, CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, aaiResource.getPluralName()));
+
+ // Build NodeProps
+ dbMaps.NodeProps.putAll(nodeType, aaiResource.getAllFields());
+
+ // build ReservedNames
+ if (nodeType.equalsIgnoreCase("reserved-prop-names")) {
+ for (String propName: aaiResource.getAllFields()) {
+ dbMaps.ReservedPropNames.put(propName, "");
+ }
+ }
+
+ // Build NodekeyProps
+ AAIResourceKeys aaiResKeys = aaiResource.getAaiResourceKeys();
+ List<String> keyList = new ArrayList<String>();
+ for (AAIResourceKey rk : aaiResKeys.getAaiResourceKey()) {
+ String keyProp = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,rk.getKeyName());
+ if (!keyList.contains(keyProp))
+ keyList.add(keyProp);
+ }
+ dbMaps.NodeKeyProps.putAll(nodeType, (Iterable<String>)keyList);
+
+ // Build PropertyDataTypeMap
+ for (String propName: aaiResource.getBooleanFields()) {
+ if (nodeType.equalsIgnoreCase("edge-prop-names")) // these properties are in mixed format in DB
+ propName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, propName);
+ if (propName.equals("sVCINFRA")) propName = "SVC-INFRA";
+ if (propName.equals("sVCINFRAREV")) propName = "SVC-INFRA-REV";
+ if (!dbMaps.PropertyDataTypeMap.containsKey(propName))
+ dbMaps.PropertyDataTypeMap.put(propName, "Boolean");
+ else if (!dbMaps.PropertyDataTypeMap.get(propName).equals("Boolean"))
+ System.out.println(propName + "defined with mis-matched types in oxm file");
+ }
+ for (String propName: aaiResource.getShortFields()) {
+ if (nodeType.equalsIgnoreCase("edge-prop-names")) // these properties are in mixed format in DB
+ propName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, propName);
+ if (propName.equals("sVCINFRA")) propName = "SVC-INFRA";
+ if (propName.equals("sVCINFRAREV")) propName = "SVC-INFRA-REV";
+ if (!dbMaps.PropertyDataTypeMap.containsKey(propName))
+ dbMaps.PropertyDataTypeMap.put(propName, "Integer");
+ else if (!dbMaps.PropertyDataTypeMap.get(propName).equals("Integer"))
+ System.out.println(propName + "defined with mis-matched types in oxm file");
+ }
+ for (String propName: aaiResource.getLongFields()) {
+ if (nodeType.equalsIgnoreCase("edge-prop-names")) // these properties are in mixed format in DB
+ propName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, propName);
+ if (propName.equals("sVCINFRA")) propName = "SVC-INFRA";
+ if (propName.equals("sVCINFRAREV")) propName = "SVC-INFRA-REV";
+ if (!dbMaps.PropertyDataTypeMap.containsKey(propName)) {
+ if (propName.contains("-ts"))
+ dbMaps.PropertyDataTypeMap.put(propName, "Long");
+ else
+ dbMaps.PropertyDataTypeMap.put(propName, "Integer");
+ } else if (!dbMaps.PropertyDataTypeMap.get(propName).equals("Integer"))
+ System.out.println(propName + "defined with mis-matched types in oxm file");
+ }
+ for (String propName: aaiResource.getIntFields()) {
+ if (nodeType.equalsIgnoreCase("edge-prop-names")) // these properties are in mixed format in DB
+ propName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, propName);
+ if (propName.equals("sVCINFRA")) propName = "SVC-INFRA";
+ if (propName.equals("sVCINFRAREV")) propName = "SVC-INFRA-REV";
+ if (!dbMaps.PropertyDataTypeMap.containsKey(propName))
+ dbMaps.PropertyDataTypeMap.put(propName, "Integer");
+ else if (!dbMaps.PropertyDataTypeMap.get(propName).equals("Integer"))
+ System.out.println(propName + "defined with mis-matched types in oxm file");
+ }
+ for (String propName: aaiResource.getStringFields()) {
+ if (nodeType.equalsIgnoreCase("edge-prop-names")) // these properties are in mixed format in DB
+ propName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, propName);
+ if (propName.equals("sVCINFRA")) propName = "SVC-INFRA";
+ if (propName.equals("sVCINFRAREV")) propName = "SVC-INFRA-REV";
+ if (!dbMaps.PropertyDataTypeMap.containsKey(propName))
+ dbMaps.PropertyDataTypeMap.put(propName, "String");
+ else if (!dbMaps.PropertyDataTypeMap.get(propName).equals("String"))
+ System.out.println(propName + "defined with mis-matched types in oxm file");
+ }
+ for (String propName: aaiResource.getStringListFields()) {
+ if (nodeType.equalsIgnoreCase("edge-prop-names")) // these properties are in mixed format in DB
+ propName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, propName);
+ if (propName.equals("sVCINFRA")) propName = "SVC-INFRA";
+ if (propName.equals("sVCINFRAREV")) propName = "SVC-INFRA-REV";
+ if (!dbMaps.PropertyDataTypeMap.containsKey(propName))
+ dbMaps.PropertyDataTypeMap.put(propName, "Set<String>");
+ else if (!dbMaps.PropertyDataTypeMap.get(propName).equals("Set<String>"))
+ System.out.println(propName + "defined with mis-matched types in oxm file");
+ }
+ }
+
+ }
+
+
+ /**
+ * Creates the property and node version info map from db maps.
+ */
+ private void createPropertyAndNodeVersionInfoMapFromDbMaps() {
+ DbMaps dbMaps = null;
+ String previousApiVersion = null;
+ List<Integer> apiIntegerKeySet = new ArrayList<Integer>();
+ for ( String vers : dbMapsContainer.keySet()) {
+ apiIntegerKeySet.add(Integer.valueOf(vers.substring(1)));
+ }
+ ArrayList<Integer> apiIntegerVersionsList = (ArrayList<Integer>) asSortedList(apiIntegerKeySet);
+ String apiVersion;
+ for ( Integer apiIntegerVersion : apiIntegerVersionsList) {
+ apiVersion = "v" + apiIntegerVersion;
+ System.out.println("apiVersion=" + apiVersion);
+ dbMaps = dbMapsContainer.get(apiVersion);
+
+ if (previousApiVersion != null) { // when running more than one version
+ dbMaps.PropertyVersionInfoMap.putAll(dbMapsContainer.get(previousApiVersion).PropertyVersionInfoMap);
+ dbMaps.NodeVersionInfoMap.putAll(dbMapsContainer.get(previousApiVersion).NodeVersionInfoMap);
+ }
+
+ Iterator<String> nodeTypeIterator = dbMaps.NodeProps.keySet().iterator();
+ while( nodeTypeIterator.hasNext() ){
+ String nType = nodeTypeIterator.next();
+ if (!dbMaps.NodeVersionInfoMap.containsKey(nType)) {
+ dbMaps.NodeVersionInfoMap.put(nType, apiVersion);
+ }
+ Collection <String> nodePropsForType = dbMaps.NodeProps.get(nType);
+ Iterator <String> propIter = nodePropsForType.iterator();
+ while( propIter.hasNext() ){
+ String propName = propIter.next();
+ String infoKey = nType + "|" + propName;
+ if( ! dbMaps.PropertyVersionInfoMap.containsKey(infoKey) ){
+ // We haven't seen this one yet -- add it in.
+ dbMaps.PropertyVersionInfoMap.put(infoKey, apiVersion);
+ }
+ }
+ }
+ dbMapsContainer.put(apiVersion, dbMaps);
+ previousApiVersion = apiVersion;
+ }
+ }
+
+ /**
+ * As sorted list.
+ *
+ * @param <T> the generic type
+ * @param c the c
+ * @return the list
+ */
+ private <T extends Comparable<? super T>> List<T> asSortedList(Collection<T> c) {
+ List<T> list = new ArrayList<T>(c);
+ java.util.Collections.sort(list);
+ return list;
+ }
+
+ /**
+ * From comma separated string.
+ *
+ * @param string the string
+ * @return the iterable
+ */
+ public Iterable<String> fromCommaSeparatedString( String string ) {
+ Iterable<String> split = Splitter.on( "," ).omitEmptyStrings().trimResults().split( string );
+ return split;
+ }
+
+ /**
+ * Pretty print map.
+ *
+ * @param map the map
+ * @return the string
+ */
+ public String prettyPrintMap(Multimap<String, String> map) {
+ StringBuilder sb = new StringBuilder();
+ sb.append('\n');
+ for (String key:map.keySet()) {
+ sb.append('\t');
+ sb.append(key);
+ sb.append('=').append('"');
+ sb.append(map.get(key));
+ sb.append('"');
+ sb.append('\n');
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Pretty print map.
+ *
+ * @param map the map
+ * @return the string
+ */
+ public String prettyPrintMap(Map<?, String> map) {
+ StringBuilder sb = new StringBuilder();
+ sb.append('\n');
+ for (Object key:map.keySet()) {
+ sb.append('\t');
+ sb.append(key);
+ sb.append('=').append('"');
+ sb.append(map.get(key));
+ sb.append('"');
+ sb.append('\n');
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/Introspector.java b/aai-core/src/main/java/org/openecomp/aai/introspection/Introspector.java
new file mode 100644
index 00000000..a62d5aee
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/Introspector.java
@@ -0,0 +1,616 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import org.apache.commons.lang.ClassUtils;
+import org.eclipse.persistence.exceptions.DynamicException;
+
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.restcore.MediaType;
+import org.openecomp.aai.schema.enums.ObjectMetadata;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+import org.openecomp.aai.workarounds.NamingExceptions;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.base.CaseFormat;
+
+public abstract class Introspector implements Cloneable {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(Introspector.class);
+
+ protected String className;
+ protected String uriChain = "";
+ protected Loader loader;
+ protected final NamingExceptions namingException = NamingExceptions.getInstance();
+ private Set<String> uniqueProperties = null;
+ private Set<String> indexedProperties = null;
+ private Set<String> allKeys = null;
+ protected Introspector(Object obj) {
+ }
+
+ public abstract boolean hasProperty(String name);
+
+ protected String convertPropertyName (String name) {
+ return CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, name);
+ }
+
+ protected abstract Object get(String name);
+ protected abstract void set(String name, Object value);
+ /**
+ *
+ * @param name the property name you'd like to retrieve the value for
+ * @return the value of the property
+ */
+ public <T> T getValue(String name) {
+ String convertedName = convertPropertyName(name);
+ Object result = null;
+
+ if (this.hasProperty(name)) {
+ result = this.get(convertedName);
+ } else {
+ /* property not found - slightly ambiguous */
+ return null;
+ }
+
+ Class<?> clazz = this.getClass(name);
+ if (this.isListType(name) && result == null) {
+ try {
+ this.set(convertedName, clazz.newInstance());
+ result = this.get(convertedName);
+ } catch (DynamicException | InstantiationException | IllegalAccessException e) {
+
+ }
+ }
+
+ return (T)result;
+ }
+
+ public Introspector getWrappedValue(String name) {
+ String convertedName = convertPropertyName(name);
+ Object value = null;
+
+ if (this.hasProperty(name)) {
+ value = this.get(convertedName);
+ } else {
+ /* property not found - slightly ambiguous */
+ return null;
+ }
+
+ Class<?> clazz = this.getClass(name);
+ if (this.isListType(name) && value == null) {
+ try {
+ this.set(convertedName, clazz.newInstance());
+ value = this.get(convertedName);
+ } catch (DynamicException | InstantiationException | IllegalAccessException e) {
+
+ }
+ }
+ if (value != null) {
+ return IntrospectorFactory.newInstance(this.getModelType(), value);
+ } else {
+ //no value
+ return null;
+ }
+
+ }
+
+ public List<Introspector> getWrappedListValue(String name) {
+ String convertedName = convertPropertyName(name);
+ Object value = null;
+ List<Introspector> resultList = new ArrayList<>();
+ if (this.hasProperty(name)) {
+ value = this.get(convertedName);
+ } else {
+ /* property not found - slightly ambiguous */
+ return null;
+ }
+ boolean isListType = this.isListType(name);
+ if (!this.isListType(name)) {
+ return null;
+ }
+ Class<?> clazz = this.getClass(name);
+ if (isListType && value == null) {
+ try {
+ this.set(convertedName, clazz.newInstance());
+ value = this.get(convertedName);
+ } catch (DynamicException | InstantiationException | IllegalAccessException e) {
+
+ }
+ }
+
+ List<Object> valueList = (List<Object>)value;
+
+ for (Object item : valueList) {
+ resultList.add(IntrospectorFactory.newInstance(this.getModelType(), item));
+ }
+
+ return resultList;
+
+ }
+
+ public Object castValueAccordingToSchema(String name, Object obj) {
+ Object result = obj;
+ Class<?> nameClass = this.getClass(name);
+ if (nameClass == null) {
+ throw new IllegalArgumentException("property: " + name + " does not exist on " + this.getDbName());
+ }
+ if (obj != null) {
+
+ try {
+ if (!obj.getClass().getName().equals(nameClass.getName())) {
+ if (nameClass.isPrimitive()) {
+ nameClass = ClassUtils.primitiveToWrapper(nameClass);
+ result = nameClass.getConstructor(String.class).newInstance(obj.toString());
+ }
+ if (obj.getClass().getName().equals("java.lang.String")) {
+ result = nameClass.getConstructor(String.class).newInstance(obj);
+ } else if (!this.isListType(name) && !this.isComplexType(name)){
+ //box = obj.toString();
+ result = nameClass.getConstructor(String.class).newInstance(obj.toString());
+ }
+ }
+ } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+ ErrorLogHelper.logError("AAI_4017", e.getMessage());
+ }
+ }
+ return result;
+ }
+
+ public List<Object> castValueAccordingToSchema(String name, List<?> objs) {
+ List<Object> result = new ArrayList<>();
+
+ for (Object item : objs) {
+ result.add(this.castValueAccordingToSchema(name, item));
+ }
+
+ return result;
+
+ }
+ /**
+ *
+ * @param name the property name you'd like to set the value of
+ * @param obj the value to be set
+ * @return
+ */
+ public void setValue(String name, Object obj) throws IllegalArgumentException {
+ Object box = this.castValueAccordingToSchema(name, obj);
+
+ name = convertPropertyName(name);
+ this.set(name, box);
+ }
+ /**
+ *
+ * @return a list of all the properties available on the object
+ */
+ public abstract Set<String> getProperties();
+
+ public Set<String> getProperties(PropertyPredicate<Introspector, String> p) {
+ final Set<String> temp = new LinkedHashSet<>();
+ this.getProperties().stream().filter(item -> {
+ return p.test(this, item);
+ }).forEach(item -> {
+ temp.add(item);
+ });
+ final Set<String> result = Collections.unmodifiableSet(temp);
+
+ return result;
+
+ }
+ /**
+ *
+ * @return a list of the required properties on the object
+ */
+ public abstract Set<String> getRequiredProperties();
+ /**
+ *
+ * @return a list of the properties that can be used to query the object in the db
+ */
+ public abstract Set<String> getKeys();
+ /**
+ *
+ * @return a list of the all key properties for this object
+ */
+ public Set<String> getAllKeys() {
+ Set<String> result = null;
+ if (this.allKeys == null) {
+ Set<String> keys = this.getKeys();
+ result = new LinkedHashSet<>();
+ result.addAll(keys);
+ String altKeys = this.getMetadata(ObjectMetadata.ALTERNATE_KEYS_1);
+ if (altKeys != null) {
+ String[] altKeysArray = altKeys.split(",");
+ for (String altKey : altKeysArray) {
+ result.add(altKey);
+ }
+ }
+ result = Collections.unmodifiableSet(result);
+ this.allKeys = result;
+ }
+ result = this.allKeys;
+ return result;
+ }
+
+ public Set<String> getIndexedProperties() {
+ Set<String> result = null;
+
+ if (this.indexedProperties == null) {
+ result = new LinkedHashSet<>();
+ Set<String> keys = this.getKeys();
+ result.addAll(keys);
+ String altKeys = this.getMetadata(ObjectMetadata.INDEXED_PROPS);
+ if (altKeys != null) {
+ String[] altKeysArray = altKeys.split(",");
+ for (String altKey : altKeysArray) {
+ result.add(altKey);
+ }
+ }
+ this.indexedProperties = Collections.unmodifiableSet(result);
+ }
+ result = this.indexedProperties;
+ return result;
+ }
+
+ public Set<String> getUniqueProperties() {
+ Set<String> result = null;
+ if (this.uniqueProperties == null) {
+ String altKeys = this.getMetadata(ObjectMetadata.UNIQUE_PROPS);
+ result = new LinkedHashSet<>();
+ if (altKeys != null) {
+ String[] altKeysArray = altKeys.split(",");
+ for (String altKey : altKeysArray) {
+ result.add(altKey);
+ }
+ }
+ this.uniqueProperties = Collections.unmodifiableSet(result);
+
+ }
+ result = this.uniqueProperties;
+ return result;
+ }
+ /**
+ *
+ * @param name
+ * @return the string name of the java class of the named property
+ */
+ public String getType(String name) {
+ Class<?> resultClass = this.getClass(name);
+ String result = "";
+
+ if (resultClass != null) {
+ result = resultClass.getName();
+ if (result.equals("java.util.ArrayList")) {
+ result = "java.util.List";
+ }
+ }
+
+ return result;
+ }
+ /**
+ * This will returned the generic parameterized type of the underlying
+ * object if it exists
+ * @param name
+ * @return the generic type of the java class of the underlying object
+ */
+ public String getGenericType(String name) {
+ Class<?> resultClass = this.getGenericTypeClass(name);
+ String result = "";
+
+ if (resultClass != null) {
+ result = resultClass.getName();
+ }
+
+ return result;
+ }
+ /**
+ *
+ * @return the string name of the java class of the underlying object
+ */
+ public abstract String getJavaClassName();
+
+ /**
+ *
+ * @param name the property name
+ * @return the Class object
+ */
+ public abstract Class<?> getClass(String name);
+
+ public abstract Class<?> getGenericTypeClass(String name);
+
+ /**
+ *
+ * @param name the property name
+ * @return a new instance of the underlying type of this property
+ * @throws AAIUnknownObjectException
+ */
+ public Object newInstanceOfProperty(String name) throws AAIUnknownObjectException {
+ String type = this.getType(name);
+ return loader.objectFromName(type);
+ }
+
+ public Object newInstanceOfNestedProperty(String name) throws AAIUnknownObjectException {
+ String type = this.getGenericType(name);
+ return loader.objectFromName(type);
+ }
+
+
+ public Introspector newIntrospectorInstanceOfProperty(String name) throws AAIUnknownObjectException {
+
+ Introspector result = IntrospectorFactory.newInstance(this.getModelType(), this.newInstanceOfProperty(name));
+
+ return result;
+
+ }
+
+ public Introspector newIntrospectorInstanceOfNestedProperty(String name) throws AAIUnknownObjectException {
+
+ Introspector result = IntrospectorFactory.newInstance(this.getModelType(), this.newInstanceOfNestedProperty(name));
+
+ return result;
+
+ }
+ /**
+ * Is this type not a Java String or primitive
+ * @param name
+ * @return
+ */
+ public boolean isComplexType(String name) {
+ String result = this.getType(name);
+
+ if (result.contains("aai") || result.equals("java.lang.Object")) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public boolean isComplexGenericType(String name) {
+ String result = this.getGenericType(name);
+
+ if (result.contains("aai")) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public boolean isSimpleType(String name) {
+ return !(this.isComplexType(name) || this.isListType(name));
+ }
+
+ public boolean isSimpleGenericType(String name) {
+ return !this.isComplexGenericType(name);
+ }
+
+ public boolean isListType(String name) {
+ String result = this.getType(name);
+
+ if (result.contains("java.util.List")) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public boolean isContainer() {
+ Set<String> props = this.getProperties();
+ boolean result = false;
+ if (props.size() == 1 && this.isListType(props.iterator().next())) {
+ result = true;
+ }
+
+ return result;
+ }
+
+ public abstract String getChildName();
+ public String getChildDBName() {
+ String result = this.getChildName();
+
+ result = namingException.getDBName(result);
+ return result;
+ }
+ public abstract String getName();
+
+ public String getDbName() {
+ String lowerHyphen = this.getName();
+
+ lowerHyphen = namingException.getDBName(lowerHyphen);
+
+ return lowerHyphen;
+ }
+
+ public abstract ModelType getModelType();
+
+ public boolean hasChild(Introspector child) {
+ boolean result = false;
+ //check all inheriting types for this child
+ if ("true".equals(this.getMetadata(ObjectMetadata.ABSTRACT))) {
+ String[] inheritors = this.getMetadata(ObjectMetadata.INHERITORS).split(",");
+ for (String inheritor : inheritors) {
+ try {
+ Introspector temp = this.loader.introspectorFromName(inheritor);
+ result = temp.hasProperty(child.getName());
+ if (result) {
+ break;
+ }
+ } catch (AAIUnknownObjectException e) {
+ LOGGER.warn("Skipping inheritor " + inheritor + " (Unknown Object)", e);
+ }
+ }
+ } else {
+ result = this.hasProperty(child.getName());
+ }
+ return result;
+ }
+
+ public void setURIChain(String uri) {
+ this.uriChain = uri;
+ }
+ public abstract String getObjectId() throws UnsupportedEncodingException;
+
+ public String getURI() throws UnsupportedEncodingException {
+ //String result = this.uriChain;
+ String result = "";
+ String namespace = this.getMetadata(ObjectMetadata.NAMESPACE);
+ String container = this.getMetadata(ObjectMetadata.CONTAINER);
+ if (this.isContainer()) {
+ result += "/" + this.getName();
+ } else {
+
+ if (container != null) {
+ result += "/" + container;
+ }
+ result += "/" + this.getDbName() + "/" + this.findKey();
+
+ if (namespace != null && !namespace.equals("")) {
+ result = "/" + namespace + result;
+ }
+ }
+
+
+ return result;
+ }
+
+ public String getGenericURI() {
+ String result = "";
+ if (this.isContainer()) {
+ result += "/" + this.getName();
+ } else {
+ result += "/" + this.getDbName();
+ for (String key : this.getKeys()) {
+ result += "/{" + this.getDbName() + "-" + key + "}";
+ }
+ }
+
+ return result;
+ }
+
+ public String getFullGenericURI() {
+ String result = "";
+ String namespace = this.getMetadata(ObjectMetadata.NAMESPACE);
+ String container = this.getMetadata(ObjectMetadata.CONTAINER);
+ if (this.isContainer()) {
+ result += "/" + this.getName();
+ } else {
+
+
+ if (container != null) {
+ result += "/" + container;
+ }
+ result += "/" + this.getDbName();
+
+ for (String key : this.getKeys()) {
+ result += "/{" + this.getDbName() + "-" + key + "}";
+ }
+ if (namespace != null && !namespace.equals("")) {
+ result = "/" + namespace + result;
+ }
+
+ }
+
+ return result;
+ }
+
+ public abstract String preProcessKey(String key);
+
+ protected abstract String findKey() throws UnsupportedEncodingException;
+
+ public abstract String marshal(MarshallerProperties properties);
+
+ public abstract Object clone();
+
+ public abstract Object getUnderlyingObject();
+
+ public String marshal(boolean formatted) {
+ MarshallerProperties properties =
+ new MarshallerProperties.Builder(MediaType.APPLICATION_JSON_TYPE).formatted(formatted).build();
+
+ return marshal(properties);
+ }
+ public String makeSingular(String word) {
+
+ String result = word;
+ result = result.replaceAll("(?:([ho])es|s)$", "");
+
+ if (result.equals("ClassesOfService")) {
+ result = "ClassOfService";
+ } else if (result.equals("CvlanTag")) {
+ result = "CvlanTagEntry";
+ } else if (result.equals("Metadata")) {
+ result = "Metadatum";
+ }
+ return result;
+ }
+
+ protected String makePlural(String word) {
+ String result = word;
+
+ if (result.equals("cvlan-tag-entry")) {
+ return "cvlan-tags";
+ } else if (result.equals("class-of-service")) {
+ return "classes-of-service";
+ } else if (result.equals("metadatum")) {
+ return "metadata";
+ }
+ result = result.replaceAll("([a-z])$", "$1s");
+ result = result.replaceAll("([hox])s$", "$1es");
+ /*
+ if (result.equals("classes-of-services")) {
+ result = "classes-of-service";
+ }*/
+
+ return result;
+ }
+
+ public abstract String getMetadata(ObjectMetadata metadataName);
+ public abstract Map<PropertyMetadata, String> getPropertyMetadata(String propName);
+ public Optional<String> getPropertyMetadata(String propName, PropertyMetadata metadataName) {
+ final String resultValue = this.getPropertyMetadata(propName).getOrDefault(metadataName, "");
+ Optional<String> result = Optional.empty();
+
+ if (!resultValue.isEmpty()) {
+ result = Optional.of(resultValue);
+ }
+ return result;
+
+ }
+
+ public abstract Version getVersion();
+ public Loader getLoader() {
+ return this.loader;
+ }
+
+ public boolean isTopLevel() {
+
+ return this.getMetadata(ObjectMetadata.NAMESPACE) != null;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/IntrospectorFactory.java b/aai-core/src/main/java/org/openecomp/aai/introspection/IntrospectorFactory.java
new file mode 100644
index 00000000..016e089f
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/IntrospectorFactory.java
@@ -0,0 +1,65 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+public class IntrospectorFactory {
+
+ /**
+ * New instance.
+ *
+ * @param type the type
+ * @param o the o
+ * @param llBuilder the ll builder
+ * @return the introspector
+ */
+ public static Introspector newInstance(ModelType type, Object o) {
+
+ if (type.equals(ModelType.MOXY)) {
+ return new MoxyStrategy(o);
+ } else if (type.equals(ModelType.POJO)) {
+ return new PojoStrategy(o);
+ } else if (type.equals(ModelType.JSON)) {
+ return new JSONStrategy(o);
+ } else {
+ throw new IllegalArgumentException("Unknown class type: " + type);
+ }
+
+ }
+
+ /**
+ * New instance.
+ *
+ * @param type the type
+ * @param o the o
+ * @param namedType the named type
+ * @param llBuilder the ll builder
+ * @return the introspector
+ */
+ public static Introspector newInstance(ModelType type, Object o, String namedType) {
+
+ if (type.equals(ModelType.JSON)) {
+ return new JSONStrategy(o, namedType);
+ } else {
+ throw new IllegalArgumentException("Unknown class type: " + type);
+ }
+
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/IntrospectorWalker.java b/aai-core/src/main/java/org/openecomp/aai/introspection/IntrospectorWalker.java
new file mode 100644
index 00000000..12d545d2
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/IntrospectorWalker.java
@@ -0,0 +1,193 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+public class IntrospectorWalker {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(IntrospectorWalker.class);
+
+ private Wanderer w = null;
+ private Set<String> blacklist = null;
+ private boolean preventCycles = false;
+ private final PropertyPredicate<Introspector, String> propVisibility;
+
+ /**
+ * Instantiates a new introspector walker.
+ *
+ * @param w the w
+ * @param llBuilder the ll builder
+ */
+ public IntrospectorWalker(Wanderer w) {
+ this.w = w;
+ this.blacklist = new HashSet<>();
+ this.propVisibility = null;
+ }
+
+ public IntrospectorWalker(Wanderer w, PropertyPredicate<Introspector, String> p) {
+ this.w = w;
+ this.blacklist = new HashSet<>();
+ this.propVisibility = p;
+ }
+
+
+ /**
+ * Sets the blacklist.
+ *
+ * @param list the new blacklist
+ */
+ public void setBlacklist(List<String> list) {
+ blacklist.addAll(list);
+ }
+
+ /**
+ * Prevent cycles.
+ *
+ * @param prevent the prevent
+ */
+ public void preventCycles(boolean prevent) {
+ this.preventCycles = prevent;
+ }
+
+ /**
+ * Walk.
+ *
+ * @param obj the obj
+ * @throws AAIException
+ */
+ public void walk(Introspector obj) throws AAIException {
+ Set<String> visited = new HashSet<>();
+
+ walk(obj, null, visited);
+ }
+
+ /**
+ * Walk.
+ *
+ * @param obj the obj
+ * @param parent the parent
+ * @throws AAIException
+ */
+ private void walk(Introspector obj, Introspector parent, Set<String> visited) throws AAIException {
+ boolean stopRecursion = false;
+ Set<String> localVisited = new HashSet<>();
+ localVisited.addAll(visited);
+ if (preventCycles) {
+ if (visited.contains(obj.getName())) {
+ stopRecursion = true;
+ }
+ if (!obj.isContainer()) {
+ localVisited.add(obj.getName()); //so we don't recurse while walking its children
+ }
+ }
+ Set<String> props;
+ //props must duplicate the result from getProperties because
+ //it is unmodifiable
+ if (this.propVisibility == null) {
+ props = new LinkedHashSet<>(obj.getProperties());
+ } else {
+ props = new LinkedHashSet<>(obj.getProperties(this.propVisibility));
+ }
+
+ w.processComplexObj(obj);
+ props.removeAll(blacklist);
+ if (!obj.isContainer()) {
+ parent = obj;
+ }
+ for (String prop : props) {
+
+ if (obj.isSimpleType(prop)) {
+
+ w.processPrimitive(prop, obj);
+ } else if (obj.isListType(prop) && !stopRecursion) {
+
+ List<Object> listReference = obj.getValue(prop);
+ boolean isComplexType = obj.isComplexGenericType(prop);
+ if (isComplexType) {
+ List<Introspector> list = obj.getWrappedListValue(prop);
+ try {
+ Introspector child = obj.newIntrospectorInstanceOfNestedProperty(prop);
+ w.modifyComplexList(list, listReference, parent, child);
+ for (Object item : listReference) {
+ child = IntrospectorFactory.newInstance(obj.getModelType(), item);
+ walk(child, parent, localVisited);
+ }
+ } catch (AAIUnknownObjectException e) {
+ LOGGER.warn("Skipping property " + prop + " (Unknown Object)", e);
+ }
+ } else {
+ w.processPrimitiveList(prop, obj);
+ }
+ if (listReference.size() == 0) {
+ if (isComplexType) {
+ try {
+ Introspector child = obj.newIntrospectorInstanceOfNestedProperty(prop);
+ int size = w.createComplexListSize(parent, child);
+ for (int i = 0; i < size; i++) {
+ child = obj.newIntrospectorInstanceOfNestedProperty(prop);
+ walk(child, parent, localVisited);
+ listReference.add(child.getUnderlyingObject());
+ }
+
+ obj.setValue(prop, listReference);
+ } catch (AAIUnknownObjectException e) {
+ LOGGER.warn("Skipping property " + prop + " (Unknown Object)", e);
+ }
+ } else if (!isComplexType){
+ w.processPrimitiveList(prop, obj);
+ }
+ }
+
+ } else if (obj.isComplexType(prop) && !stopRecursion) {
+ Introspector child = null;
+ if (obj.getValue(prop) != null) {
+ child = IntrospectorFactory.newInstance(obj.getModelType(), obj.getValue(prop));
+ } else {
+ if (w.createComplexObjIfNull()) {
+ try {
+ child = obj.newIntrospectorInstanceOfProperty(prop);
+ obj.setValue(prop, child.getUnderlyingObject());
+ } catch (AAIUnknownObjectException e) {
+ LOGGER.warn("Skipping property " + prop + " (Unknown Object)", e);
+ }
+ }
+ }
+ if (child != null) {
+ walk(child, obj, localVisited);
+ }
+ }
+
+ }
+ /*
+ if (preventCycles && !obj.isContainer()) {
+ visited.remove(obj.getName()); //so we can see it down another path that isn't in danger of recursing over it
+ }*/
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/JSONStrategy.java b/aai-core/src/main/java/org/openecomp/aai/introspection/JSONStrategy.java
new file mode 100644
index 00000000..45ffaad6
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/JSONStrategy.java
@@ -0,0 +1,360 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import org.json.simple.JSONObject;
+
+import org.openecomp.aai.schema.enums.ObjectMetadata;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+
+public class JSONStrategy extends Introspector {
+
+ private JSONObject json = null;
+ private String namedType = "";
+ protected JSONStrategy(Object o) {
+ super(o);
+ json = (JSONObject)o;
+ //Assumes you provide a wrapper
+ Set<String> keySet = json.keySet();
+ if (keySet.size() == 1) {
+ namedType = keySet.iterator().next();
+ json = (JSONObject)json.get(namedType);
+ } else {
+ throw new IllegalArgumentException("This object has no named type.");
+ }
+ }
+
+ protected JSONStrategy(Object o, String namedType) {
+ super(o);
+ json = (JSONObject)o;
+ this.namedType = namedType;
+
+ }
+
+ @Override
+ public boolean hasProperty(String name) {
+ //TODO
+ return true;
+ }
+ @Override
+ public Object getValue(String name) {
+ Object result = "";
+ result = json.get(name);
+
+ return result;
+ }
+
+ @Override
+ public void setValue(String name, Object obj) {
+ json.put(name, obj);
+
+ }
+ @Override
+ public Object getUnderlyingObject() {
+ return this.json;
+ }
+
+ @Override
+ public Set<String> getProperties() {
+ Set<String> result = json.keySet();
+ return result;
+ }
+
+ @Override
+ public Set<String> getRequiredProperties() {
+ //unknowable
+
+ return this.getProperties();
+ }
+
+ @Override
+ public Set<String> getKeys() {
+ //unknowable
+ return this.getProperties();
+ }
+
+ @Override
+ public Set<String> getAllKeys() {
+ //unknowable
+ return this.getProperties();
+ }
+
+ @Override
+ public String getType(String name) {
+ String result = "";
+ Class<?> resultClass = this.getClass(name);
+ if (resultClass != null) {
+ result = resultClass.getName();
+ }
+
+ if (result.equals("org.json.simple.JSONArray")) {
+ result = "java.util.List";
+ }
+
+ return result;
+ }
+
+ @Override
+ public String getGenericType(String name) {
+ String result = "";
+ Class<?> resultClass = this.getGenericTypeClass(name);
+ if (resultClass != null) {
+ result = resultClass.getName();
+ }
+ return result;
+ }
+
+ @Override
+ public String getJavaClassName() {
+ return json.getClass().getName();
+ }
+
+ @Override
+ public Class<?> getClass(String name) {
+ Class<?> result = null;
+ result = json.get(name).getClass();
+
+ return result;
+ }
+
+ @Override
+ public Class<?> getGenericTypeClass(String name) {
+ Object resultObject = null;
+ Class<?> resultClass = null;
+ resultObject = this.getValue(name);
+ if (resultObject.getClass().getName().equals("org.json.simple.JSONArray")) {
+ resultClass = ((List)resultObject).get(0).getClass();
+ }
+
+ return resultClass;
+ }
+
+ @Override
+ public Object newInstanceOfProperty(String name) {
+ try {
+ return this.getClass(name).newInstance();
+ } catch (InstantiationException | IllegalAccessException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public Object newInstanceOfNestedProperty(String name) {
+ try {
+ return this.getGenericTypeClass(name).newInstance();
+ } catch (InstantiationException | IllegalAccessException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean isComplexType(String name) {
+ String result = this.getType(name);
+
+ if (result.contains("JSONObject")) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
+ @Override
+ public boolean isComplexGenericType(String name) {
+ String result = this.getGenericType(name);
+
+ if (result.contains("JSONObject")) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
+ @Override
+ public boolean isListType(String name) {
+ String result = this.getType(name);
+
+ if (result.contains("java.util.List")) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
+ @Override
+ public boolean isContainer() {
+ Set<String> props = this.getProperties();
+ boolean result = false;
+ if (props.size() == 1 && this.isListType(props.iterator().next())) {
+ result = true;
+ }
+
+ return result;
+ }
+ @Override
+ protected String findKey() {
+ return "";
+ }
+
+ @Override
+ public String getName() {
+ return this.namedType;
+ }
+
+ @Override
+ public String getDbName() {
+ return this.getName();
+ }
+
+ @Override
+ public String getURI() {
+
+ // use a UUID for now
+ return UUID.randomUUID().toString();
+ }
+
+ @Override
+ public String getGenericURI() {
+
+ //there is none defined for this
+ return "";
+ }
+
+ @Override
+ public String preProcessKey (String key) {
+
+ // don't do anything with it
+ return key;
+
+ }
+
+ @Override
+ public String marshal(MarshallerProperties properties) {
+ //TODO
+ return null;
+ }
+
+ @Override
+ public Object clone() {
+ //TODO
+ return null;
+ }
+
+ /*@Override
+ public String findEdgeName(String parent, String child) {
+
+ // Always has for now
+ return "has";
+
+ }*/
+
+ @Override
+ public ModelType getModelType() {
+ return ModelType.JSON;
+ }
+
+ @Override
+ public Set<String> getIndexedProperties() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getChildName() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean hasChild(Introspector child) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isSimpleType(String name) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isSimpleGenericType(String name) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public Map<PropertyMetadata, String> getPropertyMetadata(String prop) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getMetadata(ObjectMetadata metadataName) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getChildDBName() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getFullGenericURI() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Object get(String name) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected void set(String name, Object value) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public String getObjectId() throws UnsupportedEncodingException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Version getVersion() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/Loader.java b/aai-core/src/main/java/org/openecomp/aai/introspection/Loader.java
new file mode 100644
index 00000000..76f00390
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/Loader.java
@@ -0,0 +1,112 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+import java.util.Map;
+
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.introspection.exceptions.AAIUnmarshallingException;
+import org.openecomp.aai.restcore.MediaType;
+
+public abstract class Loader {
+
+ private final Version version;
+ private final ModelType modelType;
+
+ /**
+ * Instantiates a new loader.
+ *
+ * @param version the version
+ * @param modelType the model type
+ * @param llBuilder the ll builder
+ */
+ public Loader (Version version, ModelType modelType) {
+ this.version = version;
+ this.modelType = modelType;
+ }
+
+ /**
+ * Process.
+ *
+ * @param version the version
+ */
+ protected abstract void process(Version version);
+
+ /**
+ * Object from name.
+ *
+ * @param name the name
+ * @return the object
+ * @throws AAIUnknownObjectException
+ */
+ public abstract Object objectFromName(String name) throws AAIUnknownObjectException;
+
+ /**
+ * Introspector from name.
+ *
+ * @param name the name
+ * @return the introspector
+ * @throws AAIUnknownObjectException
+ */
+ public abstract Introspector introspectorFromName(String name) throws AAIUnknownObjectException;
+
+ /**
+ * Unmarshal.
+ *
+ * @param type the type
+ * @param json the json
+ * @param mediaType the media type
+ * @return the introspector
+ */
+ public abstract Introspector unmarshal(String type, String json, MediaType mediaType) throws AAIUnmarshallingException;
+
+ /**
+ * Unmarshal.
+ *
+ * @param type the type
+ * @param json the json
+ * @return the introspector
+ */
+ public Introspector unmarshal(String type, String json) throws AAIUnmarshallingException {
+ return unmarshal(type, json, MediaType.APPLICATION_JSON_TYPE);
+ }
+
+
+ /**
+ * Gets the model type.
+ *
+ * @return the model type
+ */
+ public ModelType getModelType() {
+ return this.modelType;
+ }
+
+ /**
+ * Gets the version.
+ *
+ * @return the version
+ */
+ public Version getVersion() {
+ return this.version;
+ }
+
+ public abstract Map<String, Introspector> getAllObjects();
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/LoaderFactory.java b/aai-core/src/main/java/org/openecomp/aai/introspection/LoaderFactory.java
new file mode 100644
index 00000000..04cc00df
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/LoaderFactory.java
@@ -0,0 +1,44 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+public class LoaderFactory {
+
+ /**
+ * Creates a new Loader object.
+ *
+ * @param type the type
+ * @param version the version
+ * @param llBuilder the ll builder
+ * @return the loader
+ */
+ public static Loader createLoaderForVersion(ModelType type, Version version) {
+
+ if (type.equals(ModelType.MOXY)) {
+ return new MoxyLoader(version);
+ } else if (type.equals(ModelType.POJO)) {
+ return new PojoLoader(version);
+ }
+
+ return null;
+
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/MarshallerProperties.java b/aai-core/src/main/java/org/openecomp/aai/introspection/MarshallerProperties.java
new file mode 100644
index 00000000..25156c7b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/MarshallerProperties.java
@@ -0,0 +1,139 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+import org.openecomp.aai.restcore.MediaType;
+
+public class MarshallerProperties {
+
+ private final MediaType type;
+ private final boolean includeRoot;
+ private final boolean wrapperAsArrayName;
+ private final boolean formatted;
+
+ /**
+ * Instantiates a new marshaller properties.
+ *
+ * @param builder the builder
+ */
+ private MarshallerProperties(Builder builder) {
+
+ this.type = builder.type;
+ this.includeRoot = builder.includeRoot;
+ this.wrapperAsArrayName = builder.wrapperAsArrayName;
+ this.formatted = builder.formatted;
+ }
+
+ /**
+ * Gets the media type.
+ *
+ * @return the media type
+ */
+ public MediaType getMediaType() {
+ return this.type;
+ }
+
+ /**
+ * Gets the include root.
+ *
+ * @return the include root
+ */
+ public boolean getIncludeRoot() {
+ return this.includeRoot;
+ }
+
+ /**
+ * Gets the wrapper as array name.
+ *
+ * @return the wrapper as array name
+ */
+ public boolean getWrapperAsArrayName() {
+ return this.wrapperAsArrayName;
+ }
+
+ /**
+ * Gets the formatted.
+ *
+ * @return the formatted
+ */
+ public boolean getFormatted() {
+ return this.formatted;
+ }
+
+ public static class Builder {
+
+ private final MediaType type;
+ private boolean includeRoot = false;
+ private boolean wrapperAsArrayName = true;
+ private boolean formatted = false;
+
+ /**
+ * Instantiates a new builder.
+ *
+ * @param type the type
+ */
+ public Builder(MediaType type) {
+ this.type = type;
+ }
+
+ /**
+ * Include root.
+ *
+ * @param includeRoot the include root
+ * @return the builder
+ */
+ public Builder includeRoot (boolean includeRoot) {
+ this.includeRoot = includeRoot;
+ return this;
+ }
+
+ /**
+ * Wrapper as array name.
+ *
+ * @param wrapperAsArrayName the wrapper as array name
+ * @return the builder
+ */
+ public Builder wrapperAsArrayName (boolean wrapperAsArrayName) {
+ this.wrapperAsArrayName = wrapperAsArrayName;
+ return this;
+ }
+
+ /**
+ * Formatted.
+ *
+ * @param formatted the formatted
+ * @return the builder
+ */
+ public Builder formatted (boolean formatted) {
+ this.formatted = formatted;
+ return this;
+ }
+
+ /**
+ * Builds the properties.
+ *
+ * @return the marshaller properties
+ */
+ public MarshallerProperties build() {
+ return new MarshallerProperties(this);
+ }
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/ModelInjestor.java b/aai-core/src/main/java/org/openecomp/aai/introspection/ModelInjestor.java
new file mode 100644
index 00000000..651b28d9
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/ModelInjestor.java
@@ -0,0 +1,176 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.xml.bind.JAXBException;
+
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.eclipse.persistence.jaxb.JAXBContextProperties;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
+
+import org.openecomp.aai.util.AAIConstants;
+
+
+public class ModelInjestor {
+
+ private Map<Version, DynamicJAXBContext> versionContextMap = new HashMap<>();
+ private static final Pattern classNamePattern = Pattern.compile("\\.(v\\d+)\\.");
+ private static final Pattern uriPattern = Pattern.compile("(v\\d+)\\/");
+
+
+ /**
+ * Instantiates a new model injestor.
+ */
+ private ModelInjestor() {
+ try {
+ injestModels();
+ } catch (FileNotFoundException | JAXBException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static class Helper {
+ private static final ModelInjestor INSTANCE = new ModelInjestor();
+ }
+
+ /**
+ * Gets the single instance of ModelInjestor.
+ *
+ * @return single instance of ModelInjestor
+ */
+ public synchronized static ModelInjestor getInstance() {
+ return Helper.INSTANCE;
+ }
+
+ /**
+ * Injest models.
+ *
+ * @throws FileNotFoundException the file not found exception
+ * @throws JAXBException the JAXB exception
+ */
+ private void injestModels() throws FileNotFoundException, JAXBException {
+
+ for (Version version : Version.values()) {
+ this.injestModel(version);
+ }
+ }
+
+ /**
+ * Injest model.
+ *
+ * @param version the version
+ * @throws JAXBException the JAXB exception
+ * @throws FileNotFoundException the file not found exception
+ */
+ private void injestModel (Version version) throws JAXBException, FileNotFoundException {
+ String fileName = this.getOXMFileName(version);
+ InputStream iStream = new FileInputStream(new File(fileName));
+ Map<String, Object> properties = new HashMap<String, Object>();
+ properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, iStream);
+ final DynamicJAXBContext jaxbContext = DynamicJAXBContextFactory.createContextFromOXM(this.getClass().getClassLoader(), properties);
+ versionContextMap.put(version, jaxbContext);
+ }
+
+ /**
+ * Gets the version from class name.
+ *
+ * @param classname the classname
+ * @return the version from class name
+ */
+ public Version getVersionFromClassName (String classname) {
+ Matcher m = classNamePattern.matcher(classname);
+ String version = "v2"; //for the OXM, only the v2 ones don't include a model name, hence this default
+ if (m.find()) {
+ version = m.group(1);
+ }
+
+ return Version.valueOf(version);
+ }
+
+ /**
+ * Gets the context for URI.
+ *
+ * @param uri the uri
+ * @return the context for URI
+ */
+ public DynamicJAXBContext getContextForURI(String uri) {
+ DynamicJAXBContext result = null;
+ Matcher m = uriPattern.matcher(uri);
+ Version version = null;
+ if (m.find()) {
+ version = Version.valueOf(m.group(1));
+ result = versionContextMap.get(version);
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets the context for version.
+ *
+ * @param version the version
+ * @return the context for version
+ */
+ public DynamicJAXBContext getContextForVersion(Version version) {
+ DynamicJAXBContext result = null;
+
+ result = versionContextMap.get(version);
+
+
+ return result;
+ }
+
+ /**
+ * Gets the dynamic type for class name.
+ *
+ * @param classname the classname
+ * @return the dynamic type for class name
+ */
+ public DynamicType getDynamicTypeForClassName(String classname) {
+ DynamicType result = null;
+ DynamicJAXBContext context = null;
+
+ Version version = this.getVersionFromClassName(classname);
+
+ context = versionContextMap.get(version);
+
+ if (context != null) {
+ result = context.getDynamicType(classname);
+ }
+
+ return result;
+ }
+
+ public String getOXMFileName(Version v) {
+ return AAIConstants.AAI_HOME_ETC_OXM + "aai_oxm_" + v.toString() + ".xml";
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/ModelType.java b/aai-core/src/main/java/org/openecomp/aai/introspection/ModelType.java
new file mode 100644
index 00000000..eddc9405
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/ModelType.java
@@ -0,0 +1,25 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+public enum ModelType {
+ MOXY, POJO, JSON
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/MoxyLoader.java b/aai-core/src/main/java/org/openecomp/aai/introspection/MoxyLoader.java
new file mode 100644
index 00000000..60fb47d3
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/MoxyLoader.java
@@ -0,0 +1,190 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.stream.StreamSource;
+
+import org.eclipse.persistence.dynamic.DynamicEntity;
+import org.eclipse.persistence.jaxb.UnmarshallerProperties;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.introspection.exceptions.AAIUnmarshallingException;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.restcore.MediaType;
+import org.openecomp.aai.workarounds.NamingExceptions;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.base.CaseFormat;
+import com.google.common.collect.ImmutableMap;
+
+public class MoxyLoader extends Loader {
+
+ private DynamicJAXBContext jaxbContext = null;
+ private EELFLogger LOGGER = EELFManager.getInstance().getLogger(MoxyLoader.class);
+ private Map<String, Introspector> allObjs = null;
+
+ /**
+ * Instantiates a new moxy loader.
+ *
+ * @param version the version
+ * @param llBuilder the ll builder
+ */
+ protected MoxyLoader(Version version) {
+ super(version, ModelType.MOXY);
+ process(version);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws AAIUnknownObjectException
+ */
+ @Override
+ public Introspector introspectorFromName(String name) throws AAIUnknownObjectException {
+
+ return IntrospectorFactory.newInstance(ModelType.MOXY, objectFromName(name));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object objectFromName(String name) throws AAIUnknownObjectException {
+
+ final String sanitizedName = NamingExceptions.getInstance().getObjectName(name);
+ final String upperCamel;
+
+ //Contains any uppercase, then assume it's upper camel
+ if (name.matches(".*[A-Z].*")) {
+ upperCamel = sanitizedName;
+ } else {
+ upperCamel = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, sanitizedName);
+ }
+
+ try {
+ final DynamicEntity result = jaxbContext.newDynamicEntity(upperCamel);
+
+ if (result == null) throw new AAIUnknownObjectException("Unrecognized AAI object " + name);
+
+ return result;
+ } catch (IllegalArgumentException e) {
+ //entity does not exist
+ throw new AAIUnknownObjectException("Unrecognized AAI object " + name, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void process(Version version) {
+ ModelInjestor injestor = ModelInjestor.getInstance();
+ jaxbContext = injestor.getContextForVersion(version);
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Introspector unmarshal(String type, String json, MediaType mediaType) throws AAIUnmarshallingException {
+ try {
+ final Object clazz = objectFromName(type);
+ final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+
+ if (mediaType.equals(MediaType.APPLICATION_JSON_TYPE)) {
+ unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
+ unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
+ unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
+ }
+
+ final DynamicEntity entity = (DynamicEntity) unmarshaller.unmarshal(new StreamSource(new StringReader(json)), clazz.getClass()).getValue();
+ return IntrospectorFactory.newInstance(ModelType.MOXY, entity);
+ } catch (JAXBException e) {
+ AAIException ex = new AAIException("AAI_4007", e);
+ ErrorLogHelper.logException(ex);
+ throw new AAIUnmarshallingException("Could not unmarshall: " + e.getMessage(), ex);
+ } catch (AAIUnknownObjectException e) {
+ throw new AAIUnmarshallingException("Could not unmarshall: " + e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public Map<String, Introspector> getAllObjects() {
+ if (this.allObjs != null) {
+ return allObjs;
+ } else {
+ ImmutableMap.Builder<String, Introspector> map = new ImmutableMap.Builder<String, Introspector>();
+ Set<String> objs = objectsInVersion();
+ for (String objName : objs) {
+ try {
+ Introspector introspector = this.introspectorFromName(objName);
+ map.put(introspector.getDbName(), introspector);
+ } catch (AAIUnknownObjectException e) {
+ LOGGER.warn("Unexpected AAIUnknownObjectException while running getAllObjects()", e);
+ }
+ }
+ allObjs = map.build();
+ return allObjs;
+ }
+ }
+
+ private Set<String> objectsInVersion() {
+ final Set<String> result = new HashSet<>();
+
+ try {
+ final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+ final String fileName = ModelInjestor.getInstance().getOXMFileName(getVersion());
+
+ docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+
+ final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
+ final Document doc = docBuilder.parse(fileName);
+ final NodeList list = doc.getElementsByTagName("java-type");
+
+ for (int i = 0; i < list.getLength(); i++) {
+ result.add(list.item(i).getAttributes().getNamedItem("name").getNodeValue());
+ }
+ } catch (ParserConfigurationException | SAXException | IOException e) {
+ LOGGER.warn("Exception while enumerating objects for API version " + getVersion() + " (returning partial results)", e);
+ }
+
+ result.remove("EdgePropNames");
+ return result;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/MoxyStrategy.java b/aai-core/src/main/java/org/openecomp/aai/introspection/MoxyStrategy.java
new file mode 100644
index 00000000..ebebf251
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/MoxyStrategy.java
@@ -0,0 +1,394 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.stream.StreamSource;
+
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.dynamic.DynamicEntity;
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.eclipse.persistence.exceptions.DynamicException;
+import org.eclipse.persistence.jaxb.UnmarshallerProperties;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+import org.eclipse.persistence.mappings.DatabaseMapping;
+import org.eclipse.persistence.oxm.XMLField;
+import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping;
+import org.eclipse.persistence.oxm.mappings.XMLCompositeDirectCollectionMapping;
+import org.springframework.web.util.UriUtils;
+
+import org.openecomp.aai.restcore.MediaType;
+import org.openecomp.aai.schema.enums.ObjectMetadata;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Joiner;
+
+public class MoxyStrategy extends Introspector {
+
+ private DynamicEntity internalObject = null;
+ private DynamicType internalType = null;
+ private DynamicJAXBContext jaxbContext = null;
+ private ClassDescriptor cd = null;
+ private Marshaller marshaller = null;
+ private Unmarshaller unmarshaller = null;
+ private Version version = null;
+ private Set<String> properties = null;
+ private Set<String> keys = null;
+ private Set<String> requiredProperties = null;
+
+ private boolean isInitialized = false;
+
+ protected MoxyStrategy(Object obj) {
+ super(obj);
+ /* must look up the correct jaxbcontext for this object */
+ className = MoxyStrategy.class.getSimpleName();
+ internalObject = (DynamicEntity)obj;
+ ModelInjestor injestor = ModelInjestor.getInstance();
+ version = injestor.getVersionFromClassName(internalObject.getClass().getName());
+ jaxbContext = injestor.getContextForVersion(version);
+ super.loader = LoaderFactory.createLoaderForVersion(getModelType(), version);
+ String simpleName = internalObject.getClass().getName();
+ internalType = jaxbContext.getDynamicType(simpleName);
+ cd = internalType.getDescriptor();
+ try {
+ marshaller = jaxbContext.createMarshaller();
+ unmarshaller = jaxbContext.createUnmarshaller();
+ } catch (JAXBException e) {
+
+ }
+
+ }
+
+ private void init() {
+ isInitialized = true;
+
+ Set<String> props = new LinkedHashSet<>();
+ for (String s : internalType.getPropertiesNames()) {
+ props.add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, s));
+
+ }
+ props = Collections.unmodifiableSet(props);
+ this.properties = props;
+
+ Set<String> requiredProps = new LinkedHashSet<>();
+ requiredProps = new LinkedHashSet<>();
+ for (DatabaseMapping dm : cd.getMappings()) {
+ if (dm.getField() instanceof XMLField) {
+ XMLField x = (XMLField)dm.getField();
+ if (x != null) {
+ if (x.isRequired()) {
+ requiredProps.add(this.removeXPathDescriptor(x.getName()));
+ }
+ }
+ }
+ }
+ requiredProps = Collections.unmodifiableSet(requiredProps);
+ this.requiredProperties = requiredProps;
+
+ Set<String> keys = new LinkedHashSet<>();
+
+ for (String name : internalType.getDescriptor().getPrimaryKeyFieldNames()) {
+ keys.add(this.removeXPathDescriptor(name));
+ }
+ keys = Collections.unmodifiableSet(keys);
+ this.keys = keys;
+
+
+ }
+
+ @Override
+ public boolean hasProperty(String name) {
+ String convertedName = convertPropertyName(name);
+
+ return internalType.containsProperty(convertedName);
+ }
+
+ @Override
+ public Object get(String name) {
+ return internalObject.get(name);
+ }
+
+ @Override
+ public void set(String name, Object obj) throws IllegalArgumentException {
+
+ internalObject.set(name, obj);
+ }
+
+ @Override
+ public Set<String> getProperties() {
+
+ if(!isInitialized){
+ init();
+ }
+
+ return this.properties;
+
+ }
+
+ @Override
+ public Set<String> getRequiredProperties() {
+
+ if(!isInitialized){
+ init();
+ }
+
+ return this.requiredProperties;
+ }
+
+ @Override
+ public Set<String> getKeys() {
+
+ if(!isInitialized){
+ init();
+ }
+
+ return this.keys;
+ }
+
+ @Override
+ public Map<PropertyMetadata, String> getPropertyMetadata(String prop) {
+ String propName = this.convertPropertyName(prop);
+ DatabaseMapping mapping = cd.getMappingForAttributeName(propName);
+ Map<PropertyMetadata, String> result = new HashMap<>();
+ if (mapping != null) {
+ Set<Entry> entrySet = mapping.getProperties().entrySet();
+ for (Entry<?,?> entry : entrySet) {
+ result.put(
+ PropertyMetadata.valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, (String)entry.getKey())), (String)entry.getValue());
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public String getJavaClassName() {
+ return internalObject.getClass().getName();
+ }
+
+
+
+ @Override
+ public Class<?> getClass(String name) {
+ name = convertPropertyName(name);
+ Class<?> resultClass = null;
+ try {
+ if (internalType.getPropertyType(name) == null) {
+ if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) {
+ resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass();
+
+ } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) {
+ resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass();
+ } else {
+ ClassDescriptor referenceDiscriptor = cd.getMappingForAttributeName(name).getReferenceDescriptor();
+ if (referenceDiscriptor != null) {
+ resultClass = referenceDiscriptor.getJavaClass();
+ } else {
+ resultClass = Object.class;
+ }
+ }
+ } else {
+ resultClass = internalType.getPropertyType(name);
+ }
+ } catch (DynamicException e) {
+ //property doesn't exist
+ }
+ return resultClass;
+ }
+
+ @Override
+ public Class<?> getGenericTypeClass(String name) {
+ name = convertPropertyName(name);
+ Class<?> resultClass = null;
+ if (internalType.getPropertyType(name) == null) {
+ if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) {
+ resultClass = cd.getMappingForAttributeName(name).getFields().get(0).getType();
+
+ } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) {
+ resultClass = cd.getMappingForAttributeName(name).getReferenceDescriptor().getJavaClass();
+ }
+ }
+
+ return resultClass;
+ }
+
+ @Override
+ public Object getUnderlyingObject() {
+ return this.internalObject;
+ }
+
+ @Override
+ public String getChildName() {
+
+ String className = internalObject.getClass().getSimpleName();
+ String lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className);
+
+ if (this.isContainer()) {
+ lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,this.getGenericTypeClass(this.getProperties().iterator().next()).getSimpleName());
+ }
+
+ return lowerHyphen;
+ }
+
+ @Override
+ public String getName() {
+ String className = internalObject.getClass().getSimpleName();
+ String lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className);
+ /*
+ if (this.isContainer()) {
+ lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,this.getGenericTypeClass(this.getProperties().get(0)).getSimpleName());
+ }*/
+
+
+ return lowerHyphen;
+ }
+
+ @Override
+ public String getObjectId() throws UnsupportedEncodingException {
+ String result = "";
+ String container = this.getMetadata(ObjectMetadata.CONTAINER);
+ if (this.isContainer()) {
+ result += "/" + this.getName();
+ } else {
+
+ if (container != null) {
+ result += "/" + container;
+ }
+ result += "/" + this.getDbName() + "/" + this.findKey();
+
+ }
+
+ return result;
+ }
+
+ @Override
+ protected String findKey() throws UnsupportedEncodingException {
+ Set<String> keys = null;
+ keys = this.getKeys();
+ List<String> results = new ArrayList<>();
+ for (String key : keys) {
+ if (this.getType(key).toLowerCase().contains("long")) {
+ key = ((Long)this.getValue(key)).toString();
+ } else {
+ key = (String)this.getValue(key);
+ }
+ key = UriUtils.encode(key, "UTF-8");
+
+ results.add(key);
+ }
+
+ return Joiner.on("/").join(results);
+ }
+
+ @Override
+ public String preProcessKey (String key) {
+ String result = "";
+ //String trimmedRestURI = restURI.replaceAll("/[\\w\\-]+?/[\\w\\-]+?$", "");
+ String[] split = key.split("/");
+ int i = 0;
+ for (i = split.length-1; i >= 0; i--) {
+
+ if (jaxbContext.getDynamicType(split[i]) != null) {
+ break;
+
+ }
+
+ }
+ result = Joiner.on("/").join(Arrays.copyOfRange(split, 0, i));
+
+ return result;
+
+ }
+
+ @Override
+ public String marshal(MarshallerProperties properties) {
+ StringWriter result = new StringWriter();
+ try {
+ if (properties.getMediaType().equals(MediaType.APPLICATION_JSON_TYPE)) {
+ marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.MEDIA_TYPE, "application/json");
+ marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_INCLUDE_ROOT, properties.getIncludeRoot());
+ marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, properties.getWrapperAsArrayName());
+ marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, false);
+ }
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, properties.getFormatted());
+ marshaller.marshal(this.internalObject, result);
+ } catch (JAXBException e) {
+ //e.printStackTrace();
+ }
+
+ return result.toString();
+ }
+
+ @Override
+ public Object clone() {
+ Object result = null;
+ try {
+ unmarshaller = jaxbContext.createUnmarshaller();
+
+ unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
+ unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
+ unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
+
+ result = unmarshaller.unmarshal(new StreamSource(new StringReader(this.marshal(true))), this.internalObject.getClass()).getValue();
+ } catch (JAXBException e) {
+ // TODO Auto-generated catch block
+ //e.printStackTrace();
+ }
+ result = IntrospectorFactory.newInstance(getModelType(), result);
+ return result;
+ }
+ @Override
+ public ModelType getModelType() {
+ return ModelType.MOXY;
+ }
+
+ private String removeXPathDescriptor(String name) {
+
+ return name.replaceAll("/text\\(\\)", "");
+ }
+
+ @Override
+ public String getMetadata(ObjectMetadata name) {
+
+ return (String)cd.getProperty(name.toString());
+ }
+
+ @Override
+ public Version getVersion() {
+
+ return this.version;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/PojoInjestor.java b/aai-core/src/main/java/org/openecomp/aai/introspection/PojoInjestor.java
new file mode 100644
index 00000000..116cb787
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/PojoInjestor.java
@@ -0,0 +1,69 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+
+import org.eclipse.persistence.jaxb.JAXBContextFactory;
+
+import org.openecomp.aai.db.props.AAIProperties;
+
+public class PojoInjestor {
+
+ private String POJO_CLASSPATH = "org.openecomp.aai.domain.yang";
+ private final Pattern classNamePattern = Pattern.compile("\\.(v\\d+)\\.");
+
+ public PojoInjestor() {
+ }
+
+ public JAXBContext getContextForVersion(Version v) {
+ JAXBContext context = null;
+ try {
+ if (!v.equals(AAIProperties.LATEST)) {
+ POJO_CLASSPATH += "." + v;
+ }
+ context = JAXBContextFactory.createContext(POJO_CLASSPATH, this.getClass().getClassLoader());
+ } catch (JAXBException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ return context;
+ }
+ public Version getVersion (String classname) {
+ Matcher m = classNamePattern.matcher(classname);
+ String version;
+ if (m.find()) {
+ version = m.group(1);
+ } else {
+ //only POJOs of old versions have the version number in their classnames
+ //so if we can't find a version, default to the latest
+ version = AAIProperties.LATEST.toString();
+ }
+
+ return Version.valueOf(version);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/PojoLoader.java b/aai-core/src/main/java/org/openecomp/aai/introspection/PojoLoader.java
new file mode 100644
index 00000000..ac63e981
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/PojoLoader.java
@@ -0,0 +1,136 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+import java.io.StringReader;
+import java.util.Map;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.stream.StreamSource;
+
+import org.eclipse.persistence.jaxb.UnmarshallerProperties;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.introspection.exceptions.AAIUnmarshallingException;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.restcore.MediaType;
+import org.openecomp.aai.workarounds.NamingExceptions;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.base.CaseFormat;
+import org.eclipse.persistence.jaxb.JAXBContextFactory;
+
+public class PojoLoader extends Loader {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(PojoLoader.class);
+ private static final String POJO_BASE_PACKAGE_NAME = "org.openecomp.aai.domain.yang";
+
+ protected JAXBContext context;
+ private final String pojoPackageName;
+
+ protected PojoLoader(Version version) {
+ super(version, ModelType.POJO);
+
+ if (!version.equals(AAIProperties.LATEST)) {
+ pojoPackageName = POJO_BASE_PACKAGE_NAME + "." + version;
+ } else {
+ pojoPackageName = POJO_BASE_PACKAGE_NAME;
+ }
+
+ try {
+ context = JAXBContextFactory.createContext(pojoPackageName, this.getClass().getClassLoader());
+ } catch (JAXBException e) {
+ LOGGER.error("JAXBException while instantiation contect for PojoLoader", e);
+ }
+ }
+
+ @Override
+ public Introspector introspectorFromName(String name) throws AAIUnknownObjectException {
+ return IntrospectorFactory.newInstance(ModelType.POJO, objectFromName(name));
+ }
+
+ @Override
+ public Object objectFromName(String name) throws AAIUnknownObjectException {
+
+ final String sanitizedName = NamingExceptions.getInstance().getObjectName(name);
+ final String upperCamel;
+
+ //Contains any uppercase, then assume it's upper camel
+ if (sanitizedName.matches(".*[A-Z].*")) {
+ upperCamel = sanitizedName;
+ } else {
+ upperCamel = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, sanitizedName);
+ }
+
+ final String objectClassName;
+
+ if (!upperCamel.contains(pojoPackageName)) {
+ objectClassName = pojoPackageName + "." + upperCamel;
+ } else {
+ objectClassName = upperCamel;
+ }
+
+ try {
+ return Class.forName(objectClassName).newInstance();
+ } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
+ throw new AAIUnknownObjectException("Unrecognized AAI object " + name);
+ }
+ }
+
+ @Override
+ protected void process(Version version) {
+ LOGGER.warn("PojoLoader.process(Version) has not been implemented");
+ }
+
+ @Override
+ public Introspector unmarshal(String type, String json, MediaType mediaType) throws AAIUnmarshallingException {
+
+ try {
+ final Unmarshaller unmarshaller = context.createUnmarshaller();
+
+ if (mediaType.equals(MediaType.APPLICATION_JSON_TYPE)) {
+ unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
+ unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
+ unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
+ }
+
+ final Object clazz = objectFromName(type);
+ final Object obj = unmarshaller.unmarshal(new StreamSource(new StringReader(json)), clazz.getClass()).getValue();
+
+ return IntrospectorFactory.newInstance(ModelType.POJO, obj);
+ } catch (JAXBException e) {
+ ErrorLogHelper.logError("AAI_4007", "Could not unmarshall: " + e.getMessage());
+ throw new AAIUnmarshallingException("Could not unmarshall: " + e.getMessage());
+ } catch (AAIUnknownObjectException e) {
+ throw new AAIUnmarshallingException("Could not unmarshall: " + e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public Map<String, Introspector> getAllObjects() {
+ //TODO
+ return null;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/PojoStrategy.java b/aai-core/src/main/java/org/openecomp/aai/introspection/PojoStrategy.java
new file mode 100644
index 00000000..5632ddf7
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/PojoStrategy.java
@@ -0,0 +1,389 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.transform.stream.StreamSource;
+
+import org.eclipse.persistence.jaxb.UnmarshallerProperties;
+
+import org.openecomp.aai.annotations.Metadata;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.restcore.MediaType;
+import org.openecomp.aai.schema.enums.ObjectMetadata;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Multimap;
+
+public class PojoStrategy extends Introspector {
+
+ private Object internalObject = null;
+ private PojoInjestor injestor = null;
+ private Multimap<String, String> keyProps = null;
+ private Metadata classLevelMetadata = null;
+ private Version version;
+ private JAXBContext jaxbContext;
+ private Marshaller marshaller;
+ private Unmarshaller unmarshaller;
+ private Set<String> properties = null;
+ private Set<String> keys = null;
+ private Set<String> requiredProperties = null;
+
+ private boolean isInitialized = false;
+
+ protected PojoStrategy(Object obj) {
+ super(obj);
+ className = PojoStrategy.class.getSimpleName();
+ this.internalObject = obj;
+ injestor = new PojoInjestor();
+ classLevelMetadata = obj.getClass().getAnnotation(Metadata.class);
+
+ version = injestor.getVersion(obj.getClass().getName());
+ jaxbContext = injestor.getContextForVersion(version);
+ super.loader = LoaderFactory.createLoaderForVersion(getModelType(), version);
+ try {
+ marshaller = jaxbContext.createMarshaller();
+ unmarshaller = jaxbContext.createUnmarshaller();
+ } catch (JAXBException e) {
+
+ }
+
+ }
+
+ private void init() {
+
+ isInitialized = true;
+
+ Set<String> properties = new LinkedHashSet<>();
+ Set<String> keys = new LinkedHashSet<>();
+ Set<String> required = new LinkedHashSet<>();
+
+ Field[] fields = this.internalObject.getClass().getDeclaredFields();
+
+ for (Field field : fields) {
+ if (!field.getName().equals("any")) {
+ properties.add(covertFieldToOutputFormat(field.getName()));
+ Metadata annotation = field.getAnnotation(Metadata.class);
+ XmlElement xmlAnnotation = field.getAnnotation(XmlElement.class);
+ if (annotation != null) {
+ if (annotation.isKey()) {
+ keys.add(covertFieldToOutputFormat(field.getName()));
+ }
+ }
+ if (xmlAnnotation != null) {
+ if (xmlAnnotation.required()) {
+ required.add(covertFieldToOutputFormat(field.getName()));
+ }
+ }
+ }
+ }
+ properties = Collections.unmodifiableSet(properties);
+ this.properties = properties;
+
+ keys = Collections.unmodifiableSet(keys);
+ this.keys = keys;
+
+ required = Collections.unmodifiableSet(required);
+ this.requiredProperties = required;
+
+ }
+ private String covertFieldToOutputFormat(String propName) {
+ return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, propName);
+ }
+
+ @Override
+ public boolean hasProperty(String name) {
+ //TODO
+ return true;
+ }
+
+ @Override
+ /**
+ * Gets the value of the property via reflection
+ */
+ public Object get(String name) {
+ String getMethodName = "get" + CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, name);
+ try {
+ return this.internalObject.getClass().getDeclaredMethod(getMethodName).invoke(this.internalObject);
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public void set(String name, Object value) {
+ String setMethodName = "set" + CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, name);
+ try {
+ this.internalObject.getClass().getDeclaredMethod(setMethodName, value.getClass()).invoke(this.internalObject, value);
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+ ErrorLogHelper.logError("AAI_4017", "Error setting name/value pair on POJO: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public Set<String> getProperties() {
+
+ if(!isInitialized){
+ this.init();
+ }
+ return this.properties;
+ }
+
+
+ @Override
+ public Set<String> getRequiredProperties() {
+
+ if(!isInitialized) {
+ this.init();
+ }
+ return this.requiredProperties;
+ }
+
+ @Override
+ public Set<String> getKeys() {
+
+ if(!isInitialized){
+ this.init();
+ }
+ return this.keys;
+ }
+
+ public Class<?> getClass(String name) {
+
+ Field field = null;
+ try {
+ field = this.internalObject.getClass().getDeclaredField(CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, name));
+ } catch (NoSuchFieldException | SecurityException e) {
+
+ return null;
+ }
+
+ return field.getType();
+ }
+
+ public Class<?> getGenericTypeClass(String name) {
+
+ try {
+ String getMethodName = "get" + CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, name);
+ Method method = internalObject.getClass().getDeclaredMethod(getMethodName);
+ Type t = method.getGenericReturnType();
+ if(t instanceof ParameterizedType) {
+ ParameterizedType pt = (ParameterizedType)t;
+ return ((Class<?>)pt.getActualTypeArguments()[0]);
+ } else {
+ return null;
+ }
+
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ @Override
+ public String getJavaClassName() {
+ return internalObject.getClass().getName();
+ }
+
+ @Override
+ public Object getUnderlyingObject() {
+ return this.internalObject;
+ }
+
+ @Override
+ public String getName() {
+ String className = internalObject.getClass().getSimpleName();
+
+ return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className);
+ }
+
+ @Override
+ protected String findKey() {
+ Set<String> keys = null;
+ keys = this.getKeys();
+ List<String> results = new ArrayList<>();
+ for (String key : keys) {
+ if (this.getType(key).toLowerCase().contains("long")) {
+ key = ((Long)this.getValue(key)).toString();
+ } else {
+ key = (String)this.getValue(key);
+ }
+ results.add(key);
+ }
+
+ return Joiner.on("/").join(results);
+ }
+
+ @Override
+ public String marshal(MarshallerProperties properties) {
+ StringWriter result = new StringWriter();
+ try {
+ if (properties.getMediaType().equals(MediaType.APPLICATION_JSON_TYPE)) {
+ marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.MEDIA_TYPE, "application/json");
+ marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_INCLUDE_ROOT, properties.getIncludeRoot());
+ marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, properties.getWrapperAsArrayName());
+ }
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, properties.getFormatted());
+ marshaller.marshal(this.internalObject, result);
+ } catch (JAXBException e) {
+ //e.printStackTrace();
+ }
+
+ return result.toString();
+ }
+
+ @Override
+ public Object clone() {
+ Object result = null;
+ try {
+ unmarshaller = jaxbContext.createUnmarshaller();
+
+ unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
+ unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
+ unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
+
+ result = unmarshaller.unmarshal(new StreamSource(new StringReader(this.marshal(true))), this.internalObject.getClass()).getValue();
+ } catch (JAXBException e) {
+ // TODO Auto-generated catch block
+ //e.printStackTrace();
+ }
+ result = IntrospectorFactory.newInstance(getModelType(), result);
+ return result;
+ }
+
+ @Override
+ public String preProcessKey (String key) {
+ String result = "";
+ //String trimmedRestURI = restURI.replaceAll("/[\\w\\-]+?/[\\w\\-]+?$", "");
+ String[] split = key.split("/");
+ int i = 0;
+ for (i = split.length-1; i >= 0; i--) {
+
+ if (keyProps.containsKey(split[i])) {
+ break;
+
+ }
+
+ }
+ result = Joiner.on("/").join(Arrays.copyOfRange(split, 0, i));
+
+ return result;
+
+ }
+
+ @Override
+ public ModelType getModelType() {
+ return ModelType.POJO;
+ }
+
+ @Override
+ public String getChildName() {
+ String className = internalObject.getClass().getSimpleName();
+ String lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className);
+
+ if (this.isContainer()) {
+ lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,this.getGenericTypeClass(this.getProperties().iterator().next()).getSimpleName());
+ }
+
+ return lowerHyphen;
+ }
+
+ @Override
+ public Map<PropertyMetadata, String> getPropertyMetadata(String prop) {
+ Field f;
+ Map<PropertyMetadata, String> result = new HashMap<>();
+ try {
+ f = internalObject.getClass().getField(prop);
+ Metadata m = f.getAnnotation(Metadata.class);
+ if (m != null) {
+ Field[] fields = m.getClass().getFields();
+ String fieldName;
+ for (Field field : fields) {
+ fieldName = field.getName();
+ if (fieldName.equals("isAbstract")) {
+ fieldName = "abstract";
+ } else if (fieldName.equals("extendsFrom")) {
+ fieldName = "extends";
+ }
+ fieldName = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, fieldName);
+ result.put(PropertyMetadata.valueOf(fieldName), (String)field.get(m));
+ }
+ }
+ } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+ // TODO Auto-generated catch block
+ }
+
+ return result;
+ }
+
+ @Override
+ public String getObjectId() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getMetadata(ObjectMetadata metadataName) {
+ String value = null;
+ String methodName;
+ if (ObjectMetadata.ABSTRACT.equals(metadataName)) {
+ methodName = "isAbstract";
+ } else if (ObjectMetadata.EXTENDS.equals(metadataName)) {
+ methodName = "extendsFrom";
+ } else {
+ methodName = metadataName.toString();
+ }
+
+ try {
+ value = (String)this.classLevelMetadata.getClass().getMethod(methodName).invoke(classLevelMetadata);
+ } catch (IllegalArgumentException | IllegalAccessException | SecurityException | InvocationTargetException | NoSuchMethodException e) {
+ //TODO
+ }
+
+ return value;
+ }
+
+ @Override
+ public Version getVersion() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/PropertyPredicate.java b/aai-core/src/main/java/org/openecomp/aai/introspection/PropertyPredicate.java
new file mode 100644
index 00000000..5d23aa60
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/PropertyPredicate.java
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+import java.util.function.BiPredicate;
+import java.util.function.Predicate;
+
+public interface PropertyPredicate<T, U> extends BiPredicate<T, U> {
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/PropertyPredicates.java b/aai-core/src/main/java/org/openecomp/aai/introspection/PropertyPredicates.java
new file mode 100644
index 00000000..eeca0864
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/PropertyPredicates.java
@@ -0,0 +1,77 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+
+public final class PropertyPredicates {
+
+ private PropertyPredicates() {
+
+ }
+
+ public static PropertyPredicate<Introspector, String> includeInTestGeneration() {
+ return (obj, prop) -> {
+ final Map<PropertyMetadata, String> map = obj.getPropertyMetadata(prop);
+ if (map.containsKey(PropertyMetadata.VISIBILITY)) {
+ return !(Visibility.internal.equals(Visibility.valueOf(map.get(PropertyMetadata.VISIBILITY)))
+ || Visibility.deployment.equals(Visibility.valueOf(map.get(PropertyMetadata.VISIBILITY))));
+ }
+ if (map.containsKey("dataLocation")) {
+ return false;
+ }
+ return true;
+ };
+ }
+
+ public static PropertyPredicate<Introspector, String> isVisible() {
+ return (obj, prop) -> {
+ final Map<PropertyMetadata, String> map = obj.getPropertyMetadata(prop);
+ if (map.containsKey(PropertyMetadata.VISIBILITY)) {
+ return !Visibility.internal.equals(Visibility.valueOf(map.get(PropertyMetadata.VISIBILITY)));
+ }
+ return true;
+ };
+ }
+
+ public static PropertyPredicate<Introspector, String> includeInExamples() {
+ return (obj, prop) -> {
+ final Map<PropertyMetadata, String> map = obj.getPropertyMetadata(prop);
+ if (map.containsKey(PropertyMetadata.VISIBILITY)) {
+ return !Visibility.internal.equals(Visibility.valueOf(map.get(PropertyMetadata.VISIBILITY)));
+ }
+ if (map.containsKey("dataLocation")) {
+ return false;
+ }
+ return true;
+ };
+ }
+
+ public static PropertyPredicate<Introspector, String> isIndexed() {
+ return (obj, prop) -> {
+ Set<String> indexed = obj.getIndexedProperties();
+ return indexed.contains(prop);
+ };
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/Version.java b/aai-core/src/main/java/org/openecomp/aai/introspection/Version.java
new file mode 100644
index 00000000..fdb7a91e
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/Version.java
@@ -0,0 +1,27 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+public enum Version {
+ v8,
+ v9,
+ v10;
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/Visibility.java b/aai-core/src/main/java/org/openecomp/aai/introspection/Visibility.java
new file mode 100644
index 00000000..b9126c5b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/Visibility.java
@@ -0,0 +1,29 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+public enum Visibility {
+
+ internal,
+ external,
+ deployment,
+ all
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/Wanderer.java b/aai-core/src/main/java/org/openecomp/aai/introspection/Wanderer.java
new file mode 100644
index 00000000..217366d4
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/Wanderer.java
@@ -0,0 +1,83 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection;
+
+import java.util.List;
+
+import org.openecomp.aai.exceptions.AAIException;
+
+public interface Wanderer {
+
+ /**
+ * Process primitive.
+ *
+ * @param propName the prop name
+ * @param obj the obj
+ */
+ public void processPrimitive(String propName, Introspector obj);
+
+ /**
+ * Process primitive list.
+ *
+ * @param propName the prop name
+ * @param obj the obj
+ */
+ public void processPrimitiveList(String propName, Introspector obj);
+
+ /**
+ * Process complex obj.
+ *
+ * @param obj the obj
+ * @throws AAIException
+ */
+ public void processComplexObj(Introspector obj) throws AAIException;
+
+ /**
+ * Modify complex list.
+ *
+ * @param list the list
+ * @param listReference TODO
+ * @param parent the parent
+ * @param child the child
+ */
+ public void modifyComplexList(List<Introspector> list, List<Object> listReference, Introspector parent, Introspector child);
+
+ /**
+ * Creates the complex obj if null.
+ *
+ * @return true, if successful
+ */
+ public default boolean createComplexObjIfNull() {
+ return false;
+ }
+
+ /**
+ * Creates the complex list size.
+ *
+ * @param parent the parent
+ * @param child the child
+ * @return the int
+ */
+ public default int createComplexListSize(Introspector parent, Introspector child) {
+ return 0;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/exceptions/AAIUnknownObjectException.java b/aai-core/src/main/java/org/openecomp/aai/introspection/exceptions/AAIUnknownObjectException.java
new file mode 100644
index 00000000..ed0b3207
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/exceptions/AAIUnknownObjectException.java
@@ -0,0 +1,42 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.exceptions;
+
+import org.openecomp.aai.exceptions.AAIException;
+
+public class AAIUnknownObjectException extends AAIException {
+
+ private static final long serialVersionUID = -504200228742133774L;
+
+ public AAIUnknownObjectException() {}
+
+ public AAIUnknownObjectException(String message) {
+ super("AAI_3000", message);
+ }
+
+ public AAIUnknownObjectException(Throwable cause) {
+ super("AAI_3000", cause);
+ }
+
+ public AAIUnknownObjectException(String message, Throwable cause) {
+ super("AAI_3000", cause, message);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/exceptions/AAIUnmarshallingException.java b/aai-core/src/main/java/org/openecomp/aai/introspection/exceptions/AAIUnmarshallingException.java
new file mode 100644
index 00000000..edc06b3a
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/exceptions/AAIUnmarshallingException.java
@@ -0,0 +1,42 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.exceptions;
+
+import org.openecomp.aai.exceptions.AAIException;
+
+public class AAIUnmarshallingException extends AAIException {
+
+ private static final long serialVersionUID = -5615651557821878103L;
+
+ public AAIUnmarshallingException() {}
+
+ public AAIUnmarshallingException(String message) {
+ super("AAI_3000", message);
+ }
+
+ public AAIUnmarshallingException(Throwable cause) {
+ super("AAI_3000",cause);
+ }
+
+ public AAIUnmarshallingException(String message, Throwable cause) {
+ super("AAI_3000", cause, message);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/generator/CreateExample.java b/aai-core/src/main/java/org/openecomp/aai/introspection/generator/CreateExample.java
new file mode 100644
index 00000000..fba4525e
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/generator/CreateExample.java
@@ -0,0 +1,170 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.generator;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.IntrospectorWalker;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.PropertyPredicates;
+import org.openecomp.aai.introspection.Wanderer;
+
+public class CreateExample implements Wanderer {
+
+ private Random rand = new Random();
+ private final long range = 100000000L;
+ private Loader loader = null;
+ private Introspector result = null;
+ private String objectName = null;
+ private List<String> blacklist = null;
+
+ /**
+ * Instantiates a new creates the example.
+ *
+ * @param loader the loader
+ * @param objectName the object name
+ */
+ public CreateExample(Loader loader, String objectName) {
+
+ this.loader = loader;
+ this.objectName = objectName;
+ this.blacklist = new ArrayList<>();
+
+ }
+
+ /**
+ * Gets the example object.
+ *
+ * @return the example object
+ * @throws AAIException
+ */
+ public Introspector getExampleObject() throws AAIException {
+ result = loader.introspectorFromName(objectName);
+ blacklist = new ArrayList<>();
+ blacklist.add("any");
+ blacklist.add("relationship-list");
+ if (!result.isContainer()) {
+ blacklist.add("resource-version");
+ }
+ IntrospectorWalker walker = new IntrospectorWalker(this, PropertyPredicates.includeInExamples());
+
+ walker.preventCycles(true);
+ walker.setBlacklist(blacklist);
+ walker.walk(result);
+ //this.getExampleObject(result);
+
+ return result;
+ }
+
+ /**
+ * Gets the value.
+ *
+ * @param property the property
+ * @param type the type
+ * @param suffix the suffix
+ * @return the value
+ */
+ private Object getValue(String property, String type, String suffix) {
+ long randLong = (long)(rand.nextDouble()*range);
+ Integer randInt = rand.nextInt(100000);
+ Integer randShrt = rand.nextInt(20000);
+ short randShort = randShrt.shortValue();
+
+ Object newObj = null;
+ if (type.contains("java.lang.String")) {
+ newObj = "example-" + property + "-val-" + randInt + suffix;
+ } else if ( type.toLowerCase().equals("long") ||type.contains("java.lang.Long")) {
+ newObj = randLong;
+ } else if(type.toLowerCase().equals("boolean") || type.contains("java.lang.Boolean")){
+ newObj = Boolean.TRUE;
+ } else if ( type.toLowerCase().equals("int") || type.contains("java.lang.Integer")){
+ newObj = randInt;
+ } else if ( type.toLowerCase().equals("short") || type.contains("java.lang.Short")){
+ newObj = randShort;
+ }
+
+ return newObj;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void processPrimitive(String propName, Introspector obj) {
+ String propType = obj.getType(propName);
+
+ Object val = this.getValue(propName, propType, "");
+ obj.setValue(propName, val);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void processPrimitiveList(String propName, Introspector obj) {
+ int listSize = 2;
+ String propType = "";
+ List<Object> list = new ArrayList<>();
+ for (int i = 0; i < listSize; i++) {
+ propType = obj.getGenericType(propName);
+ Object val = this.getValue(propName, propType, "-" + (i + 1));
+ list.add(val);
+ }
+ obj.setValue(propName, list);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void processComplexObj(Introspector obj) {
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void modifyComplexList(List<Introspector> list, List<Object> listReference, Introspector parent, Introspector child) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean createComplexObjIfNull() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int createComplexListSize(Introspector parent, Introspector child) {
+ return 1;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataCopy.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataCopy.java
new file mode 100644
index 00000000..98ff219c
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataCopy.java
@@ -0,0 +1,91 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.sideeffect;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Optional;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.sideeffect.exceptions.AAIMissingRequiredPropertyException;
+import org.openecomp.aai.introspection.sideeffect.exceptions.AAIMultiplePropertiesException;
+import org.openecomp.aai.parsers.query.QueryParser;
+import org.openecomp.aai.restcore.util.URITools;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+
+
+public class DataCopy extends SideEffect {
+
+
+ public DataCopy(Introspector obj, Vertex self, TransactionalGraphEngine dbEngine, DBSerializer serializer) {
+ super(obj, self, dbEngine, serializer);
+ }
+
+ @Override
+ protected void processURI(Optional<String> completeUri, Entry<String, String> entry) throws URISyntaxException, UnsupportedEncodingException, AAIException {
+ if (completeUri.isPresent()) {
+ URI uri = new URI(completeUri.get());
+ MultivaluedMap<String, String> map = URITools.getQueryMap(uri);
+ QueryParser uriQuery = dbEngine.getQueryBuilder(this.latestLoader).createQueryFromURI(uri, map);
+ List<Vertex> results = uriQuery.getQueryBuilder().toList();
+ Introspector resultObj = this.latestLoader.introspectorFromName(uriQuery.getResultType());
+ if (results.size() == 1) {
+ serializer.dbToObject(Collections.singletonList(results.get(0)), resultObj, 0, true, "false");
+ try {
+ obj.setValue(entry.getKey(), Objects.requireNonNull(resultObj.getValue(uri.getFragment()), uri.getFragment() + " was null"));
+ } catch (NullPointerException e) {
+ throw new AAIMissingRequiredPropertyException("property " + uri.getFragment() + " not found at " + uri);
+ }
+ } else {
+ if (results.isEmpty()) {
+ throw new AAIException("AAI_6114", "object located at " + uri + " not found");
+ } else if (results.size() > 1) {
+ throw new AAIMultiplePropertiesException("multiple values of " + entry.getKey() + " found when searching " + uri);
+ }
+ }
+ } else {
+ //skip processing because no required properties were specified
+ }
+ }
+
+ @Override
+ protected PropertyMetadata getPropertyMetadata() {
+ return PropertyMetadata.DATA_COPY;
+ }
+
+ @Override
+ protected boolean replaceWithWildcard() {
+ return false;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataLinkReader.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataLinkReader.java
new file mode 100644
index 00000000..81562f0b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataLinkReader.java
@@ -0,0 +1,97 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.sideeffect;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.sideeffect.exceptions.AAIMissingRequiredPropertyException;
+import org.openecomp.aai.parsers.query.QueryParser;
+import org.openecomp.aai.restcore.util.URITools;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+
+import javax.ws.rs.core.MultivaluedMap;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.regex.Matcher;
+
+public class DataLinkReader extends SideEffect {
+
+ public DataLinkReader(Introspector obj, Vertex self, TransactionalGraphEngine dbEngine, DBSerializer serializer) {
+ super(obj, self, dbEngine, serializer);
+ }
+
+ @Override
+ protected boolean replaceWithWildcard() {
+ return true;
+ }
+
+ @Override
+ protected PropertyMetadata getPropertyMetadata() {
+ return PropertyMetadata.DATA_LINK;
+ }
+
+ @Override
+ protected void processURI(Optional<String> completeUri, Entry<String, String> entry)
+ throws URISyntaxException, UnsupportedEncodingException, AAIException {
+
+ if (completeUri.isPresent()) {
+ URI uri = new URI(completeUri.get());
+ MultivaluedMap<String, String> map = URITools.getQueryMap(uri);
+ QueryParser uriQuery = dbEngine.getQueryBuilder(this.latestLoader).createQueryFromURI(uri, map);
+ List<Vertex> results = uriQuery.getQueryBuilder().getVerticesByProperty(AAIProperties.LINKED, true).toList();
+ if (results.size() == 1) {
+ if (results.get(0).<Boolean>property(AAIProperties.LINKED).orElse(false) && obj.getValue(entry.getKey()) == null) {
+ obj.setValue(entry.getKey(), results.get(0).property(entry.getKey()).orElse(null));
+ }
+ } else {
+ //log something about not being able to return any values because there was more than one
+ }
+ }
+ }
+
+ /**
+ * always fuzzy search on reads
+ */
+ @Override
+ protected Map<String, String> findProperties(Introspector obj, String uriString) throws AAIMissingRequiredPropertyException {
+
+ final Map<String, String> result = new HashMap<>();
+ Matcher m = template.matcher(uriString);
+ while (m.find()) {
+ String propName = m.group(1);
+ if (replaceWithWildcard()) {
+ result.put(propName, "*");
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataLinkWriter.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataLinkWriter.java
new file mode 100644
index 00000000..09a1ce18
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/DataLinkWriter.java
@@ -0,0 +1,111 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.sideeffect;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Optional;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.sideeffect.exceptions.AAIMultiplePropertiesException;
+import org.openecomp.aai.parsers.query.QueryParser;
+import org.openecomp.aai.parsers.uri.URIToObject;
+import org.openecomp.aai.restcore.util.URITools;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+
+public class DataLinkWriter extends SideEffect {
+
+ public DataLinkWriter(Introspector obj, Vertex self, TransactionalGraphEngine dbEngine, DBSerializer serializer) {
+ super(obj, self, dbEngine, serializer);
+ }
+
+ @Override
+ protected PropertyMetadata getPropertyMetadata() {
+ return PropertyMetadata.DATA_LINK;
+ }
+
+ @Override
+ protected void processURI(Optional<String> completeUri, Entry<String, String> entry)
+ throws URISyntaxException, UnsupportedEncodingException, AAIException {
+ if (completeUri.isPresent()) {
+ URI uri = new URI(completeUri.get());
+ MultivaluedMap<String, String> map = URITools.getQueryMap(uri);
+ QueryParser uriQuery = dbEngine.getQueryBuilder(this.latestLoader).createQueryFromURI(uri, map);
+ List<Vertex> results = uriQuery.getQueryBuilder().toList();
+ if (results.size() == 1) {
+ if (results.get(0).<Boolean>property(AAIProperties.LINKED).orElse(false) && obj.getValue(entry.getKey()) == null) {
+ //delete vertex because property was removed
+ serializer.delete(results.get(0), "", false);
+ } else {
+ //link vertex that already exists
+ this.addLinkedProperty(results.get(0));
+ }
+ } else {
+ if (results.isEmpty()) {
+ //locate previously linked vertex
+ List<Vertex> linkedVertices = uriQuery.getQueryBuilder().getContainerQuery().getVerticesByProperty(AAIProperties.LINKED, true).toList();
+ if (!linkedVertices.isEmpty()) {
+ if (linkedVertices.size() > 1) {
+ throw new AAIMultiplePropertiesException("multiple vertices found for single cardinality propery found when searching " + uri);
+ } else {
+ //found one, remove the linked property because it didn't match the uri
+ linkedVertices.get(0).property(AAIProperties.LINKED).remove();
+ }
+ }
+ if (obj.getValue(entry.getKey()) != null) {
+ //add new vertex to database if we have values
+ URIToObject parser = new URIToObject(this.latestLoader, uri);
+ Introspector resultObj = parser.getEntity();
+ Vertex newV = serializer.createNewVertex(resultObj);
+ serializer.serializeToDb(resultObj, newV, uriQuery, completeUri.get(), this.latestLoader.getVersion().toString());
+ this.addLinkedProperty(newV);
+ }
+ } else if (results.size() > 1) {
+ throw new AAIMultiplePropertiesException("multiple values of " + entry.getKey() + " found when searching " + uri);
+ }
+ }
+ } else {
+ //skip processing because no required properties were specified
+ }
+ }
+
+ @Override
+ protected boolean replaceWithWildcard() {
+ return true;
+ }
+
+ private void addLinkedProperty(Vertex v) {
+ v.property(AAIProperties.LINKED, true);
+ }
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffect.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffect.java
new file mode 100644
index 00000000..3691651c
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffect.java
@@ -0,0 +1,133 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.sideeffect;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.LoaderFactory;
+import org.openecomp.aai.introspection.ModelType;
+import org.openecomp.aai.introspection.sideeffect.exceptions.AAIMissingRequiredPropertyException;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+
+public abstract class SideEffect {
+
+ protected static final Pattern template = Pattern.compile("\\{(.*?)\\}");
+ protected final Introspector obj;
+ protected final TransactionalGraphEngine dbEngine;
+ protected final DBSerializer serializer;
+ protected final Loader latestLoader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, AAIProperties.LATEST);
+ protected final Vertex self;
+ public SideEffect (Introspector obj, Vertex self, TransactionalGraphEngine dbEngine, DBSerializer serializer) {
+ this.obj = obj;
+ this.dbEngine = dbEngine;
+ this.serializer = serializer;
+ this.self = self;
+ }
+
+ protected void execute() throws UnsupportedEncodingException, URISyntaxException, AAIException {
+ final Map<String, String> properties = this.findPopertiesWithMetadata(obj, this.getPropertyMetadata());
+ for (Entry<String, String> entry : properties.entrySet()) {
+ Optional<String> populatedUri = this.replaceTemplates(obj, entry.getValue());
+ Optional<String> completeUri = this.resolveRelativePath(populatedUri);
+ this.processURI(completeUri, entry);
+ }
+ }
+
+ protected Map<String, String> findPopertiesWithMetadata(Introspector obj, PropertyMetadata metadata) {
+ final Map<String, String> result = new HashMap<>();
+ for (String prop : obj.getProperties()) {
+ final Map<PropertyMetadata, String> map = obj.getPropertyMetadata(prop);
+ if (map.containsKey(metadata)) {
+ result.put(prop, map.get(metadata));
+ }
+ }
+ return result;
+ }
+
+ protected Map<String, String> findProperties(Introspector obj, String uriString) throws AAIMissingRequiredPropertyException {
+
+ final Map<String, String> result = new HashMap<>();
+ final Set<String> missing = new LinkedHashSet<>();
+ Matcher m = template.matcher(uriString);
+ int properties = 0;
+ while (m.find()) {
+ String propName = m.group(1);
+ String value = obj.getValue(propName);
+ properties++;
+ if (value != null) {
+ result.put(propName, value);
+ } else {
+ if (replaceWithWildcard()) {
+ result.put(propName, "*");
+ }
+ missing.add(propName);
+ }
+ }
+
+ if (!missing.isEmpty() && (properties != missing.size())) {
+ throw new AAIMissingRequiredPropertyException("Cannot complete " + this.getPropertyMetadata().toString() + " uri. Missing properties " + missing);
+ }
+ return result;
+ }
+
+ private Optional<String> replaceTemplates(Introspector obj, String uriString) throws AAIMissingRequiredPropertyException {
+ String result = uriString;
+ final Map<String, String> propMap = this.findProperties(obj, uriString);
+ if (propMap.isEmpty()) {
+ return Optional.empty();
+ }
+ for (Entry<String, String> entry : propMap.entrySet()) {
+ result = result.replaceAll("\\{" + entry.getKey() + "\\}", entry.getValue());
+ }
+ //drop out wildcards if they exist
+ result = result.replaceFirst("/[^/]+?(?:/\\*)+", "");
+ return Optional.of(result);
+ }
+
+ private Optional<String> resolveRelativePath(Optional<String> populatedUri) throws UnsupportedEncodingException {
+ if (!populatedUri.isPresent()) {
+ return Optional.empty();
+ } else {
+ return Optional.of(populatedUri.get().replaceFirst("\\./", this.serializer.getURIForVertex(self) + "/"));
+ }
+ }
+
+ protected abstract boolean replaceWithWildcard();
+ protected abstract PropertyMetadata getPropertyMetadata();
+ protected abstract void processURI(Optional<String> completeUri, Entry<String, String> entry) throws URISyntaxException, UnsupportedEncodingException, AAIException;
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffectRunner.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffectRunner.java
new file mode 100644
index 00000000..17127da7
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffectRunner.java
@@ -0,0 +1,99 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.sideeffect;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URISyntaxException;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+public class SideEffectRunner {
+
+ protected final TransactionalGraphEngine dbEngine;
+ protected final DBSerializer serializer;
+ protected final Set<Class<? extends SideEffect>> sideEffects;
+ protected SideEffectRunner(Builder builder) {
+ this.dbEngine = builder.getDbEngine();
+ this.serializer = builder.getSerializer();
+ this.sideEffects = builder.getSideEffects();
+ }
+
+ public void execute(Introspector obj, Vertex self) throws AAIException {
+
+ for (Class<? extends SideEffect> se : sideEffects) {
+ try {
+ se.getConstructor(Introspector.class, Vertex.class, TransactionalGraphEngine.class, DBSerializer.class)
+ .newInstance(obj, self, dbEngine, serializer).execute();
+ } catch (UnsupportedEncodingException | InstantiationException | IllegalAccessException
+ | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException
+ | URISyntaxException e) {
+ throw new AAIException("strange exception", e);
+ }
+ }
+ }
+
+ public static class Builder {
+
+ private final TransactionalGraphEngine dbEngine;
+ private final DBSerializer serializer;
+ private final Set<Class<? extends SideEffect>> sideEffects;
+
+ public Builder(final TransactionalGraphEngine dbEngine, final DBSerializer serializer) {
+ this.dbEngine = dbEngine;
+ this.serializer = serializer;
+ this.sideEffects = new LinkedHashSet<>();
+ }
+
+ public Builder addSideEffect(Class<? extends SideEffect> se) {
+ sideEffects.add(se);
+ return this;
+ }
+
+ public Builder addSideEffects(Class<? extends SideEffect>... sideEffects) {
+ for (Class<? extends SideEffect> se : sideEffects) {
+ this.addSideEffect(se);
+ }
+ return this;
+ }
+
+ public SideEffectRunner build() {
+ return new SideEffectRunner(this);
+ }
+ protected TransactionalGraphEngine getDbEngine() {
+ return dbEngine;
+ }
+
+ protected DBSerializer getSerializer() {
+ return serializer;
+ }
+
+ protected Set<Class<? extends SideEffect>> getSideEffects() {
+ return sideEffects;
+ }
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffectRunnerHelper.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffectRunnerHelper.java
new file mode 100644
index 00000000..9d214623
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/SideEffectRunnerHelper.java
@@ -0,0 +1,85 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.sideeffect;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Wanderer;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Set;
+
+class SideEffectRunnerHelper implements Wanderer {
+
+
+ protected final TransactionalGraphEngine dbEngine;
+ protected final DBSerializer serializer;
+ protected final Set<Class<? extends SideEffect>> sideEffects;
+ protected SideEffectRunnerHelper(final TransactionalGraphEngine dbEngine, final DBSerializer serializer, final Set<Class<? extends SideEffect>> sideEffects) {
+ this.dbEngine = dbEngine;
+ this.serializer = serializer;
+ this.sideEffects = sideEffects;
+ }
+
+ private void runSideEffects(Introspector obj) throws AAIException {
+ for (Class<? extends SideEffect> se : sideEffects) {
+ try {
+ se.getConstructor(Introspector.class, TransactionalGraphEngine.class, DBSerializer.class)
+ .newInstance(obj, dbEngine, serializer).execute();
+ } catch (UnsupportedEncodingException | InstantiationException | IllegalAccessException
+ | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException
+ | URISyntaxException e) {
+ throw new AAIException("strange exception", e);
+ }
+ }
+ }
+ @Override
+ public void processPrimitive(String propName, Introspector obj) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void processPrimitiveList(String propName, Introspector obj) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void processComplexObj(Introspector obj) throws AAIException {
+
+ runSideEffects(obj);
+
+ }
+
+ @Override
+ public void modifyComplexList(List<Introspector> list, List<Object> listReference, Introspector parent,
+ Introspector child) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/exceptions/AAIMissingRequiredPropertyException.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/exceptions/AAIMissingRequiredPropertyException.java
new file mode 100644
index 00000000..9131f249
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/exceptions/AAIMissingRequiredPropertyException.java
@@ -0,0 +1,45 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.sideeffect.exceptions;
+
+import org.openecomp.aai.exceptions.AAIException;
+
+public class AAIMissingRequiredPropertyException extends AAIException {
+
+
+ private static final long serialVersionUID = -8907079650472014019L;
+
+ public AAIMissingRequiredPropertyException() {}
+
+ public AAIMissingRequiredPropertyException(String message) {
+ super("AAI_5107", message);
+ }
+
+ public AAIMissingRequiredPropertyException(Throwable cause) {
+ super("AAI_5107",cause);
+ }
+
+ public AAIMissingRequiredPropertyException(String message, Throwable cause) {
+ super("AAI_5107", cause, message);
+ }
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/exceptions/AAIMultiplePropertiesException.java b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/exceptions/AAIMultiplePropertiesException.java
new file mode 100644
index 00000000..0525b1b7
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/sideeffect/exceptions/AAIMultiplePropertiesException.java
@@ -0,0 +1,44 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.sideeffect.exceptions;
+
+import org.openecomp.aai.exceptions.AAIException;
+
+public class AAIMultiplePropertiesException extends AAIException {
+
+ private static final long serialVersionUID = 2098371383166008345L;
+
+ public AAIMultiplePropertiesException() {}
+
+ public AAIMultiplePropertiesException(String message) {
+ super("AAI_6136", message);
+ }
+
+ public AAIMultiplePropertiesException(Throwable cause) {
+ super("AAI_6136",cause);
+ }
+
+ public AAIMultiplePropertiesException(String message, Throwable cause) {
+ super("AAI_6136", cause, message);
+ }
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/CreateUUID.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/CreateUUID.java
new file mode 100644
index 00000000..8932da2c
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/CreateUUID.java
@@ -0,0 +1,49 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.tools;
+
+import java.util.Map;
+import java.util.UUID;
+
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+
+public class CreateUUID implements IssueResolver {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean resolveIssue(Issue issue) {
+
+ Introspector obj = issue.getIntrospector();
+ if (issue.getType().equals(IssueType.MISSING_KEY_PROP)) {
+ Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(issue.getPropName());
+ if (metadata.containsKey(PropertyMetadata.AUTO_GENERATE_UUID) && metadata.get(PropertyMetadata.AUTO_GENERATE_UUID).equals("true")) {
+ obj.setValue(issue.getPropName(), UUID.randomUUID().toString());
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/DefaultFields.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/DefaultFields.java
new file mode 100644
index 00000000..8a1143f0
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/DefaultFields.java
@@ -0,0 +1,48 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.tools;
+
+import java.util.Map;
+
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+
+public class DefaultFields implements IssueResolver {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean resolveIssue(Issue issue) {
+
+ Introspector obj = issue.getIntrospector();
+ if (issue.getType().equals(IssueType.MISSING_REQUIRED_PROP)) {
+ Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(issue.getPropName());
+ if (metadata.containsKey(PropertyMetadata.DEFAULT_VALUE)) {
+ obj.setValue(issue.getPropName(), metadata.get(PropertyMetadata.DEFAULT_VALUE));
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/InjectKeysFromURI.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/InjectKeysFromURI.java
new file mode 100644
index 00000000..23855363
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/InjectKeysFromURI.java
@@ -0,0 +1,69 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.tools;
+
+import java.net.URI;
+
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.parsers.uri.URIToObject;
+
+public class InjectKeysFromURI implements IssueResolver {
+
+ private URI uri = null;
+ private Loader loader = null;
+
+ /**
+ * Instantiates a new inject keys from URI.
+ *
+ * @param loader the loader
+ * @param uri the uri
+ */
+ public InjectKeysFromURI(Loader loader, URI uri) {
+ this.loader = loader;
+ this.uri = uri;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean resolveIssue(Issue issue) {
+ boolean result = false;
+ Introspector obj = issue.getIntrospector();
+ if (issue.getType().equals(IssueType.MISSING_KEY_PROP)) {
+ try {
+ URIToObject toObject = new URIToObject(loader, uri);
+ Introspector minimumObj = toObject.getEntity();
+ if (toObject.getEntityName().equals(obj.getDbName())) {
+ obj.setValue(issue.getPropName(), minimumObj.getValue(issue.getPropName()));
+ result = true;
+ }
+ } catch (Exception e) {
+ //log something probably
+ result = false;
+ }
+ }
+
+ return result;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IntrospectorValidator.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IntrospectorValidator.java
new file mode 100644
index 00000000..0e5b4bcd
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IntrospectorValidator.java
@@ -0,0 +1,314 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.tools;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.IntrospectorWalker;
+import org.openecomp.aai.introspection.Visibility;
+import org.openecomp.aai.introspection.Wanderer;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+
+public class IntrospectorValidator implements Wanderer {
+
+
+ private List<Issue> issues = null;
+ private List<IssueResolver> issueResolvers = null;
+ private boolean validateRequired = true;
+ private final int maximumDepth;
+ private int currentDepth = 0;
+
+ private final Set<String> relationshipChain;
+ /**
+ * Instantiates a new introspector validator.
+ *
+ * @param builder the builder
+ */
+ private IntrospectorValidator(IntrospectorValidator.Builder builder) {
+ this.validateRequired = builder.getValidateRequired();
+ this.issueResolvers = builder.getResolvers();
+ this.maximumDepth = builder.getMaximumDepth();
+ issues = new ArrayList<>();
+
+ relationshipChain = new HashSet<>();
+
+ relationshipChain.add("relationship-list");
+ relationshipChain.add("relationship");
+ relationshipChain.add("relationship-data");
+ relationshipChain.add("related-to-property");
+
+
+ }
+
+ /**
+ * Validate.
+ *
+ * @param obj the obj
+ * @return true, if successful
+ * @throws AAIException
+ */
+ public boolean validate(Introspector obj) throws AAIException {
+ IntrospectorWalker walker = new IntrospectorWalker(this);
+ this.currentDepth = 0;
+ walker.walk(obj);
+
+ for (Issue m : issues) {
+ if (!m.getSeverity().equals(Severity.WARNING)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Gets the issues.
+ *
+ * @return the issues
+ */
+ public List<Issue> getIssues() {
+ return this.issues;
+ }
+
+ /**
+ * Sets the issue resolvers.
+ *
+ * @param resolvers the new issue resolvers
+ */
+ public void setIssueResolvers(List<IssueResolver> resolvers) {
+ issueResolvers = new ArrayList<>();
+ for (IssueResolver resolver : resolvers) {
+ issueResolvers.add(resolver);
+ }
+ }
+
+ /**
+ * Resolve issues.
+ *
+ * @return true, if successful
+ */
+ public boolean resolveIssues() {
+ boolean result = true;
+ for (Issue issue : issues) {
+ for (IssueResolver resolver : issueResolvers) {
+ if (resolver.resolveIssue(issue)) {
+ issue.setResolved(true);
+ }
+ }
+ if (!issue.isResolved()) {
+ result = false;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void processComplexObj(Introspector obj) {
+
+ if (this.currentDepth > this.maximumDepth && !relationshipChain.contains(obj.getDbName())) {
+ Issue message =
+ this.buildMessage(Severity.CRITICAL, IssueType.EXCEEDED_ALLOWED_DEPTH, "Maximum allowed depth of this object has been exceeded on: " + obj.getDbName());
+ message.setIntrospector(obj);
+ issues.add(message);
+ }
+ Set<String> requiredProps = obj.getRequiredProperties();
+ Set<String> keys = obj.getKeys();
+ Set<String> props = obj.getProperties();
+
+ for (String prop : props) {
+ Object value = obj.getValue(prop);
+ if (keys.contains(prop)) {
+ if (value == null) {
+ Issue message =
+ this.buildMessage(Severity.CRITICAL, IssueType.MISSING_KEY_PROP, "Missing key property: " + prop);
+ message.setIntrospector(obj);
+ message.setPropName(prop);
+ issues.add(message);
+ }
+ } else if (requiredProps.contains(prop)) {
+ if (value == null && validateRequired) {
+ Issue message =
+ this.buildMessage(Severity.CRITICAL, IssueType.MISSING_REQUIRED_PROP, "Missing required property: " + prop);
+ message.setIntrospector(obj);
+ message.setPropName(prop);
+ issues.add(message);
+ }
+ }
+
+ final Optional<String> visibility = obj.getPropertyMetadata(prop, PropertyMetadata.VISIBILITY);
+ if(visibility.isPresent() && Visibility.internal.equals(Visibility.valueOf(visibility.get()))) {
+ Issue message =
+ this.buildMessage(Severity.ERROR, IssueType.PROPERTY_NOT_VISIBLE, "client attemptted to set property not visible: " + prop);
+ message.setIntrospector(obj);
+ message.setPropName(prop);
+ issues.add(message);
+
+ }
+ }
+
+ if (!relationshipChain.contains(obj.getDbName())) {
+ this.currentDepth++;
+ }
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void processPrimitive(String propName, Introspector obj) {
+ //NO OP
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void processPrimitiveList(String propName, Introspector obj) {
+ //NO OP
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void modifyComplexList(List<Introspector> list, List<Object> listReference, Introspector parent, Introspector child) {
+ //NO OP
+ }
+
+
+ /**
+ * Builds the message.
+ *
+ * @param severity the severity
+ * @param error the error
+ * @param detail the detail
+ * @return the issue
+ */
+ private Issue buildMessage(Severity severity, IssueType error, String detail) {
+ Issue message = new Issue();
+ message.setSeverity(severity);
+ message.setType(error);
+ message.setDetail(detail);
+
+ return message;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean createComplexObjIfNull() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int createComplexListSize(Introspector parent, Introspector child) {
+ return 0;
+ }
+
+ public static class Builder {
+
+ private boolean validateRequired = true;
+ private List<IssueResolver> issueResolvers = null;
+ private int maximumDepth = AAIProperties.MAXIMUM_DEPTH;
+ /**
+ * Instantiates a new builder.
+ *
+ * @param llBuilder the ll builder
+ */
+ public Builder() {
+ issueResolvers = new ArrayList<IssueResolver>();
+ }
+
+ /**
+ * Validate required.
+ *
+ * @param validateRequired the validate required
+ * @return the builder
+ */
+ public Builder validateRequired(boolean validateRequired) {
+ this.validateRequired = validateRequired;
+ return this;
+ }
+
+ public Builder restrictDepth(int depth) {
+ this.maximumDepth = depth;
+ return this;
+ }
+ /**
+ * Adds the resolver.
+ *
+ * @param resolver the resolver
+ * @return the builder
+ */
+ public Builder addResolver(IssueResolver resolver) {
+ issueResolvers.add(resolver);
+ return this;
+ }
+
+ /**
+ * Builds the.
+ *
+ * @return the introspector validator
+ */
+ public IntrospectorValidator build() {
+ return new IntrospectorValidator(this);
+ }
+
+ /**
+ * Gets the validate required.
+ *
+ * @return the validate required
+ */
+ public boolean getValidateRequired() {
+ return this.validateRequired;
+ }
+
+ /**
+ * Gets the resolvers.
+ *
+ * @return the resolvers
+ */
+ public List<IssueResolver> getResolvers() {
+ return this.issueResolvers;
+ }
+
+ public int getMaximumDepth() {
+ return this.maximumDepth;
+ }
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/Issue.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/Issue.java
new file mode 100644
index 00000000..b95643c1
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/Issue.java
@@ -0,0 +1,144 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.tools;
+
+import org.openecomp.aai.introspection.Introspector;
+
+public class Issue {
+
+ private Severity severity;
+ private IssueType error;
+ private String detail;
+ private Introspector obj;
+ private String propName;
+ private boolean resolved = false;
+
+ /**
+ * Sets the severity.
+ *
+ * @param severity the new severity
+ */
+ public void setSeverity(Severity severity) {
+
+ this.severity = severity;
+ }
+
+ /**
+ * Sets the error.
+ *
+ * @param error the new error
+ */
+ public void setType(IssueType error) {
+ this.error = error;
+ }
+
+ /**
+ * Sets the detail.
+ *
+ * @param detail the new detail
+ */
+ public void setDetail(String detail) {
+ this.detail = detail;
+ }
+
+ /**
+ * Gets the severity.
+ *
+ * @return the severity
+ */
+ public Object getSeverity() {
+ return this.severity;
+ }
+
+ /**
+ * Sets the introspector.
+ *
+ * @param obj the new introspector
+ */
+ public void setIntrospector(Introspector obj) {
+ this.obj = obj;
+ }
+
+ /**
+ * Gets the introspector.
+ *
+ * @return the introspector
+ */
+ public Introspector getIntrospector() {
+ return this.obj;
+ }
+
+ /**
+ * Gets the detail.
+ *
+ * @return the detail
+ */
+ public String getDetail() {
+ return this.detail;
+ }
+
+ /**
+ * Gets the error.
+ *
+ * @return the error
+ */
+ public IssueType getType() {
+ return this.error;
+ }
+
+ /**
+ * Sets the prop name.
+ *
+ * @param prop the new prop name
+ */
+ public void setPropName(String prop) {
+ this.propName= prop;
+ }
+
+ /**
+ * Gets the prop name.
+ *
+ * @return the prop name
+ */
+ public String getPropName() {
+ return this.propName;
+ }
+
+ /**
+ * Checks if is resolved.
+ *
+ * @return true, if is resolved
+ */
+ public boolean isResolved() {
+ return resolved;
+ }
+
+ /**
+ * Sets the resolved.
+ *
+ * @param resolved the new resolved
+ */
+ public void setResolved(boolean resolved) {
+ this.resolved = resolved;
+ }
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IssueResolver.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IssueResolver.java
new file mode 100644
index 00000000..409a1c02
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IssueResolver.java
@@ -0,0 +1,33 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.tools;
+
+public interface IssueResolver {
+
+
+ /**
+ * Resolve issue.
+ *
+ * @param issue the issue
+ * @return true, if successful
+ */
+ public boolean resolveIssue(Issue issue);
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IssueType.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IssueType.java
new file mode 100644
index 00000000..fad06d9a
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/IssueType.java
@@ -0,0 +1,25 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.tools;
+
+public enum IssueType {
+ MISSING_REQUIRED_PROP, MISSING_KEY_PROP, EXCEEDED_ALLOWED_DEPTH, PROPERTY_NOT_VISIBLE
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/RemoveNonVisibleProperty.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/RemoveNonVisibleProperty.java
new file mode 100644
index 00000000..2bf6afcc
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/RemoveNonVisibleProperty.java
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.tools;
+
+public class RemoveNonVisibleProperty implements IssueResolver {
+
+ @Override
+ public boolean resolveIssue(Issue issue) {
+
+ if (IssueType.PROPERTY_NOT_VISIBLE.equals(issue.getType())) {
+ //remove property value
+ issue.getIntrospector().setValue(issue.getPropName(), null);
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/tools/Severity.java b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/Severity.java
new file mode 100644
index 00000000..17663f16
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/introspection/tools/Severity.java
@@ -0,0 +1,27 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.introspection.tools;
+
+public enum Severity {
+ WARNING,
+ ERROR,
+ CRITICAL
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/CNName.java b/aai-core/src/main/java/org/openecomp/aai/logging/CNName.java
new file mode 100644
index 00000000..28afd56a
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/CNName.java
@@ -0,0 +1,93 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+import ch.qos.logback.access.pattern.AccessConverter;
+import ch.qos.logback.access.spi.IAccessEvent;
+
+import javax.security.auth.x500.X500Principal;
+import javax.servlet.http.HttpServletRequest;
+import java.security.cert.X509Certificate;
+
+import static java.util.Base64.getDecoder;
+
+public class CNName extends AccessConverter {
+
+ /**
+ * Converts access events to String response codes
+ *
+ * @param accessEvent the IAccessEvent
+ */
+ public String convert(IAccessEvent accessEvent) {
+ if (!isStarted()) {
+ return "INACTIVE_HEADER_CONV";
+ }
+
+ String cipherSuite = (String) accessEvent.getRequest().getAttribute("javax.servlet.request.cipher_suite");
+ String authUser = null;
+ if (cipherSuite != null) {
+ try {
+ X509Certificate certChain[] = (X509Certificate[]) accessEvent.getRequest()
+ .getAttribute("javax.servlet.request.X509Certificate");
+ if(certChain == null || certChain.length == 0){
+
+ HttpServletRequest request = accessEvent.getRequest();
+
+ String authorization = request.getHeader("Authorization");
+
+ // Set the auth user to "-" so if the authorization header is not found
+ // Or if the decoded basic auth credentials are not found in the format required
+ // it should return "-"
+ // If the decoded string is in the right format, find the index of ":"
+ // Then get the substring of the starting point to the colon not including the colon
+
+ authUser = "-";
+
+ if(authorization != null && authorization.startsWith("Basic ")){
+ String credentials = authorization.replace("Basic ", "");
+ byte[] userCredentials = getDecoder().decode(credentials.getBytes("utf-8"));
+ credentials = new String(userCredentials);
+
+ int codePoint = credentials.indexOf(':');
+
+ if(codePoint != -1){
+ authUser = credentials.substring(0, codePoint);
+ }
+
+ }
+
+ return authUser;
+
+ } else {
+ X509Certificate clientCert = certChain[0];
+ X500Principal subjectDN = clientCert.getSubjectX500Principal();
+ authUser = subjectDN.toString();
+ return authUser;
+ }
+ } catch(Exception ex){
+ return "-";
+ }
+ } else {
+ return "-";
+ }
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/CustomLogPatternLayout.java b/aai-core/src/main/java/org/openecomp/aai/logging/CustomLogPatternLayout.java
new file mode 100644
index 00000000..0b2df03b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/CustomLogPatternLayout.java
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+public class CustomLogPatternLayout extends ch.qos.logback.access.PatternLayout {
+ static {
+ defaultConverterMap.put("z", CNName.class.getName());
+ defaultConverterMap.put("y", DME2RestFlag.class.getName());
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/CustomLogPatternLayoutEncoder.java b/aai-core/src/main/java/org/openecomp/aai/logging/CustomLogPatternLayoutEncoder.java
new file mode 100644
index 00000000..b335109b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/CustomLogPatternLayoutEncoder.java
@@ -0,0 +1,40 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+import ch.qos.logback.access.PatternLayout;
+
+public class CustomLogPatternLayoutEncoder extends ch.qos.logback.access.PatternLayoutEncoder {
+
+/**
+ * @{inheritDoc}
+ */
+ @Override
+ public void start(){
+ PatternLayout patternLayout = new CustomLogPatternLayout();
+ patternLayout.setContext(context);
+ patternLayout.setPattern(getPattern());
+ patternLayout.start();
+ this.layout = patternLayout;
+ super.start();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/DME2RestFlag.java b/aai-core/src/main/java/org/openecomp/aai/logging/DME2RestFlag.java
new file mode 100644
index 00000000..b5426452
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/DME2RestFlag.java
@@ -0,0 +1,55 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+import ch.qos.logback.access.pattern.AccessConverter;
+import ch.qos.logback.access.spi.IAccessEvent;
+
+public class DME2RestFlag extends AccessConverter {
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public String convert(IAccessEvent accessEvent) {
+ if (!isStarted()) {
+ return "INACTIVE_HEADER_CONV";
+ }
+
+ String flag = "-";
+
+ if (accessEvent.getRequestParameter("envContext").length > 0
+ && !accessEvent.getRequestParameter("envContext")[0].isEmpty()
+ && !accessEvent.getRequestParameter("envContext")[0].equals("-")
+ && accessEvent.getRequestParameter("routeOffer").length > 0
+ && !accessEvent.getRequestParameter("routeOffer")[0].isEmpty()
+ && !accessEvent.getRequestParameter("routeOffer")[0].equals("-")
+ && accessEvent.getRequestParameter("version").length > 0
+ && !accessEvent.getRequestParameter("version")[0].isEmpty()
+ && !accessEvent.getRequestParameter("version")[0].equals("-")) {
+ flag = "DME2";
+ } else {
+ flag = "REST";
+ }
+
+ return flag;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/EcompElapsedTime.java b/aai-core/src/main/java/org/openecomp/aai/logging/EcompElapsedTime.java
new file mode 100644
index 00000000..1593e856
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/EcompElapsedTime.java
@@ -0,0 +1,66 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+import ch.qos.logback.classic.pattern.ClassicConverter;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import org.openecomp.aai.logging.LoggingContext.LoggingField;
+
+public class EcompElapsedTime extends ClassicConverter {
+
+ private static final String DEFAULT_ELAPSED_TIME_FORMAT = "%d";
+
+ private String ELAPSED_TIME_FORMAT;
+
+ @Override
+ public void start() {
+ ELAPSED_TIME_FORMAT = getFirstOption();
+ }
+
+ @Override
+ public String convert(ILoggingEvent event) {
+ final long end = event.getTimeStamp();
+
+ if (!event.getMDCPropertyMap().containsKey(LoggingField.START_TIME.toString())) {
+ return format(0);
+ } else if (event.getMDCPropertyMap().containsKey(LoggingField.ELAPSED_TIME.toString())) {
+ return format(
+ Integer.parseInt(event.getMDCPropertyMap().get(LoggingField.ELAPSED_TIME.toString()))
+ );
+ }
+
+ final long start = LogFormatTools.toTimestamp(event.getMDCPropertyMap().get(LoggingField.START_TIME.toString()));
+
+ return format(end - start);
+ }
+
+ private String format(long elapsedTime) {
+ if (ELAPSED_TIME_FORMAT == null) {
+ return format(DEFAULT_ELAPSED_TIME_FORMAT, elapsedTime);
+ }
+
+ return format (ELAPSED_TIME_FORMAT, elapsedTime);
+ }
+
+ private String format(String format, long elapsedTime) {
+ return String.format(format, elapsedTime);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/EcompEncoder.java b/aai-core/src/main/java/org/openecomp/aai/logging/EcompEncoder.java
new file mode 100644
index 00000000..daaa90de
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/EcompEncoder.java
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+import ch.qos.logback.classic.PatternLayout;
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
+
+public class EcompEncoder extends PatternLayoutEncoder {
+
+ @Override
+ public void start() {
+ PatternLayout patternLayout = new EcompPatternLayout();
+ patternLayout.setContext(context);
+ patternLayout.setPattern(getPattern());
+ patternLayout.setOutputPatternAsHeader(outputPatternAsHeader);
+ patternLayout.start();
+ this.layout = patternLayout;
+ super.start();
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/EcompPatternLayout.java b/aai-core/src/main/java/org/openecomp/aai/logging/EcompPatternLayout.java
new file mode 100644
index 00000000..296e3b81
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/EcompPatternLayout.java
@@ -0,0 +1,31 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+import ch.qos.logback.classic.PatternLayout;
+
+public class EcompPatternLayout extends PatternLayout {
+ static {
+ PatternLayout.defaultConverterMap.put("ecompStartTime", EcompStartTime.class.getName());
+ PatternLayout.defaultConverterMap.put("ecompElapsedTime", EcompElapsedTime.class.getName());
+ PatternLayout.defaultConverterMap.put("eelfClassOfCaller", EelfClassOfCaller.class.getName());
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/EcompStartTime.java b/aai-core/src/main/java/org/openecomp/aai/logging/EcompStartTime.java
new file mode 100644
index 00000000..89cd81d2
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/EcompStartTime.java
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+import ch.qos.logback.classic.pattern.ClassicConverter;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import org.openecomp.aai.logging.LoggingContext.LoggingField;
+
+public class EcompStartTime extends ClassicConverter {
+
+ @Override
+ public String convert(ILoggingEvent event) {
+
+ if (!event.getMDCPropertyMap().containsKey(LoggingField.START_TIME.toString())) {
+ return LogFormatTools.toDate(event.getTimeStamp());
+ }
+
+ return event.getMDCPropertyMap().get(LoggingField.START_TIME.toString());
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/EelfClassOfCaller.java b/aai-core/src/main/java/org/openecomp/aai/logging/EelfClassOfCaller.java
new file mode 100644
index 00000000..a90fcc8d
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/EelfClassOfCaller.java
@@ -0,0 +1,43 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+import ch.qos.logback.classic.pattern.NamedConverter;
+import ch.qos.logback.classic.spi.CallerData;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+
+public class EelfClassOfCaller extends NamedConverter {
+ protected String getFullyQualifiedName(ILoggingEvent event) {
+
+ StackTraceElement[] cda = event.getCallerData();
+
+ //If using the EELFLogger, it "hides" the calling class because it wraps the logging calls
+ //Without this, you'd only ever see "com.att.eelf.configuration.SLF4jWrapper" when using the
+ // %C pattern converter
+ if (cda != null && cda.length > 2) {
+ return cda[2].getClassName();
+ } else if (cda != null && cda.length > 0) {
+ return cda[0].getClassName();
+ } else {
+ return CallerData.NA;
+ }
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/ErrorLogHelper.java b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorLogHelper.java
new file mode 100644
index 00000000..dae30220
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorLogHelper.java
@@ -0,0 +1,587 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.apache.commons.lang.StringUtils;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.logging.LoggingContext.StatusCode;
+import org.openecomp.aai.util.AAIConstants;
+import org.openecomp.aai.util.MapperUtil;
+import org.slf4j.MDC;
+
+import javax.ws.rs.core.MediaType;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+ *
+ * This classes loads the application error properties file
+ * and provides a method that returns an ErrorObject
+ *
+ */
+
+public class ErrorLogHelper {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ErrorLogHelper.class);
+ private static final HashMap<String, ErrorObject> ERROR_OBJECTS = new HashMap<String, ErrorObject> ();
+
+ static {
+ try {
+ loadProperties();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load error.properties file", e);
+ } catch (ErrorObjectFormatException e) {
+ throw new RuntimeException("Failed to parse error.properties file", e);
+ }
+ }
+
+ /**
+ * Load properties.
+ * @throws ErrorObjectFormatException
+ * @throws Exception the exception
+ */
+ public static void loadProperties() throws IOException, ErrorObjectFormatException {
+ final String filePath = AAIConstants.AAI_HOME_ETC_APP_PROPERTIES + "error.properties";
+ final InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);
+ final Properties properties = new Properties();
+
+ if (is != null) {
+ properties.load(is);
+ } else {
+ try (final FileInputStream fis = new FileInputStream(filePath)) {
+ properties.load(fis);
+ }
+ }
+
+ for (Entry<Object, Object> entry : properties.entrySet()) {
+ final String key = (String) entry.getKey();
+ final String value = (String) entry.getValue();
+ final String[] errorProperties = value.split(":");
+
+ if (errorProperties.length != 7) throw new ErrorObjectFormatException();
+
+ final ErrorObject errorObject = new ErrorObject();
+
+ errorObject.setDisposition(errorProperties[0].trim());
+ errorObject.setCategory(errorProperties[1].trim());
+ errorObject.setSeverity(errorProperties[2].trim());
+ errorObject.setErrorCode(errorProperties[3].trim());
+ errorObject.setHTTPResponseCode(errorProperties[4].trim());
+ errorObject.setRESTErrorCode(errorProperties[5].trim());
+ errorObject.setErrorText(errorProperties[6].trim());
+
+ ERROR_OBJECTS.put(key, errorObject);
+ }
+ }
+
+ /**
+ * Logs a known A&AI exception (i.e. one that can be found in error.properties)
+ *
+ * @param key The key for the error in the error.properties file
+ * @throws IOException
+ * @throws ErrorObjectNotFoundException
+ * @throws ErrorObjectFormatException
+ */
+ public static ErrorObject getErrorObject(String code) throws ErrorObjectNotFoundException {
+
+ if (code == null) throw new IllegalArgumentException("Key cannot be null");
+
+ final ErrorObject errorObject = ERROR_OBJECTS.get(code);
+
+ if (errorObject == null) {
+ LOGGER.warn("Unknown AAIException with code=" + code + ". Using default AAIException");
+ return ERROR_OBJECTS.get(AAIException.DEFAULT_EXCEPTION_CODE);
+ }
+
+ return errorObject;
+ }
+
+ /**
+ * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error.
+ * The AAIRESTException may contain a different ErrorObject than that created with the REST error key.
+ * This allows lower level exception detail to be returned to the client to help troubleshoot the problem.
+ * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException.
+ * @param are must have a restError value whose numeric value must match what should be returned in the REST API
+ * @param variables optional list of variables to flesh out text in error string
+ * @return appropriately formatted JSON response per the REST API spec.
+ * @throws ErrorObjectFormatException
+ * @throws ErrorObjectNotFoundException
+ * @throws IOException
+ * @deprecated
+ */
+ public static String getRESTAPIErrorResponse(AAIException are, ArrayList<String> variables) {
+ List<MediaType> acceptHeaders = new ArrayList<MediaType>();
+ acceptHeaders.add(MediaType.APPLICATION_JSON_TYPE);
+
+ return getRESTAPIErrorResponse(acceptHeaders, are, variables);
+ }
+
+ /**
+ * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error.
+ * The AAIRESTException may contain a different ErrorObject than that created with the REST error key.
+ * This allows lower level exception detail to be returned to the client to help troubleshoot the problem.
+ * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException.
+ *
+ * @param acceptHeadersOrig the accept headers orig
+ * @param are must have a restError value whose numeric value must match what should be returned in the REST API
+ * @param variables optional list of variables to flesh out text in error string
+ * @return appropriately formatted JSON response per the REST API spec.
+ * @throws ErrorObjectFormatException
+ * @throws ErrorObjectNotFoundException
+ * @throws IOException
+ */
+ public static String getRESTAPIErrorResponse(List<MediaType> acceptHeadersOrig, AAIException are, ArrayList<String> variables) {
+
+
+ StringBuilder text = new StringBuilder();
+ String response = null;
+
+ List<MediaType> acceptHeaders = new ArrayList<MediaType>();
+ // we might have an exception but no accept header, so we'll set default to JSON
+ boolean foundValidAcceptHeader = false;
+ for (MediaType mt : acceptHeadersOrig) {
+ if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt) ||
+ MediaType.APPLICATION_JSON_TYPE.isCompatible(mt)) {
+ acceptHeaders.add(mt);
+ foundValidAcceptHeader = true;
+ }
+ }
+ if (foundValidAcceptHeader == false) {
+ // override the exception, client needs to set an appropriate Accept header
+ are = new AAIException("AAI_4014");
+ acceptHeaders.add(MediaType.APPLICATION_JSON_TYPE);
+ }
+
+ final ErrorObject eo = are.getErrorObject();
+
+ int restErrorCode = Integer.parseInt(eo.getRESTErrorCode());
+
+ ErrorObject restErrorObject;
+
+ try {
+ restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+restErrorCode);
+ } catch (ErrorObjectNotFoundException e) {
+ LOGGER.warn("Failed to find related error object AAI_" + restErrorCode + " for error object " + eo.getErrorCode() + "; using AAI_" + restErrorCode);
+ restErrorObject = eo;
+ }
+
+ text.append(restErrorObject.getErrorText());
+
+ // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n
+ // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the
+ // error, are ordered based on the error string.
+ int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%");
+ text.append(" (msg=%").append(localDataIndex+1).append(") (ec=%").append(localDataIndex+2).append(")");
+
+ if (variables == null)
+ {
+ variables = new ArrayList<String>();
+ }
+
+ if (variables.size() < localDataIndex) {
+ ErrorLogHelper.logError("AAI_4011", "data missing for rest error");
+ while (variables.size() < localDataIndex) {
+ variables.add("null");
+ }
+ }
+
+ // This will put the error code and error text into the right positions
+ if (are.getMessage() == null || are.getMessage().length() == 0) {
+ variables.add(localDataIndex++, eo.getErrorText());
+ }
+ else {
+ variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage());
+ }
+ variables.add(localDataIndex, eo.getErrorCodeString());
+
+ for (MediaType mediaType : acceptHeaders) {
+ if (MediaType.APPLICATION_XML_TYPE.isCompatible(mediaType)) {
+ JAXBContext context = null;
+ try {
+ if(eo.getCategory().equals("1")) {
+
+ context = JAXBContext.newInstance(org.openecomp.aai.domain.restPolicyException.Fault.class);
+ Marshaller m = context.createMarshaller();
+ m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+ m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
+
+ org.openecomp.aai.domain.restPolicyException.ObjectFactory factory = new org.openecomp.aai.domain.restPolicyException.ObjectFactory();
+ org.openecomp.aai.domain.restPolicyException.Fault fault = factory.createFault();
+ org.openecomp.aai.domain.restPolicyException.Fault.RequestError requestError = factory.createFaultRequestError();
+ org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException policyException = factory.createFaultRequestErrorPolicyException();
+ org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException.Variables polvariables = factory.createFaultRequestErrorPolicyExceptionVariables();
+
+ policyException.setMessageId("POL" + eo.getRESTErrorCode());
+ policyException.setText(text.toString());
+ for (int i=0;i<variables.size();i++)
+ {
+ polvariables.getVariable().add(variables.get(i));
+ }
+ policyException.setVariables(polvariables);
+ requestError.setPolicyException(policyException);
+ fault.setRequestError(requestError);
+
+ StringWriter sw = new StringWriter();
+ m.marshal(fault, sw);
+
+ response = sw.toString();
+
+ } else {
+
+ context = JAXBContext.newInstance(org.openecomp.aai.domain.restServiceException.Fault.class);
+ Marshaller m = context.createMarshaller();
+ m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+ m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
+
+ org.openecomp.aai.domain.restServiceException.ObjectFactory factory = new org.openecomp.aai.domain.restServiceException.ObjectFactory();
+ org.openecomp.aai.domain.restServiceException.Fault fault = factory.createFault();
+ org.openecomp.aai.domain.restServiceException.Fault.RequestError requestError = factory.createFaultRequestError();
+ org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException serviceException = factory.createFaultRequestErrorServiceException();
+ org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException.Variables svcvariables = factory.createFaultRequestErrorServiceExceptionVariables();
+ serviceException.setMessageId("SVC" + eo.getRESTErrorCode());
+ serviceException.setText(text.toString());
+ for (int i=0;i<variables.size();i++)
+ {
+ svcvariables.getVariable().add(variables.get(i));
+ }
+ serviceException.setVariables(svcvariables);
+ requestError.setServiceException(serviceException);
+ fault.setRequestError(requestError);
+
+ StringWriter sw = new StringWriter();
+ m.marshal(fault, sw);
+
+ response = sw.toString();
+
+ }
+ } catch (Exception ex) {
+ LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
+ }
+ }
+ else {
+ try {
+ if(eo.getCategory().equals("1")) {
+ org.openecomp.aai.domain.restPolicyException.RESTResponse restresp = new org.openecomp.aai.domain.restPolicyException.RESTResponse();
+ org.openecomp.aai.domain.restPolicyException.RequestError reqerr = new org.openecomp.aai.domain.restPolicyException.RequestError();
+ org.openecomp.aai.domain.restPolicyException.PolicyException polexc = new org.openecomp.aai.domain.restPolicyException.PolicyException();
+ polexc.setMessageId("POL" + eo.getRESTErrorCode());
+ polexc.setText(text.toString());
+ polexc.setVariables(variables);
+ reqerr.setPolicyException(polexc);
+ restresp.setRequestError(reqerr);
+ response = (MapperUtil.writeAsJSONString((Object) restresp));
+
+ } else {
+ org.openecomp.aai.domain.restServiceException.RESTResponse restresp = new org.openecomp.aai.domain.restServiceException.RESTResponse();
+ org.openecomp.aai.domain.restServiceException.RequestError reqerr = new org.openecomp.aai.domain.restServiceException.RequestError();
+ org.openecomp.aai.domain.restServiceException.ServiceException svcexc = new org.openecomp.aai.domain.restServiceException.ServiceException();
+ svcexc.setMessageId("SVC" + eo.getRESTErrorCode());
+ svcexc.setText(text.toString());
+ svcexc.setVariables(variables);
+ reqerr.setServiceException(svcexc);
+ restresp.setRequestError(reqerr);
+ response = (MapperUtil.writeAsJSONString((Object) restresp));
+ }
+ } catch (AAIException ex) {
+ LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
+ }
+ }
+ }
+
+
+ return response;
+ }
+
+ /**
+ * Gets the RESTAPI error response with logging.
+ *
+ * @param acceptHeadersOrig the accept headers orig
+ * @param are the are
+ * @param variables the variables
+ * @param logline the logline
+ * @return the RESTAPI error response with logging
+ * @throws ErrorObjectFormatException
+ * @throws ErrorObjectNotFoundException
+ * @throws IOException
+ */
+ public static String getRESTAPIErrorResponseWithLogging(List<MediaType> acceptHeadersOrig, AAIException are, ArrayList<String> variables) {
+ String response = ErrorLogHelper.getRESTAPIErrorResponse(acceptHeadersOrig, are, variables);
+
+ LOGGER.error(are.getMessage(), are);
+
+ return response;
+ }
+
+ /**
+ * Gets the RESTAPI info response.
+ *
+ * @param acceptHeaders the accept headers
+ * @param areList the are list
+ * @return the RESTAPI info response
+ * @throws ErrorObjectFormatException
+ * @throws ErrorObjectNotFoundException
+ * @throws IOException
+ */
+ public static Object getRESTAPIInfoResponse(List<MediaType> acceptHeaders, HashMap<AAIException,ArrayList<String>> areList) {
+
+ Object respObj = null;
+
+ org.openecomp.aai.domain.restResponseInfo.ObjectFactory factory = new org.openecomp.aai.domain.restResponseInfo.ObjectFactory();
+ org.openecomp.aai.domain.restResponseInfo.Info info = factory.createInfo();
+ org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages responseMessages = factory.createInfoResponseMessages();
+ Iterator<Entry<AAIException, ArrayList<String>>> it = areList.entrySet().iterator();
+
+ while (it.hasNext()) {
+ Entry<AAIException,ArrayList<String>> pair = (Entry<AAIException, ArrayList<String>>)it.next();
+ AAIException are = pair.getKey();
+ ArrayList<String> variables = pair.getValue();
+
+ StringBuilder text = new StringBuilder();
+
+ ErrorObject eo = are.getErrorObject();
+
+ int restErrorCode = Integer.parseInt(eo.getRESTErrorCode());
+ ErrorObject restErrorObject;
+ try {
+ restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+String.format("%04d", restErrorCode));
+ } catch (ErrorObjectNotFoundException e) {
+ restErrorObject = eo;
+ }
+ text.append(restErrorObject.getErrorText());
+
+ // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n
+ // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the
+ // error, are ordered based on the error string.
+ int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%");
+ text.append(" (msg=%").append(localDataIndex+1).append(") (rc=%").append(localDataIndex+2).append(")");
+
+ if (variables == null)
+ {
+ variables = new ArrayList<String>();
+ }
+
+ if (variables.size() < localDataIndex) {
+ ErrorLogHelper.logError("AAI_4011", "data missing for rest error");
+ while (variables.size() < localDataIndex) {
+ variables.add("null");
+ }
+ }
+
+ // This will put the error code and error text into the right positions
+ if (are.getMessage() == null) {
+ variables.add(localDataIndex++, eo.getErrorText());
+ }
+ else {
+ variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage());
+ }
+ variables.add(localDataIndex, eo.getErrorCodeString());
+
+ try {
+ org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages.ResponseMessage responseMessage = factory.createInfoResponseMessagesResponseMessage();
+ org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages.ResponseMessage.Variables infovariables = factory.createInfoResponseMessagesResponseMessageVariables();
+
+ responseMessage.setMessageId("INF" + eo.getRESTErrorCode());
+ responseMessage.setText(text.toString());
+ for (int i=0;i<variables.size();i++)
+ {
+ infovariables.getVariable().add(variables.get(i));
+ }
+
+ responseMessage.setVariables(infovariables);
+ responseMessages.getResponseMessage().add(responseMessage);
+
+ } catch (Exception ex) {
+ LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
+ }
+ }
+
+ info.setResponseMessages(responseMessages);
+ respObj = (Object) info;
+
+ return respObj;
+ }
+
+
+ /**
+ * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error.
+ * The AAIRESTException may contain a different ErrorObject than that created with the REST error key.
+ * This allows lower level exception detail to be returned to the client to help troubleshoot the problem.
+ * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException.
+ * @param are must have a restError value whose numeric value must match what should be returned in the REST API
+ * @param variables optional list of variables to flesh out text in error string
+ * @return appropriately formatted JSON response per the REST API spec.
+ * @throws ErrorObjectFormatException
+ * @throws ErrorObjectNotFoundException
+ * @throws IOException
+ */
+ public static String getRESTAPIPolicyErrorResponseXML(AAIException are, ArrayList<String> variables) {
+
+ StringBuilder text = new StringBuilder();
+ String response = null;
+ JAXBContext context = null;
+
+ ErrorObject eo = are.getErrorObject();
+
+ int restErrorCode = Integer.parseInt(eo.getRESTErrorCode());
+ ErrorObject restErrorObject;
+ try {
+ restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+restErrorCode);
+ } catch (ErrorObjectNotFoundException e) {
+ restErrorObject = eo;
+ }
+
+ text.append(restErrorObject.getErrorText());
+
+ // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n
+ // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the
+ // error, are ordered based on the error string.
+ int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%");
+ text.append(" (msg=%").append(localDataIndex+1).append(") (ec=%").append(localDataIndex+2).append(")");
+
+ if (variables == null)
+ {
+ variables = new ArrayList<String>();
+ }
+
+ if (variables.size() < localDataIndex) {
+ ErrorLogHelper.logError("AAI_4011", "data missing for rest error");
+ while (variables.size() < localDataIndex) {
+ variables.add("null");
+ }
+ }
+
+ // This will put the error code and error text into the right positions
+ if (are.getMessage() == null) {
+ variables.add(localDataIndex++, eo.getErrorText());
+ }
+ else {
+ variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage());
+ }
+ variables.add(localDataIndex, eo.getErrorCodeString());
+
+ try {
+ if(eo.getCategory().equals("1")) {
+
+ context = JAXBContext.newInstance(org.openecomp.aai.domain.restPolicyException.Fault.class);
+ Marshaller m = context.createMarshaller();
+ m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+ m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
+
+ org.openecomp.aai.domain.restPolicyException.ObjectFactory factory = new org.openecomp.aai.domain.restPolicyException.ObjectFactory();
+ org.openecomp.aai.domain.restPolicyException.Fault fault = factory.createFault();
+ org.openecomp.aai.domain.restPolicyException.Fault.RequestError requestError = factory.createFaultRequestError();
+ org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException policyException = factory.createFaultRequestErrorPolicyException();
+ org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException.Variables polvariables = factory.createFaultRequestErrorPolicyExceptionVariables();
+
+ policyException.setMessageId("POL" + eo.getRESTErrorCode());
+ policyException.setText(text.toString());
+ for (int i=0;i<variables.size();i++)
+ {
+ polvariables.getVariable().add(variables.get(i));
+ }
+ policyException.setVariables(polvariables);
+ requestError.setPolicyException(policyException);
+ fault.setRequestError(requestError);
+
+ StringWriter sw = new StringWriter();
+ m.marshal(fault, sw);
+
+ response = sw.toString();
+
+ } else {
+
+ context = JAXBContext.newInstance(org.openecomp.aai.domain.restServiceException.Fault.class);
+ Marshaller m = context.createMarshaller();
+ m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+ m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
+
+ org.openecomp.aai.domain.restServiceException.ObjectFactory factory = new org.openecomp.aai.domain.restServiceException.ObjectFactory();
+ org.openecomp.aai.domain.restServiceException.Fault fault = factory.createFault();
+ org.openecomp.aai.domain.restServiceException.Fault.RequestError requestError = factory.createFaultRequestError();
+ org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException serviceException = factory.createFaultRequestErrorServiceException();
+ org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException.Variables svcvariables = factory.createFaultRequestErrorServiceExceptionVariables();
+ serviceException.setMessageId("POL" + eo.getRESTErrorCode());
+ serviceException.setText(text.toString());
+ for (int i=0;i<variables.size();i++)
+ {
+ svcvariables.getVariable().add(variables.get(i));
+ }
+ serviceException.setVariables(svcvariables);
+ requestError.setServiceException(serviceException);
+ fault.setRequestError(requestError);
+
+ StringWriter sw = new StringWriter();
+ m.marshal(fault, sw);
+
+ response = sw.toString();
+
+ }
+ } catch (Exception ex) {
+ LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
+ }
+ return response;
+ }
+
+ public static void logException(AAIException e) {
+ final ErrorObject errorObject = e.getErrorObject();
+
+ MDC.put("severity", errorObject.getSeverity()); //TODO Use LoggingContext.severity(int severity)
+
+ final String errorMessage = new StringBuilder()
+ .append(errorObject.getErrorText())
+ .append(":")
+ .append(errorObject.getRESTErrorCode())
+ .append(":")
+ .append(errorObject.getHTTPResponseCode())
+ .append(":")
+ .append(e.getMessage())
+ .toString();
+
+ LoggingContext.responseCode(errorObject.getErrorCodeString());
+ LoggingContext.responseDescription(errorMessage);
+ LoggingContext.statusCode(StatusCode.ERROR);
+
+ if (errorObject.getSeverity().equalsIgnoreCase("WARN"))
+ LOGGER.warn(errorMessage, e);
+ else if (errorObject.getSeverity().equalsIgnoreCase("ERROR"))
+ LOGGER.error(errorMessage, e);
+ else if (errorObject.getSeverity().equalsIgnoreCase("FATAL"))
+ LOGGER.error(errorMessage, e);
+ else if (errorObject.getSeverity().equals("INFO"))
+ LOGGER.info(errorMessage + ", " + e.getMessage());
+ }
+
+ public static void logError(String code) {
+ logError(code, "");
+ }
+
+ public static void logError(String code, String message) {
+ logException(new AAIException(code, message));
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObject.java b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObject.java
new file mode 100644
index 00000000..dc355cc7
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObject.java
@@ -0,0 +1,308 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+import javax.ws.rs.core.Response.Status;
+
+/**
+ *
+ * Contains the definition of all error message fields to be mapped from the Error
+ * properties file
+ *
+ */
+public class ErrorObject {
+
+ private String disposition;
+ private String category;
+ private String severity;
+ private Status httpResponseCode = Status.INTERNAL_SERVER_ERROR; // default
+ private String restErrorCode = "3002";
+ private String errorCode;
+ private String errorText;
+
+ /**
+ * Instantiates a new error object.
+ */
+ public ErrorObject() {
+ super();
+ }
+
+ /**
+ * Creates an error object with the default HTTP Error Code (Status.INTERNAL_SERVER_ERROR)
+ *
+ * @param disposition the disposition
+ * @param category the category
+ * @param severity the severity
+ * @param httpResponseCode the http response code
+ * @param restErrorCode the rest error code
+ * @param errorCode the error code
+ * @param errorText the error text
+ */
+ public ErrorObject(String disposition, String category, String severity, Integer httpResponseCode, String restErrorCode, String errorCode, String errorText) {
+ super();
+ this.setDisposition(disposition);
+ this.setCategory(category);
+ this.severity = severity;
+ this.setHTTPResponseCode(httpResponseCode);
+ this.setRESTErrorCode(restErrorCode);
+ this.setErrorCode(errorCode);
+ this.setErrorText(errorText);
+ }
+
+ // OLD STARTS HERE
+
+ /**
+ * Instantiates a new error object.
+ *
+ * @param severity the severity
+ * @param errorCode the error code
+ * @param errorText the error text
+ * @param disposition the disposition
+ * @param category the category
+ */
+ public ErrorObject(String severity, String errorCode, String errorText, String disposition, String category) {
+ this(severity, Status.INTERNAL_SERVER_ERROR, errorCode, errorText, disposition, category);
+ }
+
+ /**
+ * Instantiates a new error object.
+ *
+ * @param severity the severity
+ * @param httpResponseCode the http response code
+ * @param errorCode the error code
+ * @param errorText the error text
+ * @param disposition the disposition
+ * @param category the category
+ */
+ public ErrorObject(String severity, Integer httpResponseCode, String errorCode, String errorText, String disposition, String category) {
+ super();
+ this.severity = severity;
+ this.setHTTPResponseCode(httpResponseCode);
+ this.setErrorCode(errorCode);
+ this.setErrorText(errorText);
+ this.setDisposition(disposition);
+ this.setCategory(category);
+ }
+
+ /**
+ * Instantiates a new error object.
+ *
+ * @param severity the severity
+ * @param httpResponseCode the http response code
+ * @param errorCode the error code
+ * @param errorText the error text
+ * @param disposition the disposition
+ * @param category the category
+ */
+ public ErrorObject(String severity, Status httpResponseCode, String errorCode, String errorText, String disposition, String category) {
+ super();
+ this.severity = severity;
+ this.setHTTPResponseCode(httpResponseCode);
+ this.setErrorCode(errorCode);
+ this.setErrorText(errorText);
+ this.setDisposition(disposition);
+ this.setCategory(category);
+ }
+
+ /**
+ * Gets the disposition.
+ *
+ * @return the disposition
+ */
+ public String getDisposition() {
+ return disposition;
+ }
+
+ /**
+ * Sets the disposition.
+ *
+ * @param disposition the new disposition
+ */
+ public void setDisposition(String disposition) {
+ this.disposition = disposition;
+ }
+
+ /**
+ * Gets the category.
+ *
+ * @return the category
+ */
+ public String getCategory() {
+ return category;
+ }
+
+ /**
+ * Sets the category.
+ *
+ * @param category the new category
+ */
+ public void setCategory(String category) {
+ this.category = category;
+ }
+
+ /**
+ * Gets the severity.
+ *
+ * @return the severity
+ */
+ public String getSeverity() {
+ return severity;
+ }
+
+ /**
+ * Sets the severity.
+ *
+ * @param severity the new severity
+ */
+ public void setSeverity(String severity) {
+ this.severity = severity;
+ }
+
+ /**
+ * Gets the error code.
+ *
+ * @return the error code
+ */
+ public String getErrorCode() {
+ return errorCode;
+ }
+
+ /**
+ * Sets the error code.
+ *
+ * @param errorCode the new error code
+ */
+ public void setErrorCode(String errorCode) {
+ this.errorCode = errorCode;
+ }
+
+ /**
+ * Gets the HTTP response code.
+ *
+ * @return the HTTP response code
+ */
+ public Status getHTTPResponseCode() {
+ return httpResponseCode;
+ }
+
+ /**
+ * Sets the HTTP response code.
+ *
+ * @param httpResponseCode the new HTTP response code
+ */
+ public void setHTTPResponseCode(Integer httpResponseCode) {
+ this.httpResponseCode = Status.fromStatusCode(httpResponseCode);
+ if (this.httpResponseCode == null) {
+ throw new IllegalArgumentException("setHTTPResponseCode was passed an invalid Integer value, fix error.properties or your code "+httpResponseCode);
+ }
+ }
+
+ /**
+ * Sets the HTTP response code.
+ *
+ * @param httpResponseCode the new HTTP response code
+ */
+ public void setHTTPResponseCode(String httpResponseCode) {
+ this.httpResponseCode = Status.fromStatusCode(Integer.valueOf(httpResponseCode));
+ if (this.httpResponseCode == null) {
+ throw new IllegalArgumentException("setHTTPResponseCode was passed an invalid String value, fix error.properties or your code "+httpResponseCode);
+ }
+ }
+
+ /**
+ * Sets the REST error code.
+ *
+ * @param restErrorCode the new REST error code
+ */
+ public void setRESTErrorCode(String restErrorCode) {
+ this.restErrorCode = restErrorCode;
+ }
+
+ /**
+ * Gets the REST error code.
+ *
+ * @return the REST error code
+ */
+ public String getRESTErrorCode() {
+ return this.restErrorCode;
+ }
+
+ /**
+ * Sets the HTTP response code.
+ *
+ * @param httpResponseCode the new HTTP response code
+ */
+ public void setHTTPResponseCode(Status httpResponseCode) {
+ this.httpResponseCode = httpResponseCode;
+ if (this.httpResponseCode == null) {
+ throw new IllegalArgumentException("setHTTPResponseCode was passed an invalid String value, fix error.properties or your code "+httpResponseCode);
+ }
+ }
+
+ /**
+ * Gets the error text.
+ *
+ * @return the error text
+ */
+ public String getErrorText() {
+ return errorText;
+ }
+
+ /**
+ * Sets the error text.
+ *
+ * @param errorText the new error text
+ */
+ public void setErrorText(String errorText) {
+ this.errorText = errorText;
+ }
+
+ /**
+ * Gets the error code string. This is also the string
+ * configured in Nagios to alert on
+ *
+ * @return the error code string
+ */
+ // Get the X.Y.Z representation of the error code
+ public String getErrorCodeString() {
+ String prefix = null;
+ switch (disposition) {
+ default:
+ prefix = "";
+ break;
+ case "5":
+ prefix = "ERR.";
+ break;
+ }
+ return prefix + disposition + "." + category + "." + errorCode;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "ErrorObject [errorCode="+ errorCode + ", errorText=" + errorText
+ + ", restErrorCode=" + restErrorCode + ", httpResponseCode="+ httpResponseCode
+ + ", severity=" + severity + ", disposition=" + disposition + ", category=" + category +"]";
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObjectFormatException.java b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObjectFormatException.java
new file mode 100644
index 00000000..0bedfca2
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObjectFormatException.java
@@ -0,0 +1,30 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+public class ErrorObjectFormatException extends Exception {
+
+ private static final long serialVersionUID = 3732705544448553685L;
+
+ public ErrorObjectFormatException() {
+ super();
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObjectNotFoundException.java b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObjectNotFoundException.java
new file mode 100644
index 00000000..28290542
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/ErrorObjectNotFoundException.java
@@ -0,0 +1,51 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+public class ErrorObjectNotFoundException extends Exception {
+
+ private static final long serialVersionUID = 4115316781400786740L;
+
+ public ErrorObjectNotFoundException() {
+ // TODO Auto-generated constructor stub
+ }
+
+ public ErrorObjectNotFoundException(String message) {
+ super(message);
+ // TODO Auto-generated constructor stub
+ }
+
+ public ErrorObjectNotFoundException(Throwable cause) {
+ super(cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public ErrorObjectNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public ErrorObjectNotFoundException(String message, Throwable cause, boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ // TODO Auto-generated constructor stub
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/LogFormatTools.java b/aai-core/src/main/java/org/openecomp/aai/logging/LogFormatTools.java
new file mode 100644
index 00000000..78ade267
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/LogFormatTools.java
@@ -0,0 +1,45 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class LogFormatTools {
+
+ private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
+ private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern(DATE_FORMAT)
+ .withZone(ZoneOffset.UTC);
+
+ public static String getCurrentDateTime() {
+ return DTF.format(ZonedDateTime.now());
+ }
+
+ public static String toDate(long timestamp) {
+ return DTF.format(Instant.ofEpochMilli(timestamp));
+ }
+
+ public static long toTimestamp(String date) {
+ return ZonedDateTime.parse(date, DTF).toInstant().toEpochMilli();
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/LoggingContext.java b/aai-core/src/main/java/org/openecomp/aai/logging/LoggingContext.java
new file mode 100644
index 00000000..17d94e61
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/LoggingContext.java
@@ -0,0 +1,299 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.slf4j.MDC;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Iterator;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+public class LoggingContext {
+
+ public enum StatusCode {
+ COMPLETE,
+ ERROR
+ }
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(LoggingContext.class);
+
+ private static final String PREVIOUS_CONTEXT_KEY = "_PREVIOUS_CONTEXT";
+
+ //ECOMP Specific Log Event Fields
+ public static enum LoggingField {
+ START_TIME("startTime"),
+ REQUEST_ID("requestId"),
+ SERVICE_INSTANCE_ID("serviceInstanceId"),
+ SERVER_NAME("serverName"),
+ SERVICE_NAME("serviceName"),
+ PARTNER_NAME("partnerName"),
+ STATUS_CODE("statusCode"),
+ RESPONSE_CODE("responseCode"),
+ RESPONSE_DESCRIPTION("responseDescription"),
+ INSTANCE_UUID("instanceUUID"),
+ SEVERITY("severity"),
+ SERVER_IP_ADDRESS("serverIpAddress"),
+ ELAPSED_TIME("elapsedTime"),
+ SERVER("server"),
+ CLIENT_IP_ADDRESS("clientIpAddress"),
+ UNUSED("unused"),
+ PROCESS_KEY("processKey"),
+ CUSTOM_FIELD_1("customField1"),
+ CUSTOM_FIELD_2("customField2"),
+ CUSTOM_FIELD_3("customField3"),
+ CUSTOM_FIELD_4("customField4"),
+
+ //ECOMP Specific Metric Log Event Fields
+ TARGET_ENTITY("targetEntity"),
+
+ //A&AI Specific Log Event Fields
+ COMPONENT("component"),
+ STOP_WATCH_START("stopWatchStart");
+
+ private final String text;
+
+ private LoggingField(final String text) {
+ this.text = text;
+ }
+
+ public String toString() {
+ return text;
+ }
+ }
+
+
+ public static void init() {
+ LoggingContext.clear();
+ LoggingContext.startTime();
+ LoggingContext.server();
+ LoggingContext.serverIpAddress();
+ }
+
+ private static void startTime() {
+ MDC.put(LoggingField.START_TIME.toString(), LogFormatTools.getCurrentDateTime());
+ }
+
+ public static void requestId(UUID requestId) {
+ MDC.put(LoggingField.REQUEST_ID.toString(), requestId.toString());
+ }
+
+ public static void requestId(String requestId) {
+ try {
+ MDC.put(LoggingField.REQUEST_ID.toString(), UUID.fromString(requestId).toString());
+ } catch (IllegalArgumentException e) {
+ final UUID generatedRequestUuid = UUID.randomUUID();
+ MDC.put(LoggingField.REQUEST_ID.toString(), generatedRequestUuid.toString());
+ LOGGER.warn("Unable to use UUID " + requestId + " (Not formatted properly). Using generated UUID=" + generatedRequestUuid);
+ }
+ }
+
+ public static void serviceInstanceId(String serviceInstanceId) {
+ MDC.put(LoggingField.SERVICE_INSTANCE_ID.toString(), serviceInstanceId);
+ }
+
+ public static void serverName(String serverName) {
+ MDC.put(LoggingField.SERVER_NAME.toString(), serverName);
+ }
+
+ public static void serviceName(String serviceName) {
+ MDC.put(LoggingField.SERVICE_NAME.toString(), serviceName);
+ }
+
+ public static void partnerName(String partnerName) {
+ MDC.put(LoggingField.PARTNER_NAME.toString(), partnerName);
+ }
+
+ public static void statusCode(LoggingContext.StatusCode statusCode) {
+ MDC.put(LoggingField.STATUS_CODE.toString(), statusCode.toString());
+ }
+
+ public static String responseCode() {
+ return (String) MDC.get(LoggingField.RESPONSE_CODE.toString());
+ }
+
+ public static void responseCode(String responseCode) {
+ MDC.put(LoggingField.RESPONSE_CODE.toString(), responseCode);
+ }
+
+ public static void responseDescription(String responseDescription) {
+ MDC.put(LoggingField.RESPONSE_DESCRIPTION.toString(), responseDescription);
+ }
+
+ public static void instanceUuid(UUID instanceUuid) {
+ MDC.put(LoggingField.INSTANCE_UUID.toString(), instanceUuid.toString());
+ }
+
+ public static void severity(int severity) {
+ MDC.put(LoggingField.SEVERITY.toString(), String.valueOf(severity));
+ }
+
+ private static void serverIpAddress() {
+ try {
+ MDC.put(LoggingField.SERVER_IP_ADDRESS.toString(), InetAddress.getLocalHost().getHostAddress());
+ } catch (UnknownHostException e) {
+ LOGGER.warn("Unable to resolve server IP address - will not be displayed in logged events");
+ }
+ }
+
+ public static void elapsedTime(long elapsedTime, TimeUnit timeUnit) {
+ MDC.put(LoggingField.ELAPSED_TIME.toString(), String.valueOf(TimeUnit.MILLISECONDS.convert(elapsedTime, timeUnit)));
+ }
+
+ private static void server() {
+ try {
+ MDC.put(LoggingField.SERVER.toString(), InetAddress.getLocalHost().getCanonicalHostName());
+ } catch (UnknownHostException e) {
+ LOGGER.warn("Unable to resolve server IP address - hostname will not be displayed in logged events");
+ }
+ }
+
+ public static void clientIpAddress(InetAddress clientIpAddress) {
+ MDC.put(LoggingField.CLIENT_IP_ADDRESS.toString(), clientIpAddress.getHostAddress());
+ }
+
+ public static void clientIpAddress(String clientIpAddress) {
+ try {
+ MDC.put(LoggingField.CLIENT_IP_ADDRESS.toString(), InetAddress.getByName(clientIpAddress).getHostAddress());
+ } catch (UnknownHostException e) {
+ //Ignore, will not be thrown since InetAddress.getByName(String) only
+ //checks the validity of the passed in string
+ }
+ }
+
+ public static void unused(String unused) {
+ LOGGER.warn("Using field '" + LoggingField.UNUSED + "' (seems like this should go unused...)");
+ MDC.put(LoggingField.UNUSED.toString(), unused);
+ }
+
+ public static void processKey(String processKey) {
+ MDC.put(LoggingField.PROCESS_KEY.toString(), processKey);
+ }
+
+ public static void customField1(String customField1) {
+ MDC.put(LoggingField.CUSTOM_FIELD_1.toString(), customField1);
+ }
+
+ public static void customField2(String customField2) {
+ MDC.put(LoggingField.CUSTOM_FIELD_2.toString(), customField2);
+ }
+
+ public static void customField3(String customField3) {
+ MDC.put(LoggingField.CUSTOM_FIELD_3.toString(), customField3);
+ }
+
+ public static void customField4(String customField4) {
+ MDC.put(LoggingField.CUSTOM_FIELD_4.toString(), customField4);
+ }
+
+ public static void component(String component) {
+ MDC.put(LoggingField.COMPONENT.toString(), component);
+ }
+
+ public static void targetEntity(String targetEntity) {
+ MDC.put(LoggingField.TARGET_ENTITY.toString(), targetEntity);
+ }
+
+ public static void stopWatchStart() {
+ MDC.put(LoggingField.STOP_WATCH_START.toString(), String.valueOf(System.nanoTime()));
+ }
+
+ public static double stopWatchStop() {
+ final long stopWatchEnd = System.nanoTime();
+ final Long stopWatchStart = Long.valueOf(MDC.get(LoggingField.STOP_WATCH_START.toString()));
+
+ if (stopWatchStart == null) throw new StopWatchNotStartedException();
+
+ MDC.remove(LoggingField.STOP_WATCH_START.toString());
+
+ final double elapsedTimeMillis = (stopWatchEnd - stopWatchStart) / 1000.0 / 1000.0;
+
+ LoggingContext.elapsedTime((long) elapsedTimeMillis, TimeUnit.MILLISECONDS);
+
+ return elapsedTimeMillis;
+ }
+
+ public static void put(String key, String value) {
+ MDC.put(key, value);
+ }
+
+ public static void clear() {
+ MDC.clear();
+ }
+
+ public static void remove(String key) {
+ MDC.remove(key);
+ }
+
+ public static void save() {
+ final JSONObject context = new JSONObject();
+
+ for (LoggingField field : LoggingField.values()) {
+ if (field == LoggingField.ELAPSED_TIME) continue;
+
+ try {
+ context.put(field.toString(), MDC.get(field.toString()));
+ } catch (JSONException e) {
+ //Ignore - only occurs when the key is null (which can't happen)
+ // or the value is invalid (everything is converted to a string
+ // before it get put() to the MDC)
+ }
+ }
+
+ MDC.put("_PREVIOUS_CONTEXT", context.toString());
+ }
+
+ public static void restore() {
+
+ final String rawPreviousContext = MDC.get(PREVIOUS_CONTEXT_KEY);
+
+ if (rawPreviousContext == null) {
+ throw new LoggingContextNotExistsException();
+ }
+
+ try {
+ final JSONObject previousContext = new JSONObject(rawPreviousContext);
+
+ @SuppressWarnings("unchecked")
+ final Iterator<String> keys = previousContext.keys();
+
+ while (keys.hasNext()) {
+ final String key = keys.next();
+
+ try {
+ MDC.put(key, previousContext.getString(key));
+ } catch (JSONException e) {
+ //Ignore, only occurs when the key is null (cannot happen)
+ // or the value is invalid (they are all strings)
+ }
+ }
+
+ MDC.remove(PREVIOUS_CONTEXT_KEY);
+ } catch (JSONException e) {
+ //Ignore, the previousContext is serialized from a JSONObject
+ }
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/LoggingContextNotExistsException.java b/aai-core/src/main/java/org/openecomp/aai/logging/LoggingContextNotExistsException.java
new file mode 100644
index 00000000..caba1df3
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/LoggingContextNotExistsException.java
@@ -0,0 +1,26 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+public class LoggingContextNotExistsException extends RuntimeException {
+
+ private static final long serialVersionUID = -4965807709525739623L;
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/StopWatch.java b/aai-core/src/main/java/org/openecomp/aai/logging/StopWatch.java
new file mode 100644
index 00000000..0812698c
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/StopWatch.java
@@ -0,0 +1,41 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+import org.openecomp.aai.logging.LoggingContext.LoggingField;
+
+public final class StopWatch {
+
+ private StopWatch() {}
+
+ public static void start() {
+ LoggingContext.stopWatchStart();
+ }
+
+ public static double stop() {
+ return LoggingContext.stopWatchStop();
+ }
+
+ public static void clear() {
+ LoggingContext.remove(LoggingField.STOP_WATCH_START.toString());
+ LoggingContext.remove(LoggingField.ELAPSED_TIME.toString());
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/logging/StopWatchNotStartedException.java b/aai-core/src/main/java/org/openecomp/aai/logging/StopWatchNotStartedException.java
new file mode 100644
index 00000000..30a90e8e
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/logging/StopWatchNotStartedException.java
@@ -0,0 +1,42 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.logging;
+
+public class StopWatchNotStartedException extends RuntimeException {
+
+ private static final long serialVersionUID = -4540164295822859408L;
+
+ public StopWatchNotStartedException() {
+ super();
+ }
+
+ public StopWatchNotStartedException(String message) {
+ super(message);
+ }
+
+ public StopWatchNotStartedException(Throwable cause) {
+ super(cause);
+ }
+
+ public StopWatchNotStartedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/exceptions/AAIIdentityMapParseException.java b/aai-core/src/main/java/org/openecomp/aai/parsers/exceptions/AAIIdentityMapParseException.java
new file mode 100644
index 00000000..75ff6c42
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/exceptions/AAIIdentityMapParseException.java
@@ -0,0 +1,41 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.exceptions;
+
+import org.openecomp.aai.exceptions.AAIException;
+
+public class AAIIdentityMapParseException extends AAIException {
+
+ private static final long serialVersionUID = -888876613879411865L;
+
+ public AAIIdentityMapParseException(String message) {
+ super("AAI_3000", message);
+ }
+
+ public AAIIdentityMapParseException(Throwable cause) {
+ super("AAI_3000",cause);
+ }
+
+ public AAIIdentityMapParseException(String message, Throwable cause) {
+ super("AAI_3000", cause, message);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/exceptions/AmbiguousMapAAIException.java b/aai-core/src/main/java/org/openecomp/aai/parsers/exceptions/AmbiguousMapAAIException.java
new file mode 100644
index 00000000..2f2354c4
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/exceptions/AmbiguousMapAAIException.java
@@ -0,0 +1,41 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.exceptions;
+
+import org.openecomp.aai.exceptions.AAIException;
+
+public class AmbiguousMapAAIException extends AAIException {
+
+ private static final long serialVersionUID = -878581771971431246L;
+
+ public AmbiguousMapAAIException(String message) {
+ super("AAI_6146", message);
+ }
+
+ public AmbiguousMapAAIException(Throwable cause) {
+ super("AAI_6146",cause);
+ }
+
+ public AmbiguousMapAAIException(String message, Throwable cause) {
+ super("AAI_6146", cause, message);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/LegacyQueryParser.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/LegacyQueryParser.java
new file mode 100644
index 00000000..8da382f7
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/LegacyQueryParser.java
@@ -0,0 +1,233 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.query;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.parsers.uri.Parsable;
+import org.openecomp.aai.parsers.uri.URIParser;
+import org.openecomp.aai.parsers.uri.URIToObject;
+import org.openecomp.aai.query.builder.QueryBuilder;
+import org.openecomp.aai.restcore.util.URITools;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+import org.openecomp.aai.serialization.db.EdgeType;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+/**
+ * The Class LegacyQueryParser.
+ */
+public class LegacyQueryParser extends QueryParser implements Parsable {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(LegacyQueryParser.class);
+
+ private Introspector previous = null;
+
+ /**
+ * Instantiates a new legacy query parser.
+ *
+ * @param loader the loader
+ * @param queryBuilder the query builder
+ * @param uri the uri
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public LegacyQueryParser(Loader loader, QueryBuilder queryBuilder, URI uri) throws UnsupportedEncodingException, AAIException {
+ super(loader, queryBuilder, uri);
+ URIParser parser = new URIParser(loader, uri);
+ parser.parse(this);
+ }
+
+ /**
+ * Instantiates a new legacy query parser.
+ *
+ * @param loader the loader
+ * @param queryBuilder the query builder
+ * @param uri the uri
+ * @param queryParams the query params
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public LegacyQueryParser(Loader loader, QueryBuilder queryBuilder, URI uri, MultivaluedMap<String, String> queryParams) throws UnsupportedEncodingException, AAIException {
+ super(loader, queryBuilder, uri);
+ URIParser parser = new URIParser(loader, uri, queryParams);
+ parser.parse(this);
+ }
+
+ /**
+ * Instantiates a new legacy query parser.
+ *
+ * @param loader the loader
+ * @param queryBuilder the query builder
+ */
+ public LegacyQueryParser(Loader loader, QueryBuilder queryBuilder) {
+ super(loader, queryBuilder);
+ }
+
+ /**
+ * @throws AAIException
+ * @{inheritDoc}
+ */
+ @Override
+ public void processObject(Introspector obj, MultivaluedMap<String, String> uriKeys) throws AAIException {
+ if (previous != null) {
+ this.parentResourceType = previous.getDbName();
+ queryBuilder.createEdgeTraversal(EdgeType.TREE, previous, obj);
+ }
+ if (previous == null) {
+ queryBuilder.createDBQuery(obj);
+ this.handleUriKeys(obj, uriKeys);
+ } else {
+ queryBuilder.createKeyQuery(obj);
+ this.handleUriKeys(obj, uriKeys);
+ }
+ previous = obj;
+ this.resultResource = obj.getDbName();
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processContainer(Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) throws AAIException {
+ if (isFinalContainer) {
+ if (previous != null) {
+ this.parentResourceType = previous.getDbName();
+ queryBuilder.createEdgeTraversal(EdgeType.TREE, previous, obj);
+ }
+
+ if (previous == null) {
+ queryBuilder.createContainerQuery(obj);
+ queryBuilder.markParentBoundary();
+ }
+ if (!uriKeys.isEmpty()) {
+
+ try {
+ Introspector child = obj.newIntrospectorInstanceOfNestedProperty(obj.getChildName());
+ this.handleUriKeys(child, uriKeys);
+ } catch (AAIUnknownObjectException e) {
+ LOGGER.warn("Skipping container child " + obj.getChildName() + " (Unknown Object)", e);
+ }
+ }
+
+ this.resultResource = obj.getChildDBName();
+ this.containerResource = obj.getName();
+ }
+ }
+
+ private void handleUriKeys(Introspector obj, MultivaluedMap<String, String> uriKeys) throws AAIException {
+ for (String key : uriKeys.keySet()) {
+ //to validate whether this property exists
+ if (!obj.hasProperty(key)) {
+ throw new AAIException("AAI_3000", "property: " + key + " not found on " + obj.getDbName());
+ }
+
+ List<String> values = uriKeys.get(key);
+ String dbPropertyName = key;
+ Map<String, String> linkedProperties = new HashMap<>();
+ final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(key);
+ if (metadata.containsKey(PropertyMetadata.DATA_LINK)) {
+ linkedProperties.put(key, metadata.get(PropertyMetadata.DATA_LINK));
+ }
+ if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
+ dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS);
+ }
+
+ if (!linkedProperties.containsKey(key)) {
+ if (values.size() > 1) {
+ queryBuilder.getVerticesByIndexedProperty(dbPropertyName, obj.castValueAccordingToSchema(key, values));
+ } else {
+ queryBuilder.getVerticesByIndexedProperty(dbPropertyName, obj.castValueAccordingToSchema(key, values.get(0)));
+ }
+ }
+ handleLinkedProperties(obj, uriKeys, linkedProperties);
+ }
+ }
+ private void handleLinkedProperties(Introspector obj, MultivaluedMap<String, String> uriKeys, Map<String, String> linkedProperties) throws AAIException {
+
+ QueryBuilder[] builders = new QueryBuilder[linkedProperties.keySet().size()];
+ Set<Entry<String, String>> entrySet = linkedProperties.entrySet();
+ int i = 0;
+ Iterator<Entry<String, String>> itr = entrySet.iterator();
+
+ while (itr.hasNext()) {
+ Entry<String, String> entry = itr.next();
+ Introspector child;
+ try {
+ child = new URIToObject(this.latestLoader, new URI(URITools.replaceTemplates(obj, entry.getValue(), PropertyMetadata.DATA_LINK, true).orElse(""))).getEntity();
+ } catch (IllegalArgumentException | UnsupportedEncodingException | URISyntaxException e) {
+ throw new AAIException("AAI_4000", e);
+ }
+ List<String> values = uriKeys.get(entry.getKey());
+ QueryBuilder builder = queryBuilder.newInstance();
+ builder.createEdgeTraversal(EdgeType.TREE, obj, child);
+ if (values.size() > 1) {
+ builder.getVerticesByIndexedProperty(entry.getKey(), obj.castValueAccordingToSchema(entry.getKey(), values));
+ } else {
+ builder.getVerticesByIndexedProperty(entry.getKey(), obj.castValueAccordingToSchema(entry.getKey(), values.get(0)));
+ }
+
+ builders[i] = builder;
+ i++;
+ }
+
+ queryBuilder.where(builders);
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processNamespace(Introspector obj) {
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public String getCloudRegionTransform() {
+ return "add";
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public boolean useOriginalLoader() {
+ return false;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/ObjectNameQueryParser.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/ObjectNameQueryParser.java
new file mode 100644
index 00000000..6ea38893
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/ObjectNameQueryParser.java
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ *
+ */
+package org.openecomp.aai.parsers.query;
+
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.query.builder.QueryBuilder;
+
+public class ObjectNameQueryParser extends QueryParser {
+
+ public ObjectNameQueryParser(Loader loader, QueryBuilder queryBuilder, String objName) {
+ super(loader, queryBuilder);
+ this.resultResource = objName;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/QueryParser.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/QueryParser.java
new file mode 100644
index 00000000..4fd6c230
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/QueryParser.java
@@ -0,0 +1,145 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.query;
+
+import java.net.URI;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.LoaderFactory;
+import org.openecomp.aai.query.builder.QueryBuilder;
+
+/**
+ * The Class QueryParser.
+ */
+public abstract class QueryParser {
+
+ protected Loader loader = null;
+ protected Loader latestLoader = null;
+ protected QueryBuilder queryBuilder = null;
+
+ protected QueryBuilder parentQueryBuilder = null;
+
+ protected URI uri = null;
+
+ protected String resultResource = "";
+
+ protected String parentResourceType = "";
+
+ protected String containerResource = "";
+
+ /**
+ * Instantiates a new query parser.
+ *
+ * @param loader the loader
+ * @param queryBuilder the query builder
+ * @param uri the uri
+ */
+ protected QueryParser(Loader loader, QueryBuilder queryBuilder, URI uri) {
+ this.uri = uri;
+ this.queryBuilder = queryBuilder;
+ this.loader = loader;
+ this.latestLoader = LoaderFactory.createLoaderForVersion(loader.getModelType(), AAIProperties.LATEST);
+ }
+
+ /**
+ * Instantiates a new query parser.
+ *
+ * @param loader the loader
+ * @param queryBuilder the query builder
+ */
+ protected QueryParser(Loader loader, QueryBuilder queryBuilder) {
+ this.queryBuilder = queryBuilder;
+ this.loader = loader;
+ this.latestLoader = LoaderFactory.createLoaderForVersion(loader.getModelType(), AAIProperties.LATEST);
+ }
+
+ /**
+ * Gets the container type.
+ *
+ * @return the container type
+ */
+ public String getContainerType() {
+
+ return this.containerResource;
+ }
+
+ /**
+ * Gets the parent result type.
+ *
+ * @return the parent result type
+ */
+ public String getParentResultType() {
+ return this.parentResourceType;
+ }
+
+ /**
+ * Gets the result type.
+ *
+ * @return the result type
+ */
+ public String getResultType() {
+ return this.resultResource;
+ }
+
+ /**
+ * Gets the query builder.
+ *
+ * @return the query builder
+ */
+ public QueryBuilder getQueryBuilder() {
+ return this.queryBuilder;
+ }
+
+ /**
+ * Gets the uri.
+ *
+ * @return the uri
+ */
+ public URI getUri() {
+ return this.uri;
+ }
+
+ /**
+ * Gets the parent query builder.
+ *
+ * @return the parent query builder
+ */
+ public QueryBuilder getParentQueryBuilder() {
+ if (this.parentQueryBuilder != null) {
+ return this.parentQueryBuilder;
+ } else {
+ return this.queryBuilder;
+ }
+ }
+
+ /**
+ * Checks if is dependent.
+ *
+ * @return true, if is dependent
+ */
+ public boolean isDependent() {
+ return !this.queryBuilder.getQuery().toString().equals(this.queryBuilder.getParentQuery().getQuery().toString());
+ }
+
+}
+
+
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/QueryParserStrategy.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/QueryParserStrategy.java
new file mode 100644
index 00000000..ea875f22
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/QueryParserStrategy.java
@@ -0,0 +1,92 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.query;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.query.builder.QueryBuilder;
+
+/**
+ * The Class QueryParserStrategy.
+ */
+public abstract class QueryParserStrategy {
+
+ protected Loader loader = null;
+
+ protected QueryBuilder builder = null;
+
+ /**
+ * Instantiates a new query parser strategy.
+ *
+ * @param loader the loader
+ * @param builder the builder
+ */
+ public QueryParserStrategy(Loader loader, QueryBuilder builder) {
+
+ this.loader = loader;
+ this.builder = builder;
+ }
+
+ /**
+ * Builds the URI parser.
+ *
+ * @param uri the uri
+ * @return the query parser
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public abstract QueryParser buildURIParser(URI uri) throws UnsupportedEncodingException, AAIException;
+
+ /**
+ * Builds the URI parser.
+ *
+ * @param uri the uri
+ * @param queryParams the query params
+ * @return the query parser
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public abstract QueryParser buildURIParser(URI uri,MultivaluedMap<String, String> queryParams) throws UnsupportedEncodingException, AAIException;
+
+ /**
+ * Builds the relationship parser.
+ *
+ * @param obj the obj
+ * @return the query parser
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public abstract QueryParser buildRelationshipParser(Introspector obj) throws UnsupportedEncodingException, AAIException;
+
+ /**
+ * Builds an ObjectNameQueryParser.
+ *
+ * @param objName - the name of the object type as used in the database
+ * @return
+ */
+ public abstract QueryParser buildObjectNameParser(String objName);
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/RelationshipQueryParser.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/RelationshipQueryParser.java
new file mode 100644
index 00000000..7904f756
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/RelationshipQueryParser.java
@@ -0,0 +1,70 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.query;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.IntrospectorFactory;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.ModelType;
+import org.openecomp.aai.parsers.relationship.RelationshipToURI;
+import org.openecomp.aai.parsers.uri.URIParser;
+import org.openecomp.aai.query.builder.QueryBuilder;
+import org.openecomp.aai.serialization.db.EdgeRules;
+import com.google.common.base.CaseFormat;
+
+/**
+ * The Class RelationshipQueryParser.
+ */
+public class RelationshipQueryParser extends LegacyQueryParser {
+
+ private Introspector relationship = null;
+
+ private ModelType modelType = null;
+
+ private EdgeRules edgeRules = null;
+
+ /**
+ * Instantiates a new relationship query parser.
+ *
+ * @param loader the loader
+ * @param queryBuilder the query builder
+ * @param obj the obj
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public RelationshipQueryParser(Loader loader, QueryBuilder queryBuilder, Introspector obj) throws UnsupportedEncodingException, AAIException {
+ super(loader, queryBuilder);
+ this.relationship = obj;
+ this.modelType = obj.getModelType();
+ this.edgeRules = EdgeRules.getInstance();
+ RelationshipToURI rToUri = new RelationshipToURI(loader, obj);
+ this.uri = rToUri.getUri();
+ URIParser parser = new URIParser(loader, uri);
+ parser.parse(this);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/TraversalStrategy.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/TraversalStrategy.java
new file mode 100644
index 00000000..664a3274
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/TraversalStrategy.java
@@ -0,0 +1,83 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.query;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.query.builder.QueryBuilder;
+
+/**
+ * The Class TraversalStrategy.
+ */
+public class TraversalStrategy extends QueryParserStrategy {
+
+
+ /**
+ * Instantiates a new traversal strategy.
+ *
+ * @param loader the loader
+ * @param builder the builder
+ */
+ public TraversalStrategy(Loader loader, QueryBuilder builder) {
+ super(loader, builder);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser buildURIParser(URI uri) throws UnsupportedEncodingException, AAIException {
+ return new LegacyQueryParser(loader, builder, uri);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser buildRelationshipParser(Introspector obj) throws UnsupportedEncodingException, AAIException {
+ return new RelationshipQueryParser(loader, builder, obj);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser buildURIParser(URI uri, MultivaluedMap<String, String> queryParams)
+ throws UnsupportedEncodingException, AAIException {
+ return new LegacyQueryParser(loader, builder, uri, queryParams);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser buildObjectNameParser(String objName) {
+ return new ObjectNameQueryParser(loader, builder, objName);
+ }
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueRelationshipQueryParser.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueRelationshipQueryParser.java
new file mode 100644
index 00000000..e1502c31
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueRelationshipQueryParser.java
@@ -0,0 +1,57 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.query;
+
+import java.io.UnsupportedEncodingException;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.parsers.relationship.RelationshipToURI;
+import org.openecomp.aai.query.builder.QueryBuilder;
+
+/**
+ * The Class UniqueRelationshipQueryParser.
+ */
+public class UniqueRelationshipQueryParser extends UniqueURIQueryParser {
+
+
+ /**
+ * Instantiates a new unique relationship query parser.
+ *
+ * @param loader the loader
+ * @param queryBuilder the query builder
+ * @param obj the obj
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws AAIException the AAI exception
+ */
+ public UniqueRelationshipQueryParser(Loader loader, QueryBuilder queryBuilder, Introspector obj) throws UnsupportedEncodingException, IllegalArgumentException, AAIException {
+ super(loader, queryBuilder);
+ RelationshipToURI rToUri = new RelationshipToURI(loader, obj);
+ UniqueURIQueryParser parser = new UniqueURIQueryParser(loader, queryBuilder, rToUri.getUri());
+ this.containerResource = parser.getContainerType();
+ this.resultResource = parser.getResultType();
+ this.queryBuilder = parser.getQueryBuilder();
+ this.parentQueryBuilder = parser.getParentQueryBuilder();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueStrategy.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueStrategy.java
new file mode 100644
index 00000000..6d594778
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueStrategy.java
@@ -0,0 +1,82 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.query;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.query.builder.QueryBuilder;
+
+/**
+ * The Class UniqueStrategy.
+ */
+public class UniqueStrategy extends QueryParserStrategy {
+
+
+
+ /**
+ * Instantiates a new unique strategy.
+ *
+ * @param loader the loader
+ * @param builder the builder
+ */
+ public UniqueStrategy(Loader loader, QueryBuilder builder) {
+ super(loader, builder);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser buildURIParser(URI uri) throws UnsupportedEncodingException, IllegalArgumentException, AAIException {
+ return new UniqueURIQueryParser(loader, builder, uri);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser buildRelationshipParser(Introspector obj) throws UnsupportedEncodingException, AAIException {
+ return new UniqueRelationshipQueryParser(loader, builder, obj);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser buildURIParser(URI uri, MultivaluedMap<String, String> queryParams)
+ throws UnsupportedEncodingException, AAIException {
+ return new LegacyQueryParser(loader, builder, uri, queryParams);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser buildObjectNameParser(String objName) {
+ return new ObjectNameQueryParser(loader, builder, objName);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueURIQueryParser.java b/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueURIQueryParser.java
new file mode 100644
index 00000000..c62d0469
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/query/UniqueURIQueryParser.java
@@ -0,0 +1,171 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.query;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriBuilder;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.parsers.uri.Parsable;
+import org.openecomp.aai.parsers.uri.URIParser;
+import org.openecomp.aai.parsers.uri.URIToDBKey;
+import org.openecomp.aai.query.builder.QueryBuilder;
+import org.openecomp.aai.serialization.db.EdgeType;
+
+
+/**
+ * The Class UniqueURIQueryParser.
+ */
+public class UniqueURIQueryParser extends QueryParser implements Parsable {
+
+
+ private URIToDBKey dbKeyParser = null;
+
+ private Introspector previous = null;
+
+ private boolean endsInContainer = false;
+
+ private Introspector finalContainer = null;
+
+ private String parentName = "";
+
+ /**
+ * Instantiates a new unique URI query parser.
+ *
+ * @param loader the loader
+ * @param queryBuilder the query builder
+ * @param uri the uri
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws AAIException the AAI exception
+ */
+ public UniqueURIQueryParser(Loader loader, QueryBuilder queryBuilder, URI uri) throws UnsupportedEncodingException, IllegalArgumentException, AAIException {
+ super(loader, queryBuilder, uri);
+ URIParser parser = new URIParser(loader, uri);
+ parser.parse(this);
+
+ if (!endsInContainer) {
+ this.dbKeyParser = new URIToDBKey(loader, uri);
+ String dbKey = (String)dbKeyParser.getResult();
+ queryBuilder.getVerticesByIndexedProperty("aai-unique-key", dbKey);
+ queryBuilder.markParentBoundary();
+
+ if (!(parentName.equals("") || parentName.equals(this.resultResource))) {
+ URI parentUri = UriBuilder.fromPath(uri.getRawPath().substring(0, uri.getRawPath().indexOf(containerResource))).build();
+ this.dbKeyParser = new URIToDBKey(loader, parentUri);
+ this.parentQueryBuilder = queryBuilder.newInstance().getVerticesByIndexedProperty("aai-unique-key", (String)dbKeyParser.getResult());
+ this.parentResourceType = parentName;
+ }
+ this.containerResource = "";
+ } else {
+ URI parentUri = UriBuilder.fromPath(uri.getRawPath().substring(0, uri.getRawPath().indexOf(this.finalContainer.getDbName()))).build();
+ this.dbKeyParser = new URIToDBKey(loader, parentUri);
+ String dbKey = (String)dbKeyParser.getResult();
+ this.parentResourceType = parentName;
+
+ if (!dbKey.equals("")) {
+ queryBuilder.getVerticesByIndexedProperty("aai-unique-key", dbKey);
+ queryBuilder.markParentBoundary();
+ queryBuilder.createEdgeTraversal(EdgeType.TREE, previous, finalContainer);
+
+ }
+
+ queryBuilder.createContainerQuery(finalContainer);
+
+
+ }
+ }
+
+
+ /**
+ * Instantiates a new unique URI query parser.
+ *
+ * @param loader the loader
+ * @param queryBuilder the query builder
+ */
+ public UniqueURIQueryParser(Loader loader, QueryBuilder queryBuilder) {
+ super(loader, queryBuilder);
+ }
+
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processObject(Introspector obj, MultivaluedMap<String, String> uriKeys) {
+ this.resultResource = obj.getDbName();
+ if (previous != null) {
+ this.parentName = previous.getDbName();
+ }
+ this.previous = obj;
+
+
+ }
+
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processContainer(Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) {
+ this.containerResource = obj.getName();
+ if (previous != null) {
+ this.parentName = previous.getDbName();
+ }
+ if (isFinalContainer) {
+ this.endsInContainer = true;
+ this.resultResource = obj.getChildDBName();
+
+ this.finalContainer = obj;
+ }
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processNamespace(Introspector obj) {
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public String getCloudRegionTransform() {
+ return "add";
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public boolean useOriginalLoader() {
+ return false;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/relationship/RelationshipToURI.java b/aai-core/src/main/java/org/openecomp/aai/parsers/relationship/RelationshipToURI.java
new file mode 100644
index 00000000..e6d09fbe
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/relationship/RelationshipToURI.java
@@ -0,0 +1,284 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.relationship;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Optional;
+
+import javax.ws.rs.core.UriBuilder;
+
+import org.apache.tinkerpop.gremlin.structure.Direction;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.IntrospectorFactory;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.ModelType;
+import org.openecomp.aai.introspection.Version;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.parsers.exceptions.AAIIdentityMapParseException;
+import org.openecomp.aai.parsers.exceptions.AmbiguousMapAAIException;
+import org.openecomp.aai.parsers.uri.URIParser;
+import org.openecomp.aai.schema.enums.ObjectMetadata;
+import org.openecomp.aai.serialization.db.EdgeRule;
+import org.openecomp.aai.serialization.db.EdgeRules;
+import org.openecomp.aai.serialization.db.EdgeType;
+import org.openecomp.aai.workarounds.LegacyURITransformer;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+/**
+ * The Class RelationshipToURI.
+ */
+public class RelationshipToURI {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(RelationshipToURI.class);
+
+ private Introspector relationship = null;
+
+ private Loader loader = null;
+
+ private ModelType modelType = null;
+
+ private EdgeRules edgeRules = null;
+
+ private URI uri = null;
+
+ private LegacyURITransformer urlTransform = null;
+
+ /**
+ * Instantiates a new relationship to URI.
+ *
+ * @param loader the loader
+ * @param relationship the relationship
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public RelationshipToURI(Loader loader, Introspector relationship) throws UnsupportedEncodingException, AAIException {
+ this.relationship = relationship;
+ this.modelType = relationship.getModelType();
+ this.edgeRules = EdgeRules.getInstance();
+ this.loader = loader;
+ this.urlTransform = LegacyURITransformer.getInstance();
+
+ this.parse();
+
+ }
+
+ /**
+ * Parses the.
+ * @throws
+ *
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ protected void parse() throws AAIException {
+ String relatedLink = (String)relationship.getValue("related-link");
+ Optional<URI> result;
+ try {
+ if (loader.getVersion().compareTo(Version.v10) >= 0) {
+ result = processRelatedLink(relatedLink);
+ if (!result.isPresent()) {
+ result = processRelationshipData();
+ }
+ } else {
+ result = processRelationshipData();
+ if (!result.isPresent()) {
+ result = processRelatedLink(relatedLink);
+ }
+ }
+ if (result.isPresent()) {
+ this.uri = result.get();
+ } else {
+ throw new AAIIdentityMapParseException("nothing to parse");
+ }
+ } catch (UnsupportedEncodingException | URISyntaxException e) {
+ throw new AAIIdentityMapParseException("Could not parse relationship-list object: " + e.getMessage(), e);
+ }
+
+ }
+
+ private Optional<URI> processRelationshipData() throws AAIException, UnsupportedEncodingException {
+ Optional<URI> result = Optional.empty();
+ StringBuilder uriBuilder = new StringBuilder();
+ List<Object> data = (List<Object>)relationship.getValue("relationship-data");
+ Introspector wrapper;
+ String key;
+ String value;
+ String objectType;
+ String propertyName;
+ String topLevelType = null;
+ String[] split;
+ HashMap<String, Introspector> map = new HashMap<>();
+ for (Object datum : data) {
+ wrapper = IntrospectorFactory.newInstance(modelType, datum);
+ key = (String)wrapper.getValue("relationship-key");
+ value = (String)wrapper.getValue("relationship-value");
+ split = key.split("\\.");
+ if (split == null || split.length != 2) {
+ throw new AAIIdentityMapParseException("incorrect format for key must be of the form {node-type}.{property-name}");
+ }
+ //check node name ok
+ //check prop name ok
+ objectType = split[0];
+ propertyName = split[1];
+
+ try {
+ Introspector wrappedObj = loader.introspectorFromName(objectType);
+
+ if (!wrappedObj.hasProperty(propertyName)) {
+ throw new AAIIdentityMapParseException("invalid property name in map: " + propertyName);
+ }
+ if (map.containsKey(objectType)) {
+ wrappedObj = map.get(objectType);
+ } else {
+ map.put(objectType, wrappedObj);
+ }
+ if (wrappedObj.getValue(propertyName) == null) {
+ wrappedObj.setValue(propertyName, value);
+ } else {
+ throw new AmbiguousMapAAIException("cannot determine where key/value goes: " + propertyName + "/" + value);
+ }
+
+ if (wrappedObj.getMetadata(ObjectMetadata.NAMESPACE) != null) {
+ if (topLevelType == null) {
+ topLevelType = objectType;
+ } else if (!topLevelType.equals(objectType)){
+ throw new AmbiguousMapAAIException("found two top level nodes of different types: " + topLevelType + " and " + objectType);
+ }
+ }
+ } catch (AAIUnknownObjectException e) {
+ throw new AAIIdentityMapParseException("invalid object name in map: " + objectType, e);
+ }
+
+ }
+ if (!map.isEmpty()) {
+ String startType = (String)relationship.getValue("related-to");
+ List<String> nodeTypes = new ArrayList<>();
+ nodeTypes.addAll(map.keySet());
+
+ String displacedType;
+ for (int i = 0; i < nodeTypes.size(); i++) {
+ if (nodeTypes.get(i).equals(startType)) {
+ displacedType = nodeTypes.set(nodeTypes.size() - 1, startType);
+ nodeTypes.set(i, displacedType);
+ break;
+ }
+ }
+ sortRelationships(nodeTypes, startType, 1);
+ int startTypeIndex = nodeTypes.indexOf(startType);
+ int topLevelIndex = 0;
+ if (topLevelType != null) {
+ topLevelIndex = nodeTypes.indexOf(topLevelType);
+ }
+ //remove additional types not needed if they are there
+ List<String> nodeTypesSubList = nodeTypes;
+ if (topLevelIndex != 0) {
+ nodeTypesSubList = nodeTypes.subList(topLevelIndex, startTypeIndex+1);
+ }
+ for (String type : nodeTypesSubList) {
+ uriBuilder.append(map.get(type).getURI());
+ }
+ if (!nodeTypesSubList.isEmpty()) {
+ result = Optional.of(UriBuilder.fromPath(uriBuilder.toString()).build());
+ }
+ }
+ return result;
+ }
+
+ private Optional<URI> processRelatedLink(String relatedLink) throws URISyntaxException, UnsupportedEncodingException, AAIIdentityMapParseException {
+ Optional<URI> result = Optional.empty();
+ if (relatedLink != null) {
+ URI resultUri = new URI(relatedLink);
+ String path = resultUri.toString();
+ resultUri = UriBuilder.fromPath(resultUri.getRawPath()).build();
+ URIParser uriParser = new URIParser(this.loader, resultUri);
+ try {
+ uriParser.validate();
+ } catch (AAIException e) {
+ throw new AAIIdentityMapParseException("related link is invalid: " + relatedLink, e);
+ }
+ result = Optional.of(resultUri);
+ }
+
+ return result;
+ }
+
+ /**
+ * Sort relationships.
+ *
+ * @param data the data
+ * @param startType the start type
+ * @param i the i
+ * @return true, if successful
+ * @throws AAIException
+ */
+ private boolean sortRelationships(List<String> data, String startType, int i) throws AAIException {
+
+ if (i == data.size()) {
+ return true;
+ }
+ int j;
+ String objectType;
+ String displacedObject;
+ EdgeRule rule;
+ Direction direction;
+ for (j = (data.size() - i) - 1; j >= 0; j--) {
+ objectType = data.get(j);
+ try {
+ rule = edgeRules.getEdgeRule(EdgeType.TREE, startType, objectType);
+ direction = rule.getDirection();
+ if (direction != null) {
+ if ((rule.getIsParent().equals("true") && direction.equals(Direction.IN)) || (rule.getIsParent().equals("reverse") && direction.equals(Direction.OUT))) {
+ displacedObject = data.set((data.size() - i) - 1, data.get(j));
+ data.set(j, displacedObject);
+ if (sortRelationships(data, objectType, i+1)) {
+ return true;
+ } else {
+ //continue to process
+ }
+ }
+ }
+ } catch (AAIException e) {
+ //ignore exceptions generated
+ continue;
+ }
+ }
+
+
+ return false;
+ }
+
+ /**
+ * Gets the uri.
+ *
+ * @return the uri
+ */
+ public URI getUri() {
+ return uri;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/uri/Parsable.java b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/Parsable.java
new file mode 100644
index 00000000..0d24b7c1
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/Parsable.java
@@ -0,0 +1,72 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.uri;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+
+/**
+ * The Interface Parsable.
+ */
+public interface Parsable {
+
+ /**
+ * Process object.
+ *
+ * @param obj the obj
+ * @param uriKeys the uri keys
+ * @throws AAIException
+ */
+ public void processObject(Introspector obj, MultivaluedMap<String, String> uriKeys) throws AAIException;
+
+ /**
+ * Process container.
+ *
+ * @param obj the obj
+ * @param uriKeys the uri keys
+ * @param isFinalContainer the is final container
+ * @throws AAIException the AAI exception
+ */
+ public void processContainer(Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) throws AAIException;
+
+ /**
+ * Process namespace.
+ *
+ * @param obj the obj
+ */
+ public void processNamespace(Introspector obj);
+
+ /**
+ * Gets the cloud region transform.
+ *
+ * @return the cloud region transform
+ */
+ public String getCloudRegionTransform();
+
+ /**
+ * Use original loader.
+ *
+ * @return true, if successful
+ */
+ public boolean useOriginalLoader();
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIParser.java b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIParser.java
new file mode 100644
index 00000000..87439774
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIParser.java
@@ -0,0 +1,249 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.uri;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.Set;
+
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriBuilder;
+
+import org.springframework.web.util.UriUtils;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.LoaderFactory;
+import org.openecomp.aai.introspection.Version;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.schema.enums.ObjectMetadata;
+import org.openecomp.aai.util.AAIConfig;
+
+
+/**
+ * The Class URIParser.
+ */
+public class URIParser {
+
+ private URI uri = null;
+
+ protected Loader loader = null;
+
+ protected Loader originalLoader = null;
+
+ private URI originalURI = null;
+
+ private MultivaluedMap<String, String> queryParams = null;
+
+
+ /**
+ * Instantiates a new URI parser.
+ *
+ * @param loader the loader
+ * @param uri the uri
+ */
+ public URIParser(Loader loader, URI uri) {
+ this.uri = uri;
+
+ String currentVersion = "v7";
+ this.originalLoader = loader;
+ try {
+ currentVersion = AAIConfig.get("aai.default.api.version");
+ } catch (AAIException e) {
+ ErrorLogHelper.logException(e);
+ }
+
+ //Load the latest version because we need it for cloud region
+
+ this.loader = loader;
+ }
+
+ /**
+ * Instantiates a new URI parser.
+ *
+ * @param loader the loader
+ * @param uri the uri
+ * @param queryParams the query params
+ */
+ public URIParser(Loader loader, URI uri, MultivaluedMap<String, String> queryParams) {
+ this(loader, uri);
+ this.queryParams = queryParams;
+ }
+
+ public Loader getLoader() {
+
+ return this.loader;
+
+ }
+
+ /**
+ * Gets the original URI.
+ *
+ * @return the original URI
+ */
+ public URI getOriginalURI() {
+ return this.originalURI;
+ }
+
+ /**
+ * Parses the.
+ *
+ * @param p the p
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public void parse(Parsable p) throws UnsupportedEncodingException, AAIException {
+ try {
+ boolean isRelative = false;
+ uri = this.trimURI(uri);
+ uri = handleCloudRegion(p.getCloudRegionTransform(), uri);
+ if (p.useOriginalLoader()) {
+ this.loader = this.originalLoader;
+ }
+ this.originalURI = UriBuilder.fromPath(uri.getRawPath()).build();
+ if (uri.getRawPath().startsWith("./")) {
+ uri = new URI(uri.getRawPath().replaceFirst("\\./", ""));
+ isRelative = true;
+ }
+ String[] parts = uri.getRawPath().split("/");
+ Introspector validNamespaces = loader.introspectorFromName("inventory");
+ Set<String> keys = null;
+ String part = "";
+ Introspector previousObj = null;
+
+ for (int i = 0; i < parts.length;) {
+ part = parts[i];
+ Introspector introspector = null;
+ introspector = loader.introspectorFromName(part);
+ if (introspector != null) {
+
+ //previous has current as property
+ if (previousObj != null && !previousObj.hasChild(introspector) && !previousObj.getDbName().equals("nodes")) {
+ throw new AAIException("AAI_3001", uri + " not a valid path. " + part + " not valid");
+ } else if (previousObj == null) {
+ String abstractType = introspector.getMetadata(ObjectMetadata.ABSTRACT);
+ if (abstractType == null) {
+ abstractType = "";
+ }
+ //first time through, make sure it starts from a namespace
+ //ignore abstract types
+ if (!isRelative && !abstractType.equals("true") && !validNamespaces.hasChild(introspector)) {
+ throw new AAIException("AAI_3000", uri + " not a valid path. It does not start from a valid namespace");
+ }
+ }
+
+ keys = introspector.getKeys();
+ if (keys.size() > 0) {
+ MultivaluedMap<String, String> uriKeys = new MultivaluedHashMap<>();
+ i++;
+ if (i == parts.length && queryParams != null) {
+ Set<String> queryKeys = queryParams.keySet();
+ for (String key : queryKeys) {
+ uriKeys.put(key, queryParams.get(key));
+ }
+ } else {
+ for (String key : keys) {
+ part = UriUtils.decode(parts[i], "UTF-8");
+
+ introspector.setValue(key, part);
+
+ //skip this for further processing
+ i++;
+ }
+ }
+
+ p.processObject(introspector, uriKeys);
+
+ } else if (introspector.isContainer()) {
+ boolean isFinalContainer = i == parts.length-1;
+ MultivaluedMap<String, String> uriKeys = new MultivaluedHashMap<>();
+
+ if (isFinalContainer && queryParams != null) {
+ Set<String> queryKeys = queryParams.keySet();
+ for (String key : queryKeys) {
+ uriKeys.put(key, queryParams.get(key));
+
+ }
+ }
+ p.processContainer(introspector, uriKeys, isFinalContainer);
+
+ i++;
+ } else {
+ p.processNamespace(introspector);
+ //namespace case
+ i++;
+ }
+ previousObj = introspector;
+ } else {
+ //invalid item found should log
+ //original said bad path
+ throw new AAIException("AAI_3001", "invalid item found in path: " + part);
+ }
+ }
+ } catch (AAIException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new AAIException("AAI_3001", e);
+ }
+ }
+
+ public boolean validate() throws UnsupportedEncodingException, AAIException {
+ this.parse(new URIValidate());
+ return true;
+ }
+ /**
+ * Handle cloud region.
+ *
+ * @param action the action
+ * @param uri the uri
+ * @return the uri
+ */
+ protected URI handleCloudRegion(String action, URI uri) {
+
+ return uri;
+
+ }
+
+ /**
+ * Trim URI.
+ *
+ * @param uri the uri
+ * @return the uri
+ */
+ protected URI trimURI(URI uri) {
+
+ String result = uri.getRawPath();
+ if (result.startsWith("/")) {
+ result = result.substring(1, result.length());
+ }
+
+ if (result.endsWith("/")) {
+ result = result.substring(0, result.length() - 1);
+ }
+
+ result = result.replaceFirst("aai/v\\d+/", "");
+
+ return UriBuilder.fromPath(result).build();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToDBKey.java b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToDBKey.java
new file mode 100644
index 00000000..e286a532
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToDBKey.java
@@ -0,0 +1,127 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.uri;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import com.google.common.base.Joiner;
+
+/**
+ * Creates a Unique database key from a URI
+ *
+ * The key is of the form node-type/key(s).
+ */
+public class URIToDBKey implements Parsable {
+
+
+ private List<String> dbKeys = new ArrayList<>();
+
+ /**
+ * Instantiates a new URI to DB key.
+ *
+ * @param loader the loader
+ * @param uri the uri
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public URIToDBKey(Loader loader, URI uri) throws IllegalArgumentException, AAIException, UnsupportedEncodingException {
+
+ URIParser parser = new URIParser(loader, uri);
+ parser.parse(this);
+ }
+ /*
+ public URIToDBKey(Version version, String uri) throws IllegalArgumentException {
+
+ super(version, uri);
+ try {
+ context = ModelInjestor.getInstance().getContextForVersion(version);
+ if (context == null) {
+ throw new IllegalArgumentException("could not find a context for version: " + version);
+ }
+ this.parse();
+ } catch (Exception e) {
+ throw new IllegalArgumentException("uri not valid against our model: " + uri);
+ }
+ }*/
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processObject (Introspector obj, MultivaluedMap<String, String> uriKeys) {
+
+ dbKeys.add(obj.getDbName());
+
+ for (String key : uriKeys.keySet()) {
+ dbKeys.add(uriKeys.getFirst(key).toString());
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processContainer (Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) {
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processNamespace(Introspector obj) {
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public String getCloudRegionTransform() {
+ return "add";
+ }
+
+ /**
+ * Gets the result.
+ *
+ * @return the result
+ */
+ public Object getResult() {
+ return Joiner.on("/").join(this.dbKeys);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public boolean useOriginalLoader() {
+ return false;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToExtensionInformation.java b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToExtensionInformation.java
new file mode 100644
index 00000000..26cf4a54
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToExtensionInformation.java
@@ -0,0 +1,169 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.uri;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.restcore.HttpMethod;
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Joiner;
+
+/**
+ * The Class URIToExtensionInformation.
+ */
+public class URIToExtensionInformation implements Parsable {
+
+ private String namespace = "";
+
+ private String methodName = "";
+
+ private String topObject = "";
+
+ private List<String> pieces = null;
+
+ /**
+ * Instantiates a new URI to extension information.
+ *
+ * @param loader the loader
+ * @param uri the uri
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public URIToExtensionInformation(Loader loader, URI uri) throws IllegalArgumentException, AAIException, UnsupportedEncodingException {
+ pieces = new ArrayList<>();
+ URIParser parser = new URIParser(loader, uri);
+ parser.parse(this);
+
+ this.methodName = Joiner.on("").join(this.pieces);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processObject(Introspector obj, MultivaluedMap<String, String> uriKeys) {
+ String upperCamel = toUpperCamel(obj.getDbName());
+ if (topObject.equals("")) {
+ topObject = upperCamel;
+ }
+ pieces.add(upperCamel);
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processContainer(Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) {
+ pieces.add(toUpperCamel(obj.getName()));
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processNamespace(Introspector obj) {
+ this.namespace = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, obj.getDbName());
+ pieces.add(toUpperCamel(obj.getDbName()));
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public String getCloudRegionTransform() {
+ return "remove";
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public boolean useOriginalLoader() {
+ return true;
+ }
+
+ /**
+ * Gets the namespace.
+ *
+ * @return the namespace
+ */
+ public String getNamespace() {
+ return this.namespace;
+ }
+
+ /**
+ * Gets the top object.
+ *
+ * @return the top object
+ */
+ public String getTopObject() {
+ return this.topObject;
+ }
+
+ /**
+ * Gets the method name.
+ *
+ * @param httpMethod the http method
+ * @param isPreprocess the is preprocess
+ * @return the method name
+ */
+ public String getMethodName(HttpMethod httpMethod, boolean isPreprocess) {
+ String result = "Dynamic";
+ if (httpMethod.equals(HttpMethod.PUT)) {
+ result += "Add";
+ } else if (httpMethod.equals(HttpMethod.DELETE)) {
+ result += "Del";
+ } else {
+ throw new IllegalArgumentException("http method not supported: " + httpMethod);
+ }
+ result += this.methodName;
+
+ if (isPreprocess) {
+ result += "PreProc";
+ } else {
+ result += "PostProc";
+ }
+ return result;
+ }
+
+ /**
+ * To upper camel.
+ *
+ * @param name the name
+ * @return the string
+ */
+ private String toUpperCamel(String name) {
+ String result = "";
+ result = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, name);
+ return result;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToObject.java b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToObject.java
new file mode 100644
index 00000000..3242adb0
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToObject.java
@@ -0,0 +1,229 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.uri;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.Version;
+import org.openecomp.aai.schema.enums.ObjectMetadata;
+
+/**
+ * Given a URI this class returns an object, or series of nested objects
+ * with their keys populated based off the values in the URI.
+ *
+ * It populates the keys in the order they are listed in the model.
+ *
+
+ *
+ */
+public class URIToObject implements Parsable {
+
+
+ private Introspector topEntity = null;
+
+ private String topEntityName = null;
+
+ private String entityName = null;
+
+ private Introspector entity = null;
+
+ private Introspector previous = null;
+
+ private List<Object> parentList = null;
+
+ private Version version = null;
+ private Loader loader = null;
+ private final HashMap<String, Introspector> relatedObjects;
+
+ /**
+ * Instantiates a new URI to object.
+ *
+ * @param loader the loader
+ * @param uri the uri
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public URIToObject(Loader loader, URI uri) throws IllegalArgumentException, AAIException, UnsupportedEncodingException {
+
+ URIParser parser = new URIParser(loader, uri);
+ this.relatedObjects = new HashMap<>();
+
+ parser.parse(this);
+ this.loader = parser.getLoader();
+ this.version = loader.getVersion();
+ }
+ public URIToObject(Loader loader, URI uri, HashMap<String, Introspector> relatedObjects) throws IllegalArgumentException, AAIException, UnsupportedEncodingException {
+
+ URIParser parser = new URIParser(loader, uri);
+ this.relatedObjects = relatedObjects;
+
+ parser.parse(this);
+ this.loader = parser.getLoader();
+ this.version = loader.getVersion();
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processObject(Introspector obj, MultivaluedMap<String, String> uriKeys) {
+
+ if (this.entityName == null) {
+ this.topEntityName = obj.getDbName();
+ this.topEntity = obj;
+ }
+ this.entityName = obj.getDbName();
+ this.entity = obj;
+ this.parentList = (List<Object>)this.previous.getValue(obj.getName());
+ this.parentList.add(entity.getUnderlyingObject());
+
+ for (String key : uriKeys.keySet()) {
+ entity.setValue(key, uriKeys.getFirst(key));
+ }
+ try {
+ if (relatedObjects.containsKey(entity.getObjectId())) {
+ Introspector relatedObject = relatedObjects.get(entity.getObjectId());
+ String nameProp = relatedObject.getMetadata(ObjectMetadata.NAME_PROPS);
+ if (nameProp == null) {
+ nameProp = "";
+ }
+ if (nameProp != null && !nameProp.equals("")) {
+ String[] nameProps = nameProp.split(",");
+ for (String prop : nameProps) {
+ entity.setValue(prop, relatedObject.getValue(prop));
+ }
+ }
+ }
+ } catch (UnsupportedEncodingException e) {
+ }
+ this.previous = entity;
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processContainer(Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) {
+
+ this.previous = obj;
+
+ if (this.entity != null) {
+ this.entity.setValue(obj.getName(), obj.getUnderlyingObject());
+ } else {
+ this.entity = obj;
+ this.topEntity = obj;
+ }
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processNamespace(Introspector obj) {
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public String getCloudRegionTransform() {
+ return "add";
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public boolean useOriginalLoader() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ /**
+ * Gets the top entity.
+ *
+ * @return the top entity
+ */
+ public Introspector getTopEntity() {
+ return this.topEntity;
+ }
+
+ /**
+ * Gets the entity.
+ *
+ * @return the entity
+ */
+ public Introspector getEntity() {
+ return this.entity;
+ }
+
+ /**
+ * Gets the parent list.
+ *
+ * @return the parent list
+ */
+ public List<Object> getParentList() {
+ return this.parentList;
+ }
+
+ /**
+ * Gets the entity name.
+ *
+ * @return the entity name
+ */
+ public String getEntityName() {
+ return this.entityName;
+ }
+
+ /**
+ * Gets the top entity name.
+ *
+ * @return the top entity name
+ */
+ public String getTopEntityName() {
+ return this.topEntityName;
+ }
+
+ /**
+ * Gets the object version.
+ *
+ * @return the object version
+ */
+ public Version getObjectVersion() {
+ return this.loader.getVersion();
+ }
+ public Loader getLoader() {
+ return this.loader;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToRelationshipObject.java b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToRelationshipObject.java
new file mode 100644
index 00000000..6888dec6
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIToRelationshipObject.java
@@ -0,0 +1,171 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.uri;
+
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.Version;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.util.AAIApiServerURLBase;
+import org.openecomp.aai.workarounds.LegacyURITransformer;
+
+/**
+ * Given a URI a Relationship Object is returned.
+ *
+ * The relationship-data objects are created from the keys in the model.
+ * The keys are processed in the order they appear in the model.
+
+ *
+ */
+public class URIToRelationshipObject implements Parsable {
+
+ private Introspector result = null;
+
+ private LegacyURITransformer uriTransformer = null;
+
+ private Version originalVersion = null;
+
+ private Introspector relationship = null;
+
+ private Loader loader = null;
+
+ private String baseURL;
+
+ private final URI uri;
+ /**
+ * Instantiates a new URI to relationship object.
+ *
+ * @param loader the loader
+ * @param uri the uri
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws MalformedURLException the malformed URL exception
+ */
+ public URIToRelationshipObject(Loader loader, URI uri) throws AAIException {
+
+ this.loader = loader;
+ uriTransformer = LegacyURITransformer.getInstance();
+ originalVersion = loader.getVersion();
+
+ try {
+ relationship = loader.introspectorFromName("relationship");
+ } catch (AAIUnknownObjectException e1) {
+ throw new RuntimeException("Fatal error - could not load relationship object!", e1);
+ }
+
+ this.baseURL = AAIApiServerURLBase.get(originalVersion);
+ this.uri = uri;
+
+ }
+
+ public URIToRelationshipObject(Loader loader, URI uri, String baseURL) throws AAIException {
+ this(loader, uri);
+
+ if (baseURL != null) {
+ this.baseURL = baseURL;
+ }
+ }
+
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public String getCloudRegionTransform(){
+ return "remove";
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processObject(Introspector obj, MultivaluedMap<String, String> uriKeys) {
+
+
+ for (String key : obj.getKeys()) {
+ try {
+ Introspector data = loader.introspectorFromName("relationship-data");
+ data.setValue("relationship-key", obj.getDbName() + "." + key);
+ data.setValue("relationship-value", obj.getValue(key));
+
+ ((List<Object>)relationship.getValue("relationship-data")).add(data.getUnderlyingObject());
+ } catch (AAIUnknownObjectException e) {
+ throw new RuntimeException("Fatal error - relationship-data object not found!");
+ }
+ }
+ relationship.setValue("related-to", obj.getDbName());
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processContainer(Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer) {
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void processNamespace(Introspector obj) {
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public boolean useOriginalLoader() {
+ return true;
+ }
+
+ /**
+ * Gets the result.
+ *
+ * @return the result
+ * @throws AAIException
+ * @throws UnsupportedEncodingException
+ * @throws URISyntaxException
+ */
+ public Introspector getResult() throws UnsupportedEncodingException, AAIException, URISyntaxException {
+ URIParser parser = new URIParser(this.loader, this.uri);
+ parser.parse(this);
+ URI originalUri = parser.getOriginalURI();
+
+ URI relatedLink = new URI(this.baseURL + this.originalVersion + "/" + originalUri);
+ this.relationship.setValue("related-link", relatedLink);
+
+
+ this.result = relationship;
+ return this.result;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIValidate.java b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIValidate.java
new file mode 100644
index 00000000..1a7ac0b2
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/parsers/uri/URIValidate.java
@@ -0,0 +1,62 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.parsers.uri;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+
+class URIValidate implements Parsable {
+
+ @Override
+ public void processObject(Introspector obj, MultivaluedMap<String, String> uriKeys) throws AAIException {
+ //NO-OP
+ //just want to make sure this URI has valid tokens
+ }
+
+ @Override
+ public void processContainer(Introspector obj, MultivaluedMap<String, String> uriKeys, boolean isFinalContainer)
+ throws AAIException {
+ //NO-OP
+ //just want to make sure this URI has valid tokens
+
+ }
+
+ @Override
+ public void processNamespace(Introspector obj) {
+ //NO-OP
+ //just want to make sure this URI has valid tokens
+
+ }
+
+ @Override
+ public String getCloudRegionTransform() {
+ return "none";
+ }
+
+ @Override
+ public boolean useOriginalLoader() {
+
+ return true;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/GraphTraversalBuilder.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/GraphTraversalBuilder.java
new file mode 100644
index 00000000..336114f0
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/GraphTraversalBuilder.java
@@ -0,0 +1,491 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.query.builder;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal.Admin;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.schema.enums.ObjectMetadata;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+import org.openecomp.aai.serialization.db.EdgeRule;
+import org.openecomp.aai.serialization.db.EdgeRules;
+import org.openecomp.aai.serialization.db.EdgeType;
+import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
+
+/**
+ * The Class GraphTraversalBuilder.
+ */
+public abstract class GraphTraversalBuilder extends QueryBuilder {
+
+ protected GraphTraversal<Vertex, Vertex> traversal = null;
+ protected Admin<Vertex, Vertex> completeTraversal = null;
+ private EdgeRules edgeRules = EdgeRules.getInstance();
+
+ protected int parentStepIndex = 0;
+ protected int containerStepIndex = 0;
+ protected int stepIndex = 0;
+
+ /**
+ * Instantiates a new graph traversal builder.
+ *
+ * @param loader the loader
+ */
+ public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) {
+ super(loader, source);
+
+ traversal = __.start();
+
+ }
+
+ /**
+ * Instantiates a new graph traversal builder.
+ *
+ * @param loader the loader
+ * @param start the start
+ */
+ public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
+ super(loader, source, start);
+
+ traversal = __.start();
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder getVerticesByIndexedProperty(String key, Object value) {
+
+ return this.getVerticesByProperty(key, value);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder getVerticesByIndexedProperty(String key, List<?> values) {
+ return this.getVerticesByProperty(key, values);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder getVerticesByProperty(String key, Object value) {
+
+ //this is because the index is registered as an Integer
+ value = this.correctObjectType(value);
+
+ traversal.has(key, value);
+
+ stepIndex++;
+ return this;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder getVerticesByProperty(final String key, final List<?> values) {
+
+ //this is because the index is registered as an Integer
+ List<Object> correctedValues = new ArrayList<>();
+ for (Object item : values) {
+ correctedValues.add(this.correctObjectType(item));
+ }
+
+ traversal.has(key, P.within(correctedValues));
+
+ stepIndex++;
+ return this;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
+ traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType);
+ stepIndex++;
+ return this;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder getTypedVerticesByMap(String type, LinkedHashMap<String, String> map) {
+
+ for (String key : map.keySet()) {
+ traversal.has(key, map.get(key));
+ stepIndex++;
+ }
+ traversal.has(AAIProperties.NODE_TYPE, type);
+ stepIndex++;
+ return this;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder createDBQuery(Introspector obj) {
+ this.createKeyQuery(obj);
+ this.createContainerQuery(obj);
+ return this;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder createKeyQuery(Introspector obj) {
+ Set<String> keys = obj.getKeys();
+ Object val;
+ for (String key : keys) {
+ val = obj.getValue(key);
+ Optional<String> metadata = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS);
+ if (metadata.isPresent()) {
+ //use the db name for the field rather than the object model
+ key = metadata.get();
+ }
+ if (val != null) {
+ //this is because the index is registered as an Integer
+ if (val.getClass().equals(Long.class)) {
+ traversal.has(key,new Integer(val.toString()));
+ } else {
+ traversal.has(key, val);
+ }
+ stepIndex++;
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public QueryBuilder exactMatchQuery(Introspector obj) {
+ this.createKeyQuery(obj);
+ allPropertiesQuery(obj);
+ this.createContainerQuery(obj);
+ return this;
+ }
+
+ private void allPropertiesQuery(Introspector obj) {
+ Set<String> props = obj.getProperties();
+ Set<String> keys = obj.getKeys();
+ Object val;
+ for (String prop : props) {
+ if (obj.isSimpleType(prop) && !keys.contains(prop)) {
+ val = obj.getValue(prop);
+ if (val != null) {
+ Optional<String> metadata = obj.getPropertyMetadata(prop, PropertyMetadata.DB_ALIAS);
+ if (metadata.isPresent()) {
+ //use the db name for the field rather than the object model
+ prop = metadata.get();
+ }
+ //this is because the index is registered as an Integer
+ if (val != null && val.getClass().equals(Long.class)) {
+ traversal.has(prop,new Integer(val.toString()));
+ } else {
+ traversal.has(prop, val);
+ }
+ stepIndex++;
+ }
+ }
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+
+ public QueryBuilder createContainerQuery(Introspector obj) {
+ String type = obj.getChildDBName();
+ String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
+ if (abstractType != null) {
+ String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
+ traversal.has(AAIProperties.NODE_TYPE, P.within(inheritors));
+ } else {
+ traversal.has(AAIProperties.NODE_TYPE, type);
+ }
+ stepIndex++;
+ markContainer();
+ return this;
+ }
+
+ /**
+ * @throws NoEdgeRuleFoundException
+ * @throws AAIException
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
+ String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT);
+ if ("true".equals(isAbstractType)) {
+ markParentBoundary();
+ traversal.union(handleAbstractEdge(type, parent, child));
+ stepIndex += 1;
+ } else {
+ this.edgeQuery(type, parent, child);
+ }
+ return this;
+
+ }
+
+ private Traversal<Vertex, Vertex>[] handleAbstractEdge(EdgeType type, Introspector abstractParent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
+ String childName = child.getDbName();
+ String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS);
+ String[] inheritors = inheritorMetadata.split(",");
+ Traversal<Vertex, Vertex>[] unionTraversals = new Traversal[inheritors.length];
+ int traversalIndex = 0;
+ for (int i = 0; i < inheritors.length; i++) {
+ String inheritor = inheritors[i];
+ if (edgeRules.hasEdgeRule(inheritor, childName) || edgeRules.hasEdgeRule(childName, inheritor)) {
+ EdgeRule rule = edgeRules.getEdgeRule(type, inheritor, childName);
+ GraphTraversal<Vertex, Vertex> innerTraversal = __.start();
+ if (rule.getDirection().equals(Direction.OUT)) {
+ innerTraversal.out(rule.getLabel());
+ } else {
+ innerTraversal.in(rule.getLabel());
+ }
+ innerTraversal.has(AAIProperties.NODE_TYPE, childName);
+ unionTraversals[traversalIndex] = innerTraversal;
+ traversalIndex++;
+ }
+ }
+ if (traversalIndex < inheritors.length) {
+ Traversal<Vertex, Vertex>[] temp = Arrays.copyOfRange(unionTraversals, 0, traversalIndex);
+ unionTraversals = temp;
+ }
+ return unionTraversals;
+ }
+ /**
+ * @throws NoEdgeRuleFoundException
+ * @throws AAIException
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder createEdgeTraversal(EdgeType type, Vertex parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
+
+ String nodeType = parent.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ Introspector parentObj = loader.introspectorFromName(nodeType);
+ this.edgeQuery(type, parentObj, child);
+ return this;
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder union(QueryBuilder... builder) {
+ GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
+ for (int i = 0; i < builder.length; i++) {
+ traversals[i] = (GraphTraversal<Vertex, Vertex>)builder[i].getQuery();
+ }
+ this.traversal.union(traversals);
+ stepIndex++;
+
+ return this;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder where(QueryBuilder... builder) {
+ GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
+ for (int i = 0; i < builder.length; i++) {
+ this.traversal.where((GraphTraversal<Vertex, Vertex>)builder[i].getQuery());
+ stepIndex++;
+ }
+
+ return this;
+ }
+
+ /**
+ * Edge query.
+ *
+ * @param outType the out type
+ * @param inType the in type
+ * @throws NoEdgeRuleFoundException
+ * @throws AAIException
+ */
+ private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj) throws AAIException, NoEdgeRuleFoundException {
+ String outType = outObj.getDbName();
+ String inType = inObj.getDbName();
+
+ if (outObj.isContainer()) {
+ outType = outObj.getChildDBName();
+ }
+ if (inObj.isContainer()) {
+ inType = inObj.getChildDBName();
+ }
+ markParentBoundary();
+ EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType);
+ if (rule.getDirection().equals(Direction.OUT)) {
+ traversal.out(rule.getLabel());
+ } else {
+ traversal.in(rule.getLabel());
+ }
+ stepIndex++;
+ this.createContainerQuery(inObj);
+ }
+
+ @Override
+ public QueryBuilder limit(long amount) {
+ traversal.limit(amount);
+ return this;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public <T> T getQuery() {
+ return (T)this.traversal;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder getParentQuery() {
+
+ return cloneQueryAtStep(parentStepIndex);
+ }
+
+ @Override
+ public QueryBuilder getContainerQuery() {
+
+ if (this.parentStepIndex == 0) {
+ return removeQueryStepsBetween(0, containerStepIndex);
+ } else {
+ return cloneQueryAtStep(containerStepIndex);
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void markParentBoundary() {
+ parentStepIndex = stepIndex;
+ }
+
+ @Override
+ public void markContainer() {
+ containerStepIndex = stepIndex;
+ }
+
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public Vertex getStart() {
+ return this.start;
+ }
+
+ protected int getParentStepIndex() {
+ return parentStepIndex;
+ }
+
+ protected int getContainerStepIndex() {
+ return containerStepIndex;
+ }
+
+ protected int getStepIndex() {
+ return stepIndex;
+ }
+
+ protected abstract QueryBuilder cloneQueryAtStep(int index);
+ /**
+ * end is exclusive
+ *
+ * @param start
+ * @param end
+ * @return
+ */
+ protected abstract QueryBuilder removeQueryStepsBetween(int start, int end);
+
+ private void executeQuery() {
+
+ Admin<Vertex, Vertex> admin;
+ if (start != null) {
+ admin = source.V(start).asAdmin();
+ } else {
+ admin = source.V().asAdmin();
+
+ }
+
+ TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin);
+
+ this.completeTraversal = admin;
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (this.completeTraversal == null) {
+ executeQuery();
+ }
+
+ return this.completeTraversal.hasNext();
+ }
+
+ @Override
+ public Vertex next() {
+ if (this.completeTraversal == null) {
+ executeQuery();
+ }
+
+ return this.completeTraversal.next();
+ }
+
+ @Override
+ public List<Vertex> toList() {
+ if (this.completeTraversal == null) {
+ executeQuery();
+ }
+
+ return this.completeTraversal.toList();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinPipelineBuilder.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinPipelineBuilder.java
new file mode 100644
index 00000000..d06e1e18
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinPipelineBuilder.java
@@ -0,0 +1,214 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+package org.openecomp.aai.query.builder;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.serialization.db.EdgeRule;
+import org.openecomp.aai.serialization.db.EdgeRules;
+
+public abstract class GremlinPipelineBuilder extends QueryBuilder {
+
+ private GremlinPipeline pipeline = null;
+ private EdgeRules edgeRules = EdgeRules.getInstance();
+ private int parentStepIndex = 0;
+ private int stepIndex = 0;
+
+ public GremlinPipelineBuilder(Loader loader) {
+ super(loader);
+
+ pipeline = new GremlinPipeline(new IdentityPipe()).V();
+
+ }
+
+ public GremlinPipelineBuilder(Loader loader, Vertex start) {
+ super(loader, start);
+
+ pipeline = new GremlinPipeline(start);
+
+ }
+
+ @Override
+ public QueryBuilder getVerticesByIndexedProperty(String key, Object value) {
+
+ return this.getVerticesByProperty(key, value);
+ }
+
+ @Override
+ public QueryBuilder getVerticesByProperty(String key, Object value) {
+
+ //this is because the index is registered as an Integer
+ if (value != null && value.getClass().equals(Long.class)) {
+ pipeline.has(key,new Integer(value.toString()));
+ } else {
+ pipeline.has(key, value);
+ }
+ stepIndex++;
+ return this;
+ }
+
+ @Override
+ public QueryBuilder getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
+ pipeline.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType);
+ stepIndex++;
+ return this;
+ }
+
+ @Override
+ public QueryBuilder getTypedVerticesByMap(String type, LinkedHashMap<String, String> map) {
+
+ for (String key : map.keySet()) {
+ pipeline.has(key, map.get(key));
+ stepIndex++;
+ }
+ pipeline.has(AAIProperties.NODE_TYPE, type);
+ stepIndex++;
+ return this;
+ }
+
+ @Override
+ public QueryBuilder createDBQuery(Introspector obj) {
+ this.createKeyQuery(obj);
+ this.createContainerQuery(obj);
+ return this;
+ }
+
+ @Override
+ public QueryBuilder createKeyQuery(Introspector obj) {
+ List<String> keys = obj.getKeys();
+ Object val = null;
+ for (String key : keys) {
+ val = obj.getValue(key);
+ //this is because the index is registered as an Integer
+ if (val != null && val.getClass().equals(Long.class)) {
+ pipeline.has(key,new Integer(val.toString()));
+ } else {
+ pipeline.has(key, val);
+ }
+ stepIndex++;
+ }
+ return this;
+ }
+
+ @Override
+
+ public QueryBuilder createContainerQuery(Introspector obj) {
+ String type = obj.getChildDBName();
+ String abstractType = obj.getMetadata("abstract");
+ if (abstractType != null) {
+ String[] inheritors = obj.getMetadata("inheritors").split(",");
+ GremlinPipeline[] pipes = new GremlinPipeline[inheritors.length];
+ for (int i = 0; i < inheritors.length; i++) {
+ pipes[i] = new GremlinPipeline(new IdentityPipe()).has(AAIProperties.NODE_TYPE, inheritors[i]);
+ }
+ pipeline.or(pipes);
+ } else {
+ pipeline.has(AAIProperties.NODE_TYPE, type);
+ }
+ stepIndex++;
+ return this;
+ }
+
+ @Override
+ public QueryBuilder createEdgeTraversal(Introspector parent, Introspector child) {
+ String parentName = parent.getDbName();
+ String childName = child.getDbName();
+ String isAbstractType = parent.getMetadata("abstract");
+ if ("true".equals(isAbstractType)) {
+ formBoundary();
+ pipeline.outE().has("isParent", true).inV();
+ } else {
+ if (parent.isContainer()) {
+ parentName = parent.getChildDBName();
+ }
+ if (child.isContainer()) {
+ childName = child.getChildDBName();
+ }
+ this.edgeQuery(parentName, childName);
+ }
+ return this;
+
+ }
+
+ @Override
+ public QueryBuilder createEdgeTraversal(Vertex parent, Introspector child) {
+
+ String nodeType = parent.getProperty(AAIProperties.NODE_TYPE);
+ this.edgeQuery(nodeType, child.getDbName());
+ return this;
+
+ }
+
+ private void edgeQuery(String outType, String inType) {
+ formBoundary();
+ EdgeRule rule;
+ String label = "";
+ try {
+ rule = edgeRules.getEdgeRule(outType, inType);
+ label = rule.getLabel();
+ } catch (AAIException e) {
+ // TODO Auto-generated catch block
+ }
+ pipeline = pipeline.out(label);
+ stepIndex++;
+ }
+
+ @Override
+ public Object getQuery() {
+ return this.pipeline;
+ }
+
+ @Override
+ public Object getParentQuery() {
+ GremlinPipeline parent = new GremlinPipeline();
+ if (parentStepIndex == 0) {
+ parentStepIndex = stepIndex;
+ }
+ List<Pipe> pipes = this.pipeline.getPipes();
+ //add two for the garbage identity pipes
+ for (int i = 0; i < parentStepIndex + 2; i++) {
+ parent.add(pipes.get(i));
+ }
+
+ return parent;
+ }
+
+ @Override
+ public void formBoundary() {
+ parentStepIndex = stepIndex;
+ }
+
+
+ @Override
+ public Vertex getStart() {
+ return this.start;
+ }
+
+}
+*/
diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinPipelineTraversal.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinPipelineTraversal.java
new file mode 100644
index 00000000..c8147ed4
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinPipelineTraversal.java
@@ -0,0 +1,76 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+package org.openecomp.aai.query.builder;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.parsers.query.QueryParser;
+import org.openecomp.aai.parsers.query.TraversalStrategy;
+
+public class GremlinPipelineTraversal extends GremlinPipelineBuilder {
+
+ public GremlinPipelineTraversal(Loader loader) {
+ super(loader);
+ this.factory = new TraversalStrategy(this.loader, this);
+ }
+
+ public GremlinPipelineTraversal(Loader loader, Vertex start) {
+ super(loader, start);
+ this.factory = new TraversalStrategy(this.loader, this);
+ }
+
+ @Override
+ public QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException {
+ return factory.buildURIParser(uri);
+ }
+
+ @Override
+ public QueryParser createQueryFromRelationship(Introspector relationship) throws UnsupportedEncodingException, AAIException {
+ return factory.buildRelationshipParser(relationship);
+ }
+
+ @Override
+ public QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams)
+ throws UnsupportedEncodingException, AAIException {
+ return factory.buildURIParser(uri, queryParams);
+ }
+
+ @Override
+ public QueryBuilder newInstance(Vertex start) {
+ return new GremlinPipelineTraversal(loader, start);
+ }
+
+ @Override
+ public QueryBuilder newInstance() {
+ return new GremlinPipelineTraversal(loader);
+ }
+
+}
+*/
diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinQueryBuilder.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinQueryBuilder.java
new file mode 100644
index 00000000..9c313ca8
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinQueryBuilder.java
@@ -0,0 +1,416 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.query.builder;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.restcore.search.GremlinGroovyShellSingleton;
+import org.openecomp.aai.schema.enums.ObjectMetadata;
+import org.openecomp.aai.serialization.db.EdgeRule;
+import org.openecomp.aai.serialization.db.EdgeRules;
+import org.openecomp.aai.serialization.db.EdgeType;
+import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
+import com.google.common.base.Joiner;
+
+/**
+ * The Class GremlinQueryBuilder.
+ */
+public abstract class GremlinQueryBuilder extends QueryBuilder {
+
+ private EdgeRules edgeRules = EdgeRules.getInstance();
+ private GremlinGroovyShellSingleton gremlinGroovy = GremlinGroovyShellSingleton.getInstance();
+ private GraphTraversal<?, ?> completeTraversal = null;
+ protected List<String> list = null;
+
+ protected int parentStepIndex = 0;
+ protected int containerStepIndex = 0;
+ protected int stepIndex = 0;
+
+ /**
+ * Instantiates a new gremlin query builder.
+ *
+ * @param loader the loader
+ */
+ public GremlinQueryBuilder(Loader loader, GraphTraversalSource source) {
+ super(loader, source);
+ list = new ArrayList<String>();
+ }
+
+ /**
+ * Instantiates a new gremlin query builder.
+ *
+ * @param loader the loader
+ * @param start the start
+ */
+ public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
+ super(loader, source, start);
+ list = new ArrayList<String>();
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder createDBQuery(Introspector obj) {
+ this.createKeyQuery(obj);
+ this.createContainerQuery(obj);
+ return this;
+ }
+
+ @Override
+ public QueryBuilder exactMatchQuery(Introspector obj) {
+ // TODO not implemented because this is implementation is no longer used
+ this.createKeyQuery(obj);
+ //allPropertiesQuery(obj);
+ this.createContainerQuery(obj);
+ return this;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder getVerticesByIndexedProperty(String key, Object value) {
+ return this.getVerticesByProperty(key, value);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder getVerticesByIndexedProperty(String key, List<?> values) {
+ return this.getVerticesByProperty(key, values);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder getVerticesByProperty(String key, Object value) {
+
+ String term = "";
+ if (value != null && !value.getClass().getName().equals("java.lang.String")) {
+ term = value.toString();
+ } else {
+ term = "'" + value + "'";
+ }
+ list.add(".has('" + key + "', " + term + ")");
+ stepIndex++;
+ return this;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder getVerticesByProperty(String key, List<?> values) {
+
+ String term = "";
+ String predicate = "P.within(#!#argument#!#)";
+ List<String> arguments = new ArrayList<>();
+ for (Object item : values) {
+ if (item != null && !item.getClass().getName().equals("java.lang.String")) {
+ arguments.add(item.toString());
+ } else {
+ arguments.add("'" + item + "'");
+ }
+ }
+ String argument = Joiner.on(",").join(arguments);
+ predicate = predicate.replace("#!#argument#!#", argument);
+ list.add(".has('" + key + "', " + predicate + ")");
+ stepIndex++;
+ return this;
+ }
+
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
+ /*
+ String query = ".has('aai-node-type', '" + childType + "')";
+
+ return this.processGremlinQuery(parentKey, parentValue, query);
+ */
+ //TODO
+ return this;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder getTypedVerticesByMap(String type, LinkedHashMap<String, String> map) {
+
+ for (String key : map.keySet()) {
+ list.add(".has('" + key + "', '" + map.get(key) + "')");
+ stepIndex++;
+ }
+ list.add(".has('aai-node-type', '" + type + "')");
+ stepIndex++;
+ return this;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder createKeyQuery(Introspector obj) {
+ Set<String> keys = obj.getKeys();
+
+ for (String key : keys) {
+
+ this.getVerticesByProperty(key, obj.<Object>getValue(key));
+
+ }
+ return this;
+ }
+
+ /**
+ * @throws NoEdgeRuleFoundException
+ * @throws AAIException
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
+ String parentName = parent.getDbName();
+ String childName = child.getDbName();
+ if (parent.isContainer()) {
+ parentName = parent.getChildDBName();
+ }
+ if (child.isContainer()) {
+ childName = child.getChildDBName();
+ }
+ this.edgeQuery(type, parentName, childName);
+ return this;
+
+ }
+
+ /**
+ * @throws NoEdgeRuleFoundException
+ * @throws AAIException
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder createEdgeTraversal(EdgeType type, Vertex parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
+ String nodeType = parent.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ this.edgeQuery(type, nodeType, child.getDbName());
+
+ return this;
+
+ }
+
+ /**
+ * Edge query.
+ *
+ * @param outType the out type
+ * @param inType the in type
+ * @throws NoEdgeRuleFoundException
+ * @throws AAIException
+ */
+ private void edgeQuery(EdgeType type, String outType, String inType) throws AAIException, NoEdgeRuleFoundException {
+ markParentBoundary();
+ EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType);
+ if (rule.getDirection().equals(Direction.OUT)) {
+ list.add(".out('" + rule.getLabel() + "')");
+ } else {
+ list.add(".in('" + rule.getLabel() + "')");
+ }
+ list.add(".has('" + AAIProperties.NODE_TYPE + "', '" + inType + "')");
+ stepIndex += 2;
+ }
+ @Override
+ public QueryBuilder limit(long amount) {
+ list.add(".limit(" + amount + ")");
+ return this;
+ }
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder createContainerQuery(Introspector obj) {
+ String type = obj.getChildDBName();
+ String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
+ if (abstractType != null) {
+ String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
+ String[] wrapped = new String[inheritors.length];
+ StringBuilder command = new StringBuilder();
+ command.append("P.within(");
+ for (int i = 0; i < inheritors.length; i++) {
+ wrapped[i] = "'" + inheritors[i] + "'";
+ }
+ command.append(Joiner.on(",").join(wrapped));
+ command.append(")");
+ list.add(".has('aai-node-type', " + command + ")");
+
+ } else {
+ list.add(".has('aai-node-type', '" + type + "')");
+ }
+ stepIndex++;
+ this.markContainer();
+ return this;
+ }
+
+ @Override
+ public QueryBuilder union(QueryBuilder... builder) {
+ markParentBoundary();
+ String[] traversals = new String[builder.length];
+ StringBuilder command = new StringBuilder();
+ for (int i = 0; i < builder.length; i++) {
+ traversals[i] = "__" + (String)builder[i].getQuery();
+ }
+ command.append(".union(");
+ command.append(Joiner.on(",").join(traversals));
+ command.append(")");
+ list.add(command.toString());
+ stepIndex++;
+
+ return this;
+ }
+
+ @Override
+ public QueryBuilder where(QueryBuilder... builder) {
+ markParentBoundary();
+ List<String> traversals = new ArrayList<>();
+ for (int i = 0; i < builder.length; i++) {
+ traversals.add(".where(__" + (String)builder[i].getQuery() + ")");
+ stepIndex++;
+ }
+ list.addAll(traversals);
+
+
+ return this;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder getParentQuery() {
+ return cloneQueryAtStep(parentStepIndex);
+ }
+
+ @Override
+ public QueryBuilder getContainerQuery() {
+ return cloneQueryAtStep(containerStepIndex);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public <T> T getQuery() {
+ StringBuilder sb = new StringBuilder();
+
+ for (String piece : this.list) {
+ sb.append(piece);
+ }
+
+ return (T)sb.toString();
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void markParentBoundary() {
+ parentStepIndex = stepIndex;
+ }
+
+ @Override
+ public void markContainer() {
+ this.containerStepIndex = stepIndex;
+ }
+
+ protected abstract QueryBuilder cloneQueryAtStep(int index);
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public Vertex getStart() {
+ return this.start;
+ }
+
+ protected int getParentStepIndex() {
+ return parentStepIndex;
+ }
+
+ protected int getContainerStepIndex() {
+ return containerStepIndex;
+ }
+
+ protected int getStepIndex() {
+ return stepIndex;
+ }
+
+ private void executeQuery() {
+ String queryString = "g" + Joiner.on("").join(list);
+ Map<String, Object> params = new HashMap<>();
+ if (this.start == null) {
+ params.put("g", source.V());
+ } else {
+ params.put("g", source.V(this.start));
+ }
+ this.completeTraversal = this.gremlinGroovy.executeTraversal(queryString, params);
+ }
+ @Override
+ public boolean hasNext() {
+ if (this.completeTraversal == null) {
+ executeQuery();
+ }
+
+ return this.completeTraversal.hasNext();
+ }
+
+ @Override
+ public Vertex next() {
+ if (this.completeTraversal == null) {
+ executeQuery();
+ }
+
+ return (Vertex)this.completeTraversal.next();
+ }
+
+ @Override
+ public List<Vertex> toList() {
+ if (this.completeTraversal == null) {
+ executeQuery();
+ }
+
+ return (List<Vertex>)this.completeTraversal.toList();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinTraversal.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinTraversal.java
new file mode 100644
index 00000000..5b70d43d
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinTraversal.java
@@ -0,0 +1,137 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.query.builder;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.parsers.query.QueryParser;
+import org.openecomp.aai.parsers.query.TraversalStrategy;
+
+/**
+ * The Class GremlinTraversal.
+ */
+public class GremlinTraversal extends GremlinQueryBuilder {
+
+ /**
+ * Instantiates a new gremlin traversal.
+ *
+ * @param loader the loader
+ */
+ public GremlinTraversal(Loader loader, GraphTraversalSource source) {
+ super(loader, source);
+ this.factory = new TraversalStrategy(this.loader, this);
+ }
+
+ /**
+ * Instantiates a new gremlin traversal.
+ *
+ * @param loader the loader
+ * @param start the start
+ */
+ public GremlinTraversal(Loader loader, GraphTraversalSource source, Vertex start) {
+ super(loader, source, start);
+ this.factory = new TraversalStrategy(this.loader, this);
+ }
+
+ protected GremlinTraversal(List<String> traversal, Loader loader, GraphTraversalSource source, GremlinQueryBuilder gtb) {
+ super(loader, source);
+ this.list = traversal;
+ this.stepIndex = gtb.getStepIndex();
+ this.parentStepIndex = gtb.getParentStepIndex();
+ this.containerStepIndex = gtb.getContainerStepIndex();
+ this.factory = new TraversalStrategy(this.loader, this);
+ this.start = gtb.getStart();
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException {
+ return factory.buildURIParser(uri);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser createQueryFromRelationship(Introspector relationship) throws UnsupportedEncodingException, AAIException {
+ return factory.buildRelationshipParser(relationship);
+ }
+
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams)
+ throws UnsupportedEncodingException, AAIException {
+ return factory.buildURIParser(uri, queryParams);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser createQueryFromObjectName(String objName) {
+ return factory.buildObjectNameParser(objName);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder newInstance(Vertex start) {
+ return new GremlinTraversal(loader, source, start);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder newInstance() {
+ return new GremlinTraversal(loader, source);
+ }
+
+ @Override
+ protected QueryBuilder cloneQueryAtStep(int index) {
+ if (index == 0) {
+ index = stepIndex;
+ }
+ List<String> newList = new ArrayList<>();
+ for (int i = 0; i < index; i++) {
+ newList.add(this.list.get(i));
+ }
+
+ return new GremlinTraversal(newList, loader, source, this);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinUnique.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinUnique.java
new file mode 100644
index 00000000..d9fb06b8
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/GremlinUnique.java
@@ -0,0 +1,137 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.query.builder;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.parsers.query.QueryParser;
+import org.openecomp.aai.parsers.query.TraversalStrategy;
+import org.openecomp.aai.parsers.query.UniqueStrategy;
+
+/**
+ * The Class GremlinUnique.
+ */
+public class GremlinUnique extends GremlinQueryBuilder {
+
+ /**
+ * Instantiates a new gremlin unique.
+ *
+ * @param loader the loader
+ */
+ public GremlinUnique(Loader loader, GraphTraversalSource source) {
+ super(loader, source);
+ this.factory = new UniqueStrategy(this.loader, this);
+ }
+
+ /**
+ * Instantiates a new gremlin unique.
+ *
+ * @param loader the loader
+ * @param start the start
+ */
+ public GremlinUnique(Loader loader, GraphTraversalSource source, Vertex start) {
+ super(loader, source, start);
+ this.factory = new UniqueStrategy(this.loader, this);
+ }
+
+ protected GremlinUnique(List<String> traversal, Loader loader, GraphTraversalSource source, GremlinQueryBuilder gtb) {
+ super(loader, source);
+ this.list = traversal;
+ this.stepIndex = gtb.getStepIndex();
+ this.parentStepIndex = gtb.getParentStepIndex();
+ this.containerStepIndex = gtb.getContainerStepIndex();
+ this.factory = new TraversalStrategy(this.loader, this);
+ this.start = gtb.getStart();
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException {
+ return factory.buildURIParser(uri);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser createQueryFromRelationship(Introspector relationship) throws UnsupportedEncodingException, AAIException {
+ return factory.buildRelationshipParser(relationship);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams)
+ throws UnsupportedEncodingException, AAIException {
+ return factory.buildURIParser(uri, queryParams);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser createQueryFromObjectName(String objName) {
+ return factory.buildObjectNameParser(objName);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder newInstance() {
+ return new GremlinUnique(loader, source);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder newInstance(Vertex start) {
+ return new GremlinUnique(loader, source, start);
+ }
+
+ @Override
+ protected QueryBuilder cloneQueryAtStep(int index) {
+ if (index == 0) {
+ index = stepIndex;
+ }
+ List<String> newList = new ArrayList<>();
+ for (int i = 0; i < index; i++) {
+ newList.add(this.list.get(i));
+ }
+
+ return new GremlinUnique(newList, loader, source, this);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/QueryBuilder.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/QueryBuilder.java
new file mode 100644
index 00000000..ad9f3082
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/QueryBuilder.java
@@ -0,0 +1,293 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.query.builder;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.parsers.query.QueryParser;
+import org.openecomp.aai.parsers.query.QueryParserStrategy;
+import org.openecomp.aai.serialization.db.EdgeType;
+import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
+
+/**
+ * The Class QueryBuilder.
+ */
+public abstract class QueryBuilder implements Iterator<Vertex> {
+
+ protected QueryParserStrategy factory = null;
+
+ protected Loader loader = null;
+
+ protected boolean optimize = false;
+
+ protected Vertex start = null;
+ protected final GraphTraversalSource source;
+
+ /**
+ * Instantiates a new query builder.
+ *
+ * @param loader the loader
+ */
+ public QueryBuilder(Loader loader, GraphTraversalSource source) {
+ this.loader = loader;
+ this.source = source;
+ }
+
+ /**
+ * Instantiates a new query builder.
+ *
+ * @param loader the loader
+ * @param start the start
+ */
+ public QueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
+ this.loader = loader;
+ this.start = start;
+ this.source = source;
+ }
+
+ /**
+ * Gets the vertices by indexed property.
+ *
+ * @param key the key
+ * @param value the value
+ * @return the vertices by indexed property
+ */
+ public abstract QueryBuilder getVerticesByIndexedProperty(String key, Object value);
+
+ /**
+ * Gets the vertices by property.
+ *
+ * @param key the key
+ * @param value the value
+ * @return the vertices by property
+ */
+ public abstract QueryBuilder getVerticesByProperty(String key, Object value);
+
+ /**
+ * filters by all the values for this property
+ * @param key
+ * @param values
+ * @return vertices that match these values
+ */
+ public abstract QueryBuilder getVerticesByIndexedProperty(String key, List<?> values);
+
+ /**
+ * filters by all the values for this property
+ * @param key
+ * @param values
+ * @return vertices that match these values
+ */
+ public abstract QueryBuilder getVerticesByProperty(String key, List<?> values);
+
+ /**
+ * Gets the child vertices from parent.
+ *
+ * @param parentKey the parent key
+ * @param parentValue the parent value
+ * @param childType the child type
+ * @return the child vertices from parent
+ */
+ public abstract QueryBuilder getChildVerticesFromParent(String parentKey, String parentValue, String childType);
+
+ /**
+ * Gets the typed vertices by map.
+ *
+ * @param type the type
+ * @param map the map
+ * @return the typed vertices by map
+ */
+ public abstract QueryBuilder getTypedVerticesByMap(String type, LinkedHashMap<String, String> map);
+
+ /**
+ * Creates the DB query.
+ *
+ * @param obj the obj
+ * @return the query builder
+ */
+ public abstract QueryBuilder createDBQuery(Introspector obj);
+
+ /**
+ * Creates the key query.
+ *
+ * @param obj the obj
+ * @return the query builder
+ */
+ public abstract QueryBuilder createKeyQuery(Introspector obj);
+
+ /**
+ * Creates the container query.
+ *
+ * @param obj the obj
+ * @return the query builder
+ */
+ public abstract QueryBuilder createContainerQuery(Introspector obj);
+
+ /**
+ * Creates the edge traversal.
+ *
+ * @param parent the parent
+ * @param child the child
+ * @return the query builder
+ */
+ public abstract QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException;
+
+ /**
+ * Creates the edge traversal.
+ *
+ * @param parent the parent
+ * @param child the child
+ * @return the query builder
+ */
+ public abstract QueryBuilder createEdgeTraversal(EdgeType type, Vertex parent, Introspector child) throws AAIException;
+
+ public QueryBuilder createEdgeTraversal(EdgeType type, String outNodeType, String inNodeType) throws NoEdgeRuleFoundException, AAIException {
+ Introspector out = loader.introspectorFromName(outNodeType);
+ Introspector in = loader.introspectorFromName(inNodeType);
+
+ return createEdgeTraversal(type, out, in);
+ }
+
+ /**
+ * Creates the query from URI.
+ *
+ * @param uri the uri
+ * @return the query parser
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public abstract QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException;
+
+ /**
+ * Creates the query from URI.
+ *
+ * @param uri the uri
+ * @param queryParams the query params
+ * @return the query parser
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public abstract QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams) throws UnsupportedEncodingException, AAIException;
+
+ /**
+ * Creates a queryparser from a given object name.
+ *
+ * @param objName - name of the object type as it appears in the database
+ * @return
+ */
+ public abstract QueryParser createQueryFromObjectName(String objName);
+
+ /**
+ * Creates the query from relationship.
+ *
+ * @param relationship the relationship
+ * @return the query parser
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public abstract QueryParser createQueryFromRelationship(Introspector relationship) throws UnsupportedEncodingException, AAIException;
+
+ /**
+ * Gets the parent query.
+ *
+ * @return the parent query
+ */
+ public abstract QueryBuilder getParentQuery();
+
+ /**
+ * Gets the query.
+ *
+ * @return the query
+ */
+ public abstract <T> T getQuery();
+
+ /**
+ * Form boundary.
+ */
+ public abstract void markParentBoundary();
+
+ public abstract QueryBuilder limit(long amount);
+ /**
+ * New instance.
+ *
+ * @param start the start
+ * @return the query builder
+ */
+ public abstract QueryBuilder newInstance(Vertex start);
+
+ /**
+ * New instance.
+ *
+ * @return the query builder
+ */
+ public abstract QueryBuilder newInstance();
+
+ /**
+ * Gets the start.
+ *
+ * @return the start
+ */
+ public abstract Vertex getStart();
+
+ protected Object correctObjectType(Object obj) {
+
+ if (obj != null && obj.getClass().equals(Long.class)) {
+ return new Integer(obj.toString());
+ }
+
+ return obj;
+ }
+ /**
+ * uses all fields in the introspector to create a query
+ *
+ * @param obj
+ * @return
+ */
+ public abstract QueryBuilder exactMatchQuery(Introspector obj);
+
+ /**
+ * lets you join any number of QueryBuilders
+ * <b>be careful about starting with a union it will not use indexes</b>
+ * @param builder
+ * @return
+ */
+ public abstract QueryBuilder union(QueryBuilder[] builder);
+
+ public abstract QueryBuilder where(QueryBuilder[] builder);
+ public abstract void markContainer();
+
+ public abstract QueryBuilder getContainerQuery();
+
+ public abstract List<Vertex> toList();
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/query/builder/TraversalQuery.java b/aai-core/src/main/java/org/openecomp/aai/query/builder/TraversalQuery.java
new file mode 100644
index 00000000..84e72860
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/query/builder/TraversalQuery.java
@@ -0,0 +1,150 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.query.builder;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.List;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.parsers.query.QueryParser;
+import org.openecomp.aai.parsers.query.TraversalStrategy;
+
+/**
+ * The Class TraversalQuery.
+ */
+public class TraversalQuery extends GraphTraversalBuilder {
+
+ /**
+ * Instantiates a new traversal query.
+ *
+ * @param loader the loader
+ */
+ public TraversalQuery(Loader loader, GraphTraversalSource source) {
+ super(loader, source);
+ this.factory = new TraversalStrategy(this.loader, this);
+ }
+
+ /**
+ * Instantiates a new traversal query.
+ *
+ * @param loader the loader
+ * @param start the start
+ */
+ public TraversalQuery(Loader loader, GraphTraversalSource source, Vertex start) {
+ super(loader, source, start);
+ this.factory = new TraversalStrategy(this.loader, this);
+ }
+
+ protected TraversalQuery(GraphTraversal<Vertex, Vertex> traversal, Loader loader, GraphTraversalSource source, GraphTraversalBuilder gtb) {
+ super(loader, source);
+ this.traversal = traversal;
+ this.stepIndex = gtb.getStepIndex();
+ this.parentStepIndex = gtb.getParentStepIndex();
+ this.containerStepIndex = gtb.getContainerStepIndex();
+ this.factory = new TraversalStrategy(this.loader, this);
+ this.start = gtb.getStart();
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException {
+ return factory.buildURIParser(uri);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser createQueryFromRelationship(Introspector relationship) throws UnsupportedEncodingException, AAIException {
+ return factory.buildRelationshipParser(relationship);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams)
+ throws UnsupportedEncodingException, AAIException {
+ return factory.buildURIParser(uri, queryParams);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryParser createQueryFromObjectName(String objName) {
+ return factory.buildObjectNameParser(objName);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder newInstance(Vertex start) {
+ return new TraversalQuery(loader, source, start);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public QueryBuilder newInstance() {
+ return new TraversalQuery(loader, source);
+ }
+
+ @Override
+ protected QueryBuilder cloneQueryAtStep(int index) {
+ if (index == 0) {
+ index = stepIndex;
+ }
+ GraphTraversal<Vertex, Vertex> clone = this.traversal.asAdmin().clone();
+ GraphTraversal.Admin<Vertex, Vertex> cloneAdmin = clone.asAdmin();
+ List<Step> steps = cloneAdmin.getSteps();
+
+ for (int i = steps.size()-1; i >= index; i--) {
+ cloneAdmin.removeStep(i);
+ }
+ return new TraversalQuery(cloneAdmin, loader, source, this);
+ }
+
+ @Override
+ protected QueryBuilder removeQueryStepsBetween(int start, int end) {
+ GraphTraversal<Vertex, Vertex> clone = this.traversal.asAdmin().clone();
+ GraphTraversal.Admin<Vertex, Vertex> cloneAdmin = clone.asAdmin();
+
+ for (int i = end-2; i >= start; i--) {
+ cloneAdmin.removeStep(i);
+ }
+ return new TraversalQuery(cloneAdmin, loader, source, this);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/CustomJacksonJaxBJsonProvider.java b/aai-core/src/main/java/org/openecomp/aai/restcore/CustomJacksonJaxBJsonProvider.java
new file mode 100644
index 00000000..b7360b1c
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/restcore/CustomJacksonJaxBJsonProvider.java
@@ -0,0 +1,71 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.restcore;
+
+import javax.ws.rs.ext.Provider;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
+import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
+
+/**
+ * The Class CustomJacksonJaxBJsonProvider.
+ */
+@Provider
+public class CustomJacksonJaxBJsonProvider extends JacksonJaxbJsonProvider {
+
+ private static ObjectMapper commonMapper = null;
+
+ /**
+ * Instantiates a new custom jackson jax B json provider.
+ */
+ public CustomJacksonJaxBJsonProvider() {
+ if (commonMapper == null) {
+ ObjectMapper mapper = new ObjectMapper();
+
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+
+ mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ mapper.configure(SerializationFeature.INDENT_OUTPUT, false);
+ mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
+
+ mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, false);
+
+ mapper.registerModule(new JaxbAnnotationModule());
+
+ commonMapper = mapper;
+ }
+ super.setMapper(commonMapper);
+ }
+
+ /**
+ * Gets the mapper.
+ *
+ * @return the mapper
+ */
+ public ObjectMapper getMapper() {
+ return commonMapper;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/HttpMethod.java b/aai-core/src/main/java/org/openecomp/aai/restcore/HttpMethod.java
new file mode 100644
index 00000000..0acaf35f
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/restcore/HttpMethod.java
@@ -0,0 +1,33 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.restcore;
+
+/**
+ * The Enum HttpMethod.
+ */
+public enum HttpMethod {
+ PUT,
+ MERGE_PATCH,
+ DELETE,
+ PUT_EDGE,
+ DELETE_EDGE,
+ GET;
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/JettyObfuscationConversionCommandLineUtil.java b/aai-core/src/main/java/org/openecomp/aai/restcore/JettyObfuscationConversionCommandLineUtil.java
new file mode 100644
index 00000000..8a81ee44
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/restcore/JettyObfuscationConversionCommandLineUtil.java
@@ -0,0 +1,97 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.restcore;
+
+import org.apache.commons.cli.BasicParser;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.eclipse.jetty.util.security.Password;
+
+/*
+ * The purpose of this class is to be a tool for
+ * manually applying jetty obfuscation/deobfuscation
+ * so that one can obfuscate the various passwords/secrets
+ * in aaiconfig.properties.
+ *
+ * Originally, they were being encrypted by a similar
+ * command line utility, however the encryption key
+ * was being hardcoded in the src package
+ * which is a security violation.
+ * Since this ultimately just moved the problem of how
+ * to hide secrets to a different secret in a different file,
+ * and since that encryption was really just being done to
+ * obfuscate those values in case someone needed to look at
+ * properties with others looking at their screen,
+ * we decided that jetty obfuscation would be adequate
+ * for that task as well as
+ * removing the "turtles all the way down" secret-to-hide-
+ * the-secret-to-hide-the-secret problem.
+ */
+public class JettyObfuscationConversionCommandLineUtil {
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args){
+ Options options = new Options();
+ options.addOption("e", true, "obfuscate the given string");
+ options.addOption("d", true, "deobfuscate the given string");
+
+ CommandLineParser parser = new BasicParser();
+
+ try {
+ CommandLine cmd = parser.parse(options, args);
+ String toProcess = null;
+
+ if (cmd.hasOption("e")){
+ toProcess = cmd.getOptionValue("e");
+ String encoded = Password.obfuscate(toProcess);
+ System.out.println(encoded);
+ } else if (cmd.hasOption("d")) {
+ toProcess = cmd.getOptionValue("d");
+ String decoded_str = Password.deobfuscate(toProcess);
+ System.out.println(decoded_str);
+ } else {
+ usage();
+ }
+ } catch (ParseException e) {
+ System.out.println("failed to parse input");
+ System.out.println(e.toString());
+ usage();
+ } catch (Exception e) {
+ System.out.println("exception:" + e.toString());
+ }
+ }
+
+ /**
+ * Usage.
+ */
+ private static void usage(){
+ System.out.println("usage:");;
+ System.out.println("-e [string] to obfuscate");
+ System.out.println("-d [string] to deobfuscate");
+ System.out.println("-h help");
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/MediaType.java b/aai-core/src/main/java/org/openecomp/aai/restcore/MediaType.java
new file mode 100644
index 00000000..73cb0f22
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/restcore/MediaType.java
@@ -0,0 +1,66 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.restcore;
+
+/**
+ * The Enum MediaType.
+ */
+public enum MediaType {
+ APPLICATION_JSON_TYPE("application/json"),
+ APPLICATION_XML_TYPE("application/xml");
+
+ private final String text;
+
+ /**
+ * Instantiates a new media type.
+ *
+ * @param text the text
+ */
+ private MediaType(final String text) {
+ this.text = text;
+ }
+
+ /**
+ * Gets the enum.
+ *
+ * @param value the value
+ * @return the enum
+ */
+ public static MediaType getEnum(String value) {
+
+ for(MediaType v : values()) {
+ if(v.toString().equalsIgnoreCase(value)) {
+ return v;
+ }
+ }
+
+ throw new IllegalArgumentException("bad value: " + value);
+
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return text;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/RESTAPI.java b/aai-core/src/main/java/org/openecomp/aai/restcore/RESTAPI.java
new file mode 100644
index 00000000..59d35ff2
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/restcore/RESTAPI.java
@@ -0,0 +1,343 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.restcore;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.base.Joiner;
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.dbmap.DBConnectionType;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.tools.*;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+import org.openecomp.aai.util.AAITxnLog;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * Base class for AAI REST API classes.
+ * Provides method to validate header information
+ * TODO should authenticate caller and authorize them for the API they are calling
+ * TODO should store the transaction
+
+ *
+ */
+public class RESTAPI {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(RESTAPI.class);
+
+ protected final String COMPONENT = "aairest";
+
+ /**
+ * The Enum Action.
+ */
+ public enum Action {
+ GET, PUT, POST, DELETE
+ };
+
+
+ public AAITxnLog txn = null;
+
+ /**
+ * Gets the from app id.
+ *
+ * @param headers the headers
+ * @param logline the logline
+ * @return the from app id
+ * @throws AAIException the AAI exception
+ */
+ protected String getFromAppId(HttpHeaders headers) throws AAIException {
+ String fromAppId = null;
+ if (headers != null) {
+ List<String> fromAppIdHeader = headers.getRequestHeader("X-FromAppId");
+ if (fromAppIdHeader != null) {
+ for (String fromAppIdValue : fromAppIdHeader) {
+ fromAppId = fromAppIdValue;
+ }
+ }
+ }
+
+ if (fromAppId == null) {
+ throw new AAIException("AAI_4009");
+ }
+
+ return fromAppId;
+ }
+
+ /**
+ * Gets the trans id.
+ *
+ * @param headers the headers
+ * @param logline the logline
+ * @return the trans id
+ * @throws AAIException the AAI exception
+ */
+ protected String getTransId(HttpHeaders headers) throws AAIException {
+ String transId = null;
+ if (headers != null) {
+ List<String> transIdHeader = headers.getRequestHeader("X-TransactionId");
+ if (transIdHeader != null) {
+ for (String transIdValue : transIdHeader) {
+ transId = transIdValue;
+ }
+ }
+ }
+
+ if (transId == null) {
+ throw new AAIException("AAI_4010");
+ }
+
+ return transId;
+ }
+
+
+ /**
+ * Gen date.
+ *
+ * @return the string
+ */
+ protected String genDate() {
+ Date date = new Date();
+ DateFormat formatter = null;
+ try {
+ formatter = new SimpleDateFormat(AAIConfig.get(AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT));
+ } catch (AAIException ex) {
+ ErrorLogHelper.logException(ex);
+ } finally {
+ if (formatter == null) {
+ formatter = new SimpleDateFormat("YYMMdd-HH:mm:ss:SSS");
+ }
+ }
+
+ return formatter.format(date);
+ }
+
+ /**
+ * Gets the media type.
+ *
+ * @param mediaTypeList the media type list
+ * @return the media type
+ */
+ protected String getMediaType(List <MediaType> mediaTypeList) {
+ String mediaType = MediaType.APPLICATION_JSON; // json is the default
+ for (MediaType mt : mediaTypeList) {
+ if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt)) {
+ mediaType = MediaType.APPLICATION_XML;
+ }
+ }
+ return mediaType;
+ }
+
+
+ /**
+ * Log transaction.
+ *
+ * @param appId the app id
+ * @param tId the t id
+ * @param action the action
+ * @param input the input
+ * @param rqstTm the rqst tm
+ * @param respTm the resp tm
+ * @param request the request
+ * @param response the response
+ */
+ /* ---------------- Log Transaction into HBase --------------------- */
+ public void logTransaction( String appId, String tId, String action,
+ String input, String rqstTm, String respTm, String request, Response response) {
+ String respBuf = "";
+ int status = 0;
+
+ if (response != null && response.getEntity() != null) {
+ respBuf = response.getEntity().toString();
+ status = response.getStatus();
+ }
+ logTransaction(appId, tId, action, input, rqstTm, respTm, request, respBuf, String.valueOf(status));
+ }
+
+ /**
+ * Log transaction.
+ *
+ * @param appId the app id
+ * @param tId the t id
+ * @param action the action
+ * @param input the input
+ * @param rqstTm the rqst tm
+ * @param respTm the resp tm
+ * @param request the request
+ * @param respBuf the resp buf
+ * @param status the status
+ * @param logline the logline
+ */
+ public void logTransaction( String appId, String tId, String action,
+ String input, String rqstTm, String respTm, String request, String respBuf, String status) {
+ try {
+ // we only run this way if we're not doing it in the CXF interceptor
+ if (!AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_INTERCEPTOR).equalsIgnoreCase("true")) {
+ if (AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_ENABLED).equalsIgnoreCase("true")) {
+ txn = new AAITxnLog(tId, appId);
+ // tid, status, rqstTm, respTm, srcId, rsrcId, rsrcType, rqstBuf, respBuf
+ String hbtid = txn.put(tId, status,
+ rqstTm, respTm, appId, input, action, request, respBuf);
+
+ LOGGER.debug("HbTransId={}",hbtid);
+ LOGGER.debug("action={}", action);
+ LOGGER.debug("urlin={}", input);
+ }
+
+ }
+ } catch (AAIException e) {
+ // i think we do nothing
+ }
+ }
+
+ /* ----------helpers for common consumer actions ----------- */
+
+ /**
+ * Sets the depth.
+ *
+ * @param depthParam the depth param
+ * @return the int
+ * @throws AAIException the AAI exception
+ */
+ protected int setDepth(String depthParam) throws AAIException {
+ int depth = AAIProperties.MAXIMUM_DEPTH; //default
+ if (depthParam != null && depthParam.length() > 0 && !depthParam.equals("all")){
+ try {
+ depth = Integer.valueOf(depthParam);
+ } catch (Exception e) {
+ throw new AAIException("AAI_4016");
+ }
+ }
+ return depth;
+ }
+
+ /**
+ * Consumer exception response generator.
+ *
+ * @param headers the headers
+ * @param info the info
+ * @param templateAction the template action
+ * @param e the e
+ * @return the response
+ */
+ protected Response consumerExceptionResponseGenerator(HttpHeaders headers, UriInfo info, HttpMethod templateAction, AAIException e) {
+ ArrayList<String> templateVars = new ArrayList<String>();
+ templateVars.add(templateAction.toString()); //GET, PUT, etc
+ templateVars.add(info.getPath().toString());
+ templateVars.addAll(e.getTemplateVars());
+
+ return Response
+ .status(e.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponseWithLogging(headers.getAcceptableMediaTypes(), e, templateVars))
+ .build();
+ }
+
+ /**
+ * Validate introspector.
+ *
+ * @param obj the obj
+ * @param loader the loader
+ * @param uri the uri
+ * @param validateRequired the validate required
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ protected void validateIntrospector(Introspector obj, Loader loader, URI uri, HttpMethod method) throws AAIException, UnsupportedEncodingException {
+
+ int maximumDepth = AAIProperties.MAXIMUM_DEPTH;
+ boolean validateRequired = true;
+ if (method.equals(HttpMethod.MERGE_PATCH)) {
+ validateRequired = false;
+ maximumDepth = 0;
+ }
+ IntrospectorValidator validator = new IntrospectorValidator.Builder()
+ .validateRequired(validateRequired)
+ .restrictDepth(maximumDepth)
+ .addResolver(new RemoveNonVisibleProperty())
+ .addResolver(new CreateUUID())
+ .addResolver(new DefaultFields())
+ .addResolver(new InjectKeysFromURI(loader, uri))
+ .build();
+ boolean result = validator.validate(obj);
+ if (!result) {
+ result = validator.resolveIssues();
+ }
+ if (!result) {
+ List<String> messages = new ArrayList<>();
+ for (Issue issue : validator.getIssues()) {
+ if (!issue.isResolved()) {
+ messages.add(issue.getDetail());
+ }
+ }
+ String errors = Joiner.on(",").join(messages);
+ throw new AAIException("AAI_3000", errors);
+ }
+ //check that key in payload and key in request uri are the same
+ String objURI = obj.getURI();
+ //if requested object is a parent objURI will have a leading slash the input uri will lack
+ //this adds that leading slash for the comparison
+ String testURI = "/" + uri.getRawPath();
+ if (!testURI.endsWith(objURI)) {
+ throw new AAIException("AAI_3000", "uri and payload keys don't match");
+ }
+ }
+
+ protected DBConnectionType determineConnectionType(String fromAppId, String realTime) {
+ DBConnectionType type = DBConnectionType.REALTIME;
+ boolean isRealTimeClient = AAIConfig.get("aai.realtime.clients", "").contains(fromAppId);
+ if (isRealTimeClient || realTime != null) {
+ type = DBConnectionType.REALTIME;
+ } else {
+ type = DBConnectionType.CACHED;
+ }
+
+ return type;
+ }
+
+ /**
+ * Gets the input media type.
+ *
+ * @param mediaType the media type
+ * @return the input media type
+ */
+ protected String getInputMediaType(MediaType mediaType) {
+ String result = mediaType.getType() + "/" + mediaType.getSubtype();
+
+ return result;
+
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/search/GremlinGroovyShellSingleton.java b/aai-core/src/main/java/org/openecomp/aai/restcore/search/GremlinGroovyShellSingleton.java
new file mode 100644
index 00000000..b80884b7
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/restcore/search/GremlinGroovyShellSingleton.java
@@ -0,0 +1,88 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.restcore.search;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer;
+import org.codehaus.groovy.control.customizers.ImportCustomizer;
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyShell;
+import groovy.lang.Script;
+import groovy.transform.TimedInterrupt;
+
+/**
+ * Creates and returns a groovy shell with the
+ * configuration to statically import graph classes
+ *
+ */
+public class GremlinGroovyShellSingleton {
+
+ private final GroovyShell shell;
+ private GremlinGroovyShellSingleton() {
+ Map<String, Object> parameters = new HashMap<>();
+ parameters.put("value", 30000);
+ parameters.put("unit", new PropertyExpression(new ClassExpression(ClassHelper.make(TimeUnit.class)),"MILLISECONDS"));
+
+ ASTTransformationCustomizer custom = new ASTTransformationCustomizer(parameters, TimedInterrupt.class);
+ ImportCustomizer imports = new ImportCustomizer();
+ imports.addStaticStars(
+ "org.apache.tinkerpop.gremlin.process.traversal.P"
+ );
+ imports.addImports(
+ "org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__",
+ "org.apache.tinkerpop.gremlin.structure.T",
+ "org.apache.tinkerpop.gremlin.process.traversal.P");
+ CompilerConfiguration config = new CompilerConfiguration();
+ config.addCompilationCustomizers(custom, imports);
+
+ this.shell = new GroovyShell(config);
+ }
+
+ private static class Helper {
+ private static final GremlinGroovyShellSingleton INSTANCE = new GremlinGroovyShellSingleton();
+ }
+
+ public static GremlinGroovyShellSingleton getInstance() {
+
+ return Helper.INSTANCE;
+ }
+
+ /**
+ * @param traversal
+ * @param params
+ * @return result of graph traversal
+ */
+ public GraphTraversal<?, ?> executeTraversal (String traversal, Map<String, Object> params) {
+ Binding binding = new Binding(params);
+ Script script = shell.parse(traversal);
+ script.setBinding(binding);
+ return (GraphTraversal<?, ?>) script.run();
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/util/GenerateEdgeRules.java b/aai-core/src/main/java/org/openecomp/aai/restcore/util/GenerateEdgeRules.java
new file mode 100644
index 00000000..3bbe7dec
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/restcore/util/GenerateEdgeRules.java
@@ -0,0 +1,154 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.restcore.util;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
+
+import java.io.*;
+import java.util.*;
+
+public class GenerateEdgeRules {
+
+ private static final EELFLogger LOG = EELFManager.getInstance().getLogger(GenerateEdgeRules.class);
+
+ public static void main(String[] args) throws IOException, TemplateException {
+
+ String filename = "/AAI8032.csv";
+ InputStream inputStream = GenerateEdgeRules.class.getResourceAsStream(filename);
+ Map<String, Integer> headers = new HashMap<>();
+ Map<String, Object> edgeRulesMap = new TreeMap<String, Object>();
+ List<Map<String, String>> edgeRules = new ArrayList<>();
+
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
+
+ String line = null;
+
+ int rowNum = 0;
+
+ // Retrieve the header line to map the indexes to their column names
+
+ while ((line = reader.readLine()) != null) {
+
+ if (rowNum == 0) {
+ headers = retrieveHeaderMap(line);
+ } else {
+ String[] columns = line.split(",");
+
+ String originalNode = columns[headers.get("Orig NodeA|NodeB")];
+ String finalNode = columns[headers.get("Final NodeA|NodeB")];
+ String originalEdge = columns[headers.get("Orig EdgeLabel")];
+ String finalEdge = columns[headers.get("Final EdgeLabel")];
+
+ String lineage = columns[headers.get("Final Lineage")];
+ String originalParent = columns[headers.get("Orig ParentOf")];
+ String usesResource = columns[headers.get("Revised UsesResource")];
+ String hasDelTarget = columns[headers.get("Revised hasDelTarget")];
+ String svcInfra = columns[headers.get("Final SVC-INFRA")];
+ String svcInfraRev = "";
+
+ if(usesResource.equals("T"))
+ usesResource = "true";
+ else if(usesResource.equals("F"))
+ usesResource = "false";
+
+ if (hasDelTarget.equals("T") || hasDelTarget.equals("AB")) {
+ hasDelTarget = "true";
+ } else if (hasDelTarget.equals("F")) {
+ hasDelTarget = "false";
+ }
+
+ if (svcInfra.equals("T")) {
+ svcInfra = "true";
+ } else if (svcInfra.equals("F")) {
+ svcInfra = "false";
+ } else if (svcInfra.equals("R")) {
+ svcInfra = "reverse";
+ }
+
+ if (originalParent.equals("T")) {
+ if (lineage.trim().equalsIgnoreCase("CHILD")) {
+ lineage = "true";
+ } else if (lineage.trim().equalsIgnoreCase("PARENT")) {
+ lineage = "reverse";
+ }
+ } else {
+ lineage = "false";
+ }
+
+ Map<String, String> edgeMap = new HashMap<String, String>();
+
+ edgeMap.put("lineage", lineage);
+ edgeMap.put("usesResource", usesResource);
+ edgeMap.put("hasDelTarget", hasDelTarget);
+ edgeMap.put("SVC-INFRA", svcInfra);
+ edgeMap.put("SVC-INFRA-REV", svcInfraRev);
+ edgeMap.put("nodes", finalNode);
+ edgeMap.put("edge", finalEdge);
+ edgeMap.put("direction", columns[headers.get("Orig Direction")]);
+ edgeMap.put("multiplicity", columns[headers.get("Revised Multiplicity")]);
+
+ edgeRules.add(edgeMap);
+
+ }
+ ++rowNum;
+ }
+ } catch(Exception ex){
+ ex.printStackTrace();
+ }
+
+ edgeRulesMap.put("edgeRules", edgeRules);
+
+ Collections.sort(edgeRules, new Comparator<Map<String, String>>() {
+ @Override
+ public int compare(Map<String, String> o1, Map<String, String> o2) {
+ return o1.get("nodes").compareTo(o2.get("nodes"));
+ }
+ });
+
+ Configuration configuration = new Configuration();
+ Template template = configuration.getTemplate("ajsc-aai/src/main/resources/EdgeRules.ftl");
+ Writer file = new FileWriter(new File("ajsc-aai/src/main/resources" + "/" + "EdgeRules.txt"));
+ template.process(edgeRulesMap, file);
+ }
+
+ private static Map<String, Integer> retrieveHeaderMap(String line){
+
+ if(line == null)
+ throw new NullPointerException();
+
+ String[] columnNames = line.split(",");
+
+ Map<String, Integer> map = new HashMap<String, Integer>();
+
+ int index = 0;
+
+ for(String columnName : columnNames){
+ map.put(columnName, index++);
+ }
+
+ return map;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/restcore/util/URITools.java b/aai-core/src/main/java/org/openecomp/aai/restcore/util/URITools.java
new file mode 100644
index 00000000..2683240a
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/restcore/util/URITools.java
@@ -0,0 +1,113 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.restcore.util;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.springframework.web.util.UriUtils;
+
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.sideeffect.exceptions.AAIMissingRequiredPropertyException;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+
+public class URITools {
+
+ protected static final Pattern template = Pattern.compile("\\{(.*?)\\}");
+
+ public static MultivaluedMap<String, String> getQueryMap(URI uri) {
+ MultivaluedMap<String, String> result = new MultivaluedHashMap<>();
+ String queryParams = uri.getRawQuery();
+ if (queryParams != null) {
+ try {
+ String[] sections = queryParams.split("&");
+ String[] query = null;
+ String key, value = "";
+ for (String section : sections) {
+ query = section.split("=");
+ key = UriUtils.decode(query[0], "UTF-8");
+ value = UriUtils.decode(query[1], "UTF-8");
+ if (result.containsKey(key)) {
+ result.add(key, value);
+ } else {
+ result.putSingle(key, value);
+ }
+ }
+ } catch (UnsupportedEncodingException e ) {
+
+ }
+ }
+ return result;
+
+ }
+
+ public static Optional<String> replaceTemplates(Introspector obj, String uriString, PropertyMetadata metadata, boolean replaceWithWildcard) throws AAIMissingRequiredPropertyException {
+ String result = uriString;
+ final Map<String, String> propMap = URITools.findProperties(obj, uriString, metadata, replaceWithWildcard);
+ if (propMap.isEmpty()) {
+ return Optional.empty();
+ }
+ for (Entry<String, String> entry : propMap.entrySet()) {
+ result = result.replaceAll("\\{" + entry.getKey() + "\\}", entry.getValue());
+ }
+ //drop out wildcards if they exist
+ result = result.replaceFirst("/[^/]+?(?:/\\*)+", "");
+ return Optional.of(result);
+ }
+
+ private static Map<String, String> findProperties(Introspector obj, String uriString, PropertyMetadata metadata, boolean replaceWithWildcard) throws AAIMissingRequiredPropertyException {
+
+ final Map<String, String> result = new HashMap<>();
+ final Set<String> missing = new LinkedHashSet<>();
+ Matcher m = template.matcher(uriString);
+ int properties = 0;
+ while (m.find()) {
+ String propName = m.group(1);
+ String value = obj.getValue(propName);
+ properties++;
+ if (value != null) {
+ result.put(propName, value);
+ } else {
+ if (replaceWithWildcard) {
+ result.put(propName, "*");
+ }
+ missing.add(propName);
+ }
+ }
+
+ if (!missing.isEmpty() && (properties != missing.size())) {
+ throw new AAIMissingRequiredPropertyException("Cannot complete " + metadata.toString() + " uri. Missing properties " + missing);
+ }
+ return result;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/DBSerializer.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/DBSerializer.java
new file mode 100644
index 00000000..fb3300e3
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/DBSerializer.java
@@ -0,0 +1,1484 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.db;
+
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.base.CaseFormat;
+import com.thinkaurelius.titan.core.SchemaViolationException;
+import org.apache.commons.collections.IteratorUtils;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
+import org.apache.tinkerpop.gremlin.structure.*;
+import org.javatuples.Pair;
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.*;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.introspection.sideeffect.DataCopy;
+import org.openecomp.aai.introspection.sideeffect.DataLinkReader;
+import org.openecomp.aai.introspection.sideeffect.DataLinkWriter;
+import org.openecomp.aai.introspection.sideeffect.SideEffectRunner;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.parsers.query.QueryParser;
+import org.openecomp.aai.parsers.uri.URIParser;
+import org.openecomp.aai.parsers.uri.URIToRelationshipObject;
+import org.openecomp.aai.query.builder.QueryBuilder;
+import org.openecomp.aai.schema.enums.ObjectMetadata;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+import org.openecomp.aai.serialization.tinkerpop.TreeBackedVertex;
+import org.openecomp.aai.util.AAIApiServerURLBase;
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+import org.openecomp.aai.workarounds.NamingExceptions;
+
+import javax.ws.rs.core.UriBuilder;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+public class DBSerializer {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class);
+
+ private final TransactionalGraphEngine engine;
+ private final String sourceOfTruth;
+ private final ModelType introspectionType;
+ private final Version version;
+ private final Loader latestLoader;
+ private final EdgeRules edgeRules = EdgeRules.getInstance();
+ private final Loader loader;
+ private final String baseURL;
+ /**
+ * Instantiates a new DB serializer.
+ *
+ * @param version the version
+ * @param engine the engine
+ * @param g the g
+ * @param introspectionType the introspection type
+ * @param sourceOfTruth the source of truth
+ * @param llBuilder the ll builder
+ * @throws AAIException
+ */
+ public DBSerializer(Version version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException {
+ this.engine = engine;
+ this.sourceOfTruth = sourceOfTruth;
+ this.introspectionType = introspectionType;
+ this.latestLoader = LoaderFactory.createLoaderForVersion(introspectionType, AAIProperties.LATEST);
+ this.version = version;
+ this.loader = LoaderFactory.createLoaderForVersion(introspectionType, version);
+ this.baseURL = AAIApiServerURLBase.get(version);
+ }
+
+ /**
+ * Touch standard vertex properties.
+ *
+ * @param v the v
+ * @param isNewVertex the is new vertex
+ */
+ /*
+ * to be defined and expanded later
+ */
+ public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) {
+
+ long unixTimeNow = System.currentTimeMillis();
+ String timeNowInSec = "" + unixTimeNow;
+ if (isNewVertex) {
+ v.property(AAIProperties.SOURCE_OF_TRUTH, this.sourceOfTruth);
+ v.property(AAIProperties.CREATED_TS, timeNowInSec);
+ }
+ v.property(AAIProperties.RESOURCE_VERSION, timeNowInSec );
+ v.property(AAIProperties.LAST_MOD_TS, timeNowInSec);
+ v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth);
+
+ }
+
+
+
+ /**
+ * Creates the new vertex.
+ *
+ * @param wrappedObject the wrapped object
+ * @return the vertex
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public Vertex createNewVertex(Introspector wrappedObject) {
+
+
+ Vertex v = this.engine.tx().addVertex();
+ v.property(AAIProperties.NODE_TYPE, wrappedObject.getDbName());
+ touchStandardVertexProperties(v, true);
+
+ return v;
+ }
+
+ /**
+ * Trim class name.
+ *
+ * @param className the class name
+ * @return the string
+ */
+ /*
+ * Removes the classpath from a class name
+ */
+ public String trimClassName (String className) {
+ String returnValue = "";
+
+ if (className.lastIndexOf('.') == -1) {
+ return className;
+ }
+ returnValue = className.substring(className.lastIndexOf('.') + 1, className.length());
+
+ return returnValue;
+ }
+
+ /**
+ * Serialize to db.
+ *
+ * @param obj the obj
+ * @param v the v
+ * @param uriQuery the uri query
+ * @param identifier the identifier
+ * @throws SecurityException the security exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws InstantiationException the instantiation exception
+ * @throws InterruptedException the interrupted exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ public void serializeToDb(Introspector obj, Vertex v, QueryParser uriQuery, String identifier, String requestContext) throws AAIException, UnsupportedEncodingException {
+
+ try {
+ if (uriQuery.isDependent()) {
+ //try to find the parent
+ List<Vertex> vertices = uriQuery.getQueryBuilder().getParentQuery().toList();
+ if (!vertices.isEmpty()) {
+ Vertex parent = vertices.get(0);
+ this.reflectDependentVertex(parent, v, obj, requestContext);
+ } else {
+ throw new AAIException("AAI_6114", "No parent Node of type " + uriQuery.getParentResultType() + " for " + identifier);
+ }
+ } else {
+ serializeSingleVertex(v, obj, requestContext);
+ }
+
+ } catch (SchemaViolationException e) {
+ throw new AAIException("AAI_6117", e);
+ }
+
+ }
+
+ public void serializeSingleVertex(Vertex v, Introspector obj, String requestContext) throws UnsupportedEncodingException, AAIException {
+ try {
+ boolean isTopLevel = obj.isTopLevel();
+ if (isTopLevel) {
+ v.property(AAIProperties.AAI_URI, obj.getURI());
+ }
+ processObject(obj, v, requestContext);
+ if (!isTopLevel) {
+ URI uri = this.getURIForVertex(v);
+ URIParser parser = new URIParser(this.loader, uri);
+ if (parser.validate()) {
+ VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI);
+ if (!uriProp.isPresent() || uriProp.isPresent() && !uriProp.value().equals(uri.toString())) {
+ v.property(AAIProperties.AAI_URI, uri.toString());
+ }
+ }
+ }
+ } catch (SchemaViolationException e) {
+ throw new AAIException("AAI_6117", e);
+ }
+ }
+
+ /**
+ * Process object.
+ *
+ * @param <T> the generic type
+ * @param obj the obj
+ * @param v the v
+ * @return the list
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ /*
+ * Helper method for reflectToDb
+ * Handles all the property setting
+ */
+ private <T> List<Vertex> processObject (Introspector obj, Vertex v, String requestContext) throws UnsupportedEncodingException, AAIException {
+ Set<String> properties = new LinkedHashSet<>(obj.getProperties());
+ properties.remove(AAIProperties.RESOURCE_VERSION);
+ List<Vertex> dependentVertexes = new ArrayList<>();
+ List<Vertex> processedVertexes = new ArrayList<>();
+ boolean isComplexType = false;
+ boolean isListType = false;
+ this.executePreSideEffects(obj, v);
+ for (String property : properties) {
+ Object value = null;
+ final String propertyType;
+ propertyType = obj.getType(property);
+ isComplexType = obj.isComplexType(property);
+ isListType = obj.isListType(property);
+ value = obj.getValue(property);
+
+ if (!(isComplexType || isListType)) {
+ boolean canModify = this.canModify(obj, property, requestContext);
+
+ if (canModify) {
+ final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
+ String dbProperty = property;
+ if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
+ dbProperty = metadata.get(PropertyMetadata.DB_ALIAS);
+ }
+ if (metadata.containsKey(PropertyMetadata.DATA_LINK)) {
+ //data linked properties are ephemeral
+ //they are populated dynamically on GETs
+ continue;
+ }
+ if (value != null) {
+ if (propertyType.toLowerCase().contains(".long")) {
+ v.property(dbProperty, new Integer(((Long)value).toString()));
+ } else {
+ v.property(dbProperty, value);
+ }
+ } else {
+ v.property(dbProperty).remove();
+ }
+ }
+ } else if (isListType) {
+ List<Object> list = (List<Object>)value;
+ if (obj.isComplexGenericType(property)) {
+ if (list != null) {
+ for (Object o : list) {
+ Introspector child = IntrospectorFactory.newInstance(this.introspectionType, o);
+ child.setURIChain(obj.getURI());
+ processedVertexes.add(reflectDependentVertex(v, child, requestContext));
+ }
+ }
+ } else {
+ //simple list case
+ engine.setListProperty(v, property, list);
+ }
+ } else {
+ //method.getReturnType() is not 'simple' then create a vertex and edge recursively returning an edge back to this method
+ if (value != null) { //effectively ignore complex properties not included in the object we're processing
+ if (value.getClass().isArray()) {
+
+ int length = Array.getLength(value);
+ for (int i = 0; i < length; i ++) {
+ Object arrayElement = Array.get(value, i);
+ Introspector child = IntrospectorFactory.newInstance(this.introspectionType, arrayElement);
+ child.setURIChain(obj.getURI());
+ processedVertexes.add(reflectDependentVertex(v, child, requestContext));
+
+ }
+ } else if (!property.equals("relationship-list")) {
+ // container case
+ Introspector introspector = IntrospectorFactory.newInstance(this.introspectionType, value);
+ if (introspector.isContainer()) {
+ dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getChildDBName()));
+ introspector.setURIChain(obj.getURI());
+
+ processedVertexes.addAll(processObject(introspector, v, requestContext));
+
+ } else {
+ dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getDbName()));
+ processedVertexes.add(reflectDependentVertex(v, introspector, requestContext));
+
+ }
+ } else if (property.equals("relationship-list")) {
+ handleRelationships(obj, v);
+ }
+ }
+ }
+ }
+ this.writeThroughDefaults(v, obj);
+ /* handle those vertexes not touched */
+ for (Vertex toBeRemoved : processedVertexes) {
+ dependentVertexes.remove(toBeRemoved);
+ }
+ this.deleteItemsWithTraversal(dependentVertexes);
+
+ this.executePostSideEffects(obj, v);
+ return processedVertexes;
+ }
+
+ /**
+ * Handle relationships.
+ *
+ * @param obj the obj
+ * @param vertex the vertex
+ * @throws SecurityException the security exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ /*
+ * Handles the explicit relationships defined for an obj
+ */
+ private void handleRelationships(Introspector obj, Vertex vertex) throws UnsupportedEncodingException, AAIException {
+
+
+
+ Introspector wrappedRl = obj.getWrappedValue("relationship-list");
+ processRelationshipList(wrappedRl, vertex);
+
+
+ }
+
+
+ /**
+ * Process relationship list.
+ *
+ * @param wrapped the wrapped
+ * @param v the v
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ private void processRelationshipList(Introspector wrapped, Vertex v) throws UnsupportedEncodingException, AAIException {
+
+ List<Object> relationships = (List<Object>)wrapped.getValue("relationship");
+
+ List<Pair<Vertex, Vertex>> addEdges = new ArrayList<>();
+ List<Edge> existingEdges = this.engine.getQueryEngine().findEdgesForVersion(v, wrapped.getLoader());
+
+ for (Object relationship : relationships) {
+ Edge e = null;
+ Vertex cousinVertex = null;
+ Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship);
+ QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel);
+
+ List<Vertex> results = parser.getQueryBuilder().toList();
+ if (results.isEmpty()) {
+ final AAIException ex = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
+ ex.getTemplateVars().add(parser.getResultType());
+ ex.getTemplateVars().add(parser.getUri().toString());
+ throw ex;
+ } else {
+ //still an issue if there's more than one
+ cousinVertex = results.get(0);
+ }
+
+ if (cousinVertex != null) {
+ try {
+ e = this.getEdgeBetween(EdgeType.COUSIN, v, cousinVertex);
+
+ if (e == null) {
+ addEdges.add(new Pair<>(v, cousinVertex));
+ } else {
+ existingEdges.remove(e);
+ }
+ } catch (NoEdgeRuleFoundException e1) {
+ throw new AAIException("AAI_6145");
+ }
+ }
+ }
+
+ for (Edge edge : existingEdges) {
+ edge.remove();
+ }
+ for (Pair<Vertex, Vertex> pair : addEdges) {
+ try {
+ edgeRules.addEdge(this.engine.asAdmin().getTraversalSource(), pair.getValue0(), pair.getValue1());
+ } catch (NoEdgeRuleFoundException e) {
+ throw new AAIException("AAI_6129", e);
+ }
+ }
+
+ }
+
+ /**
+ * Write through defaults.
+ *
+ * @param v the v
+ * @param obj the obj
+ * @throws AAIUnknownObjectException
+ */
+ private void writeThroughDefaults(Vertex v, Introspector obj) throws AAIUnknownObjectException {
+ Introspector latest = this.latestLoader.introspectorFromName(obj.getName());
+ if (latest != null) {
+ Set<String> required = latest.getRequiredProperties();
+
+ for (String field : required) {
+ String defaultValue = null;
+ Object vertexProp = null;
+ defaultValue = latest.getPropertyMetadata(field).get(PropertyMetadata.DEFAULT_VALUE);
+ if (defaultValue != null) {
+ vertexProp = v.<Object>property(field).orElse(null);
+ if (vertexProp == null) {
+ v.property(field, defaultValue);
+ }
+ }
+ }
+ }
+
+ }
+
+
+ /**
+ * Reflect dependent vertex.
+ *
+ * @param v the v
+ * @param dependentObj the dependent obj
+ * @return the vertex
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ private Vertex reflectDependentVertex(Vertex v, Introspector dependentObj, String requestContext) throws AAIException, UnsupportedEncodingException {
+
+ //QueryParser p = this.engine.getQueryBuilder().createQueryFromURI(obj.getURI());
+ //List<Vertex> items = p.getQuery().toList();
+ QueryBuilder query = this.engine.getQueryBuilder(v);
+ query.createEdgeTraversal(EdgeType.TREE, v, dependentObj);
+ query.createKeyQuery(dependentObj);
+
+ List<Vertex> items = query.toList();
+
+ Vertex dependentVertex = null;
+ if (items.size() == 1) {
+ dependentVertex = items.get(0);
+ this.verifyResourceVersion("update", dependentObj.getDbName(), dependentVertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI());
+ } else {
+ this.verifyResourceVersion("create", dependentObj.getDbName(), "", (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI());
+ dependentVertex = createNewVertex(dependentObj);
+ }
+
+ return reflectDependentVertex(v, dependentVertex, dependentObj, requestContext);
+
+ }
+
+ /**
+ * Reflect dependent vertex.
+ *
+ * @param parent the parent
+ * @param child the child
+ * @param obj the obj
+ * @return the vertex
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ private Vertex reflectDependentVertex(Vertex parent, Vertex child, Introspector obj, String requestContext) throws AAIException, UnsupportedEncodingException {
+
+ String parentUri = parent.<String>property(AAIProperties.AAI_URI).orElse(null);
+ if (parentUri != null) {
+ child.property(AAIProperties.AAI_URI, parentUri + obj.getURI());
+ }
+ processObject(obj, child, requestContext);
+
+ Edge e;
+ e = this.getEdgeBetween(EdgeType.TREE, parent, child);
+ if (e == null) {
+ String canBeLinked = obj.getMetadata(ObjectMetadata.CAN_BE_LINKED);
+ if (canBeLinked != null && canBeLinked.equals("true")) {
+ boolean isFirst = !this.engine.getQueryBuilder(parent).createEdgeTraversal(EdgeType.TREE, parent, obj).hasNext();
+ if (isFirst) {
+ child.property(AAIProperties.LINKED, true);
+ }
+ }
+ edgeRules.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child);
+ }
+ return child;
+
+ }
+
+ /**
+ * Db to object.
+ *
+ * @param vertices the vertices
+ * @param obj the obj
+ * @param depth the depth
+ * @param cleanUp the clean up
+ * @return the introspector
+ * @throws AAIException the AAI exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws SecurityException the security exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws AAIUnknownObjectException
+ * @throws URISyntaxException
+ */
+ public Introspector dbToObject(List<Vertex> vertices, final Introspector obj, int depth, boolean nodeOnly, String cleanUp) throws UnsupportedEncodingException, AAIException {
+
+ final int internalDepth;
+ if (depth == Integer.MAX_VALUE) {
+ internalDepth = depth--;
+ } else {
+ internalDepth = depth;
+ }
+ if (vertices.size() > 1 && !obj.isContainer()) {
+ throw new AAIException("AAI_6136", "query object mismatch: this object cannot hold multiple items." + obj.getDbName());
+ } else if (obj.isContainer()) {
+ final List getList;
+ String listProperty = null;
+ for (String property : obj.getProperties()) {
+ if (obj.isListType(property) && obj.isComplexGenericType(property)) {
+ listProperty = property;
+ break;
+ }
+ }
+ final String propertyName = listProperty;
+ getList = (List)obj.getValue(listProperty);
+
+ /* This is an experimental multithreading experiment
+ * on get alls.
+ */
+ ExecutorService pool = GetAllPool.getInstance().getPool();
+
+ List<Future<Object>> futures = new ArrayList<>();
+ for (Vertex v : vertices) {
+ Callable<Object> task = () -> {
+ Set<Vertex> seen = new HashSet<>();
+ Introspector childObject = obj.newIntrospectorInstanceOfNestedProperty(propertyName);
+ Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, internalDepth, nodeOnly);
+ TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
+ dbToObject(childObject, treeVertex, seen, internalDepth, nodeOnly, cleanUp);
+ return childObject.getUnderlyingObject();
+ //getList.add(childObject.getUnderlyingObject());
+ };
+ futures.add(pool.submit(task));
+ }
+
+ for (Future<Object> future : futures) {
+ try {
+ getList.add(future.get());
+ } catch (ExecutionException e) {
+ throw new AAIException("AAI_4000", e);
+ } catch (InterruptedException e) {
+ throw new AAIException("AAI_4000", e);
+ }
+ }
+ } else if (vertices.size() == 1) {
+ Set<Vertex> seen = new HashSet<>();
+ Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(vertices.get(0), depth, nodeOnly);
+ TreeBackedVertex treeVertex = new TreeBackedVertex(vertices.get(0), tree);
+ dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
+ } else {
+ //obj = null;
+ }
+
+
+ return obj;
+ }
+
+ /**
+ * Db to object.
+ *
+ * @param obj the obj
+ * @param v the v
+ * @param seen the seen
+ * @param depth the depth
+ * @param cleanUp the clean up
+ * @return the introspector
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws SecurityException the security exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws AAIUnknownObjectException
+ * @throws URISyntaxException
+ */
+ private Introspector dbToObject(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, String cleanUp) throws AAIException, UnsupportedEncodingException {
+
+ if (depth < 0) {
+ return null;
+ }
+ depth--;
+ seen.add(v);
+
+ boolean modified = false;
+ for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
+ List<Object> getList = null;
+ Vertex[] vertices = null;
+
+ if (!(obj.isComplexType(property) || obj.isListType(property))) {
+ this.copySimpleProperty(property, obj, v);
+ modified = true;
+ } else {
+ if (obj.isComplexType(property)) {
+ /* container case */
+
+ if (!property.equals("relationship-list") && depth >= 0) {
+ Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
+ Object result = dbToObject(argumentObject, v, seen, depth+1, nodeOnly, cleanUp);
+ if (result != null) {
+ obj.setValue(property, argumentObject.getUnderlyingObject());
+ modified = true;
+ }
+ } else if (property.equals("relationship-list") && !nodeOnly){
+ /* relationships need to be handled correctly */
+ Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
+ relationshipList = createRelationshipList(v, relationshipList, cleanUp);
+ if (relationshipList != null) {
+ modified = true;
+ obj.setValue(property, relationshipList.getUnderlyingObject());
+ modified = true;
+ }
+
+ }
+ } else if (obj.isListType(property)) {
+
+ if (property.equals("any")) {
+ continue;
+ }
+ String genericType = obj.getGenericTypeClass(property).getSimpleName();
+ if (obj.isComplexGenericType(property) && depth >= 0) {
+ final String childDbName = convertFromCamelCase(genericType);
+ String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ EdgeRule rule;
+
+ rule = edgeRules.getEdgeRule(EdgeType.TREE, vType, childDbName);
+ if (rule.getIsParent().equals("true") || rule.getIsParent().equals("reverse")) {
+ //vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), childDbName);
+ Direction ruleDirection = rule.getDirection();
+ Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
+ List<Vertex> verticesList = (List<Vertex>) IteratorUtils.toList(itr);
+ itr = verticesList.stream().filter(item -> {
+ return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
+ }).iterator();
+ if (itr.hasNext()) {
+ getList = (List<Object>)obj.getValue(property);
+ }
+ int processed = 0;
+ int removed = 0;
+ while (itr.hasNext()) {
+ Vertex childVertex = itr.next();
+ if (!seen.contains(childVertex)) {
+ Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
+
+ Object result = dbToObject(argumentObject, childVertex, seen, depth, nodeOnly, cleanUp);
+ if (result != null) {
+ getList.add(argumentObject.getUnderlyingObject());
+ }
+
+ processed++;
+ } else {
+ removed++;
+ LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString());
+ }
+ }
+ if (processed == 0) {
+ //vertices were all seen, reset the list
+ getList = null;
+ }
+ if (processed > 0) {
+ modified = true;
+ }
+ }
+ } else if (obj.isSimpleGenericType(property)) {
+ List<Object> temp = this.engine.getListProperty(v, property);
+ if (temp != null) {
+ getList = (List<Object>)obj.getValue(property);
+ getList.addAll(temp);
+ modified = true;
+ }
+
+ }
+
+ }
+
+ }
+ }
+
+ //no changes were made to this obj, discard the instance
+ if (!modified) {
+ return null;
+ }
+ this.enrichData(obj, v);
+ return obj;
+
+ }
+
+
+ public Introspector getVertexProperties(Vertex v) throws AAIException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIUnknownObjectException, URISyntaxException {
+ String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if (nodeType == null) {
+ throw new AAIException("AAI_6143");
+ }
+ Introspector obj = this.latestLoader.introspectorFromName(nodeType);
+ Set<Vertex> seen = new HashSet<>();
+ int depth = 0;
+ String cleanUp = "false";
+ boolean nodeOnly = true;
+ this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp);
+
+ return obj;
+
+ }
+ public Introspector getLatestVersionView(Vertex v) throws AAIException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIUnknownObjectException, URISyntaxException {
+ String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if (nodeType == null) {
+ throw new AAIException("AAI_6143");
+ }
+ Introspector obj = this.latestLoader.introspectorFromName(nodeType);
+ Set<Vertex> seen = new HashSet<>();
+ int depth = AAIProperties.MAXIMUM_DEPTH;
+ String cleanUp = "false";
+ boolean nodeOnly = false;
+ Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, depth, nodeOnly);
+ TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
+ this.dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
+
+ return obj;
+ }
+ /**
+ * Copy simple property.
+ *
+ * @param property the property
+ * @param obj the obj
+ * @param v the v
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ */
+ private void copySimpleProperty(String property, Introspector obj, Vertex v) {
+ final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
+ String dbPropertyName = property;
+ if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
+ dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS);
+ }
+ final Object temp = v.<Object>property(dbPropertyName).orElse(null);
+ if (temp != null) {
+
+ obj.setValue(property, temp);
+ }
+ }
+
+ /**
+ * Simple db to object.
+ *
+ * @param obj the obj
+ * @param v the v
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ */
+ private void simpleDbToObject (Introspector obj, Vertex v) {
+ for (String property : obj.getProperties()) {
+
+
+ if (!(obj.isComplexType(property) || obj.isListType(property))) {
+ this.copySimpleProperty(property, obj, v);
+ }
+ }
+ }
+
+ /**
+ * Creates the relationship list.
+ *
+ * @param v the v
+ * @param obj the obj
+ * @param cleanUp the clean up
+ * @return the object
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws URISyntaxException
+ */
+ private Introspector createRelationshipList(Vertex v, Introspector obj, String cleanUp) throws UnsupportedEncodingException, AAIException {
+
+
+ List<Vertex> cousins = this.engine.getQueryEngine().findCousinVertices(v);
+
+ List<Object> relationshipObjList = obj.getValue("relationship");
+
+ for (Vertex cousin : cousins) {
+
+ Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
+ Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp);
+ if (result != null) {
+ relationshipObjList.add(result);
+ }
+
+ }
+
+ if (relationshipObjList.isEmpty()) {
+ return null;
+ } else {
+ return obj;
+ }
+ }
+
+ /**
+ * Process edge relationship.
+ *
+ * @param relationshipObj the relationship obj
+ * @param edge the edge
+ * @param direction the direction
+ * @param cleanUp the clean up
+ * @return the object
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws AAIUnknownObjectException
+ * @throws URISyntaxException
+ */
+ private Object processEdgeRelationship(Introspector relationshipObj, Vertex cousin, String cleanUp) throws UnsupportedEncodingException, AAIUnknownObjectException {
+
+
+ //we must look up all parents in this case because we need to compute name-properties
+ //we cannot used the cached aaiUri to perform this action currently
+ Pair<Vertex, List<Introspector>> tuple = this.getParents(relationshipObj.getLoader(), cousin, "true".equals(cleanUp));
+ //damaged vertex found, ignore
+ if (tuple == null) {
+ return null;
+ }
+ List<Introspector> list = tuple.getValue1();
+ URI uri = this.getURIFromList(list);
+
+ URIToRelationshipObject uriParser = null;
+ Introspector result = null;
+ try {
+ uriParser = new URIToRelationshipObject(relationshipObj.getLoader(), uri, this.baseURL);
+ result = uriParser.getResult();
+ } catch (AAIException | URISyntaxException e) {
+ LOGGER.error("Error while processing edge relationship in version " + relationshipObj.getVersion() + " (bad vertex ID=" + tuple.getValue0().id().toString() + ": " + e.getMessage(), e);
+ if ("true".equals(cleanUp)) {
+ this.deleteWithTraversal(tuple.getValue0());
+ }
+ return null;
+ }
+ return result.getUnderlyingObject();
+ }
+
+ /**
+ * Gets the URI for vertex.
+ *
+ * @param v the v
+ * @return the URI for vertex
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ public URI getURIForVertex(Vertex v) throws UnsupportedEncodingException {
+
+ return getURIForVertex(v, false);
+ }
+
+ public URI getURIForVertex(Vertex v, boolean overwrite) throws UnsupportedEncodingException {
+ URI uri = null;
+
+ String aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null);
+
+ if (aaiUri != null && !overwrite) {
+ uri = UriBuilder.fromPath(aaiUri).build();
+ } else {
+ Pair<Vertex, List<Introspector>> tuple = this.getParents(this.loader, v, false);
+ List<Introspector> list = tuple.getValue1();
+ uri = this.getURIFromList(list);
+ }
+ return uri;
+ }
+ /**
+ * Gets the URI from list.
+ *
+ * @param list the list
+ * @return the URI from list
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private URI getURIFromList(List<Introspector> list) throws UnsupportedEncodingException {
+ String uri = "";
+ StringBuilder sb = new StringBuilder();
+ for (Introspector i : list) {
+ sb.insert(0, i.getURI());
+ }
+
+ uri = sb.toString();
+ URI result = UriBuilder.fromPath(uri).build();
+ return result;
+ }
+
+ /**
+ * Gets the parents.
+ *
+ * @param start the start
+ * @param removeDamaged the remove damaged
+ * @return the parents
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws AAIUnknownObjectException
+ */
+ private Pair<Vertex, List<Introspector>> getParents(Loader loader, Vertex start, boolean removeDamaged) {
+
+ List<Vertex> results = this.engine.getQueryEngine().findParents(start);
+ List<Introspector> objs = new ArrayList<>();
+ boolean shortCircuit = false;
+ for (Vertex v : results) {
+ String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ Introspector obj = null;
+ //vertex on the other end of this edge is bad
+ if (nodeType == null) {
+ //log something here about what was found and that it was removed
+ ErrorLogHelper.logError("AAI-6143", "Found a damaged parent vertex " + v.id().toString());
+ if (removeDamaged) {
+ this.deleteWithTraversal(v);
+ }
+ shortCircuit = true;
+ } else {
+ try {
+ obj = loader.introspectorFromName(nodeType);
+ } catch (AAIUnknownObjectException e) {
+ LOGGER.info("attempted to create node type " + nodeType + " but we do not understand it for version: " + loader.getVersion());
+ obj = null;
+ }
+ }
+
+ if (obj == null) {
+ //can't make a valid path because we don't understand this object
+ // don't include it
+ } else {
+ this.simpleDbToObject(obj, v);
+ objs.add(obj);
+ }
+ }
+
+ //stop processing and don't return anything for this bad vertex
+ if (shortCircuit) {
+ return null;
+ }
+
+ return new Pair<>(results.get(results.size()-1), objs);
+ }
+ /**
+ * Takes a list of vertices and a list of objs and assumes they are in
+ * the order you want the URIs to be nested.
+ * [A,B,C] creates uris [A, AB, ABC]
+ * @param vertices
+ * @param objs
+ * @throws UnsupportedEncodingException
+ * @throws URISyntaxException
+ */
+ public void setCachedURIs(List<Vertex> vertices, List<Introspector> objs) throws UnsupportedEncodingException, URISyntaxException {
+
+ String uriChain = "";
+ for (int i = 0; i < vertices.size(); i++) {
+ String aaiUri = "";
+ Vertex v = null;
+ v = vertices.get(i);
+ aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null);
+ if (aaiUri != null) {
+ uriChain += aaiUri;
+ } else {
+ URI uri = UriBuilder.fromPath(objs.get(i).getURI()).build();
+ aaiUri = uri.toString();
+ uriChain += aaiUri;
+ v.property(AAIProperties.AAI_URI, uriChain);
+ }
+ }
+
+
+
+ }
+
+
+ /**
+ * Adds the r
+ * @throws AAIUnknownObjectException
+ * @throws IllegalArgumentException elated to property.
+ *
+ * @param relationship the relationship
+ * @param child the throws IllegalArgumentException, AAIUnknownObjectException child
+ */
+ public void addRelatedToProperty(Introspector relationship, Introspector child) throws AAIUnknownObjectException {
+ String nameProps = child.getMetadata(ObjectMetadata.NAME_PROPS);
+ List<Introspector> relatedToProperties = new ArrayList<>();
+
+ if (nameProps != null) {
+ String[] props = nameProps.split(",");
+ for (String prop : props) {
+ Introspector relatedTo = relationship.newIntrospectorInstanceOfNestedProperty("related-to-property");
+ relatedTo.setValue("property-key", child.getDbName() + "." + prop);
+ relatedTo.setValue("property-value", child.getValue(prop));
+ relatedToProperties.add(relatedTo);
+ }
+ }
+
+ if (relatedToProperties.size() > 0) {
+ List relatedToList = (List)relationship.getValue("related-to-property");
+ for (Introspector obj : relatedToProperties) {
+ relatedToList.add(obj.getUnderlyingObject());
+ }
+ }
+
+ }
+
+ /**
+ * Creates the edge.
+ *
+ * @param relationship the relationship
+ * @param inputVertex the input vertex
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public boolean createEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
+
+ Vertex relatedVertex = null;
+
+ QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
+
+ List<Vertex> results = parser.getQueryBuilder().toList();
+ if (results.size() == 0) {
+ AAIException e = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
+ e.getTemplateVars().add(parser.getResultType());
+ e.getTemplateVars().add(parser.getUri().toString());
+ throw e;
+ } else {
+ //still an issue if there's more than one
+ relatedVertex = results.get(0);
+ }
+
+ if (relatedVertex != null) {
+
+ Edge e;
+ try {
+ e = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex);
+ if (e == null) {
+ edgeRules.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex);
+
+ } else {
+ //attempted to link two vertexes already linked
+ }
+ } catch (NoEdgeRuleFoundException e1) {
+ throw new AAIException("AAI_6129", e1);
+ }
+
+
+
+
+ }
+
+ return true;
+ }
+
+ /**
+ * Gets the edges between.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edges between
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException, NoEdgeRuleFoundException {
+
+ List<Edge> result = new ArrayList<>();
+
+ if (bVertex != null) {
+ EdgeRule rule = edgeRules.getEdgeRule(type, aVertex, bVertex);
+ GraphTraversal<Vertex, Edge> findEdgesBetween = null;
+ findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE(rule.getLabel()).filter(__.otherV().hasId(bVertex.id()));
+ List<Edge> edges = findEdgesBetween.toList();
+ for (Edge edge : edges) {
+ if (edge.label().equals(rule.getLabel())) {
+ result.add(edge);
+ }
+ }
+
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets the edge between.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edge between
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ private Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException {
+
+
+
+ if (bVertex != null) {
+
+ List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex);
+
+ if (edges.size() > 0) {
+ return edges.get(0);
+ }
+
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Delete edge.
+ *
+ * @param relationship the relationship
+ * @param inputVertex the input vertex
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public boolean deleteEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
+
+ Vertex relatedVertex = null;
+
+ QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
+
+ List<Vertex> results = parser.getQueryBuilder().toList();
+
+ if (results.size() == 0) {
+ return false;
+ }
+
+ relatedVertex = results.get(0);
+ Edge edge;
+ try {
+ edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex);
+ } catch (NoEdgeRuleFoundException e) {
+ throw new AAIException("AAI_6129", e);
+ }
+ if (edge != null) {
+ edge.remove();
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
+ /**
+ * Delete items with traversal.
+ *
+ * @param vertexes the vertexes
+ * @throws IllegalStateException the illegal state exception
+ */
+ public void deleteItemsWithTraversal(List<Vertex> vertexes) throws IllegalStateException {
+ for (Vertex v : vertexes) {
+ LOGGER.debug("About to delete the vertex with id: " + v.id());
+ deleteWithTraversal(v);
+ }
+ }
+
+ /**
+ * Delete with traversal.
+ *
+ * @param startVertex the start vertex
+ */
+ public void deleteWithTraversal(Vertex startVertex) {
+
+ List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex);
+
+ for (Vertex v : results) {
+ LOGGER.warn("Removing vertex " + v.id().toString());
+
+ v.remove();
+ }
+
+ }
+
+ /**
+ * Delete.
+ *
+ * @param v the v
+ * @param resourceVersion the resource version
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws AAIException the AAI exception
+ * @throws InterruptedException the interrupted exception
+ */
+ public void delete(Vertex v, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException {
+
+ boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
+ if (result) {
+ try {
+ deleteWithTraversal(v);
+ } catch (IllegalStateException e) {
+ throw new AAIException("AAI_6110", e);
+ }
+
+ }
+
+ }
+
+
+ /**
+ * Verify delete semantics.
+ *
+ * @param vertex the vertex
+ * @param resourceVersion the resource version
+ * @return true, if successful
+ * @throws AAIException the AAI exception
+ */
+ private boolean verifyDeleteSemantics(Vertex vertex, String resourceVersion, boolean enableResourceVersion) throws AAIException {
+ boolean result = false;
+ String nodeType = "";
+ DeleteSemantic semantic = null;
+ List<Edge> inEdges = null;
+ List<Edge> outEdges = null;
+ String errorDetail = " unknown delete semantic found";
+ String aaiExceptionCode = "";
+ nodeType = vertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if (enableResourceVersion && !this.verifyResourceVersion("delete", nodeType, vertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), resourceVersion, nodeType)) {
+ }
+ semantic = edgeRules.getDeleteSemantic(nodeType);
+ inEdges = (List<Edge>) IteratorUtils.toList(vertex.edges(Direction.IN));
+ outEdges = (List<Edge>) IteratorUtils.toList(vertex.edges(Direction.OUT));
+ if (semantic.equals(DeleteSemantic.CASCADE_TO_CHILDREN)) {
+ result = true;
+ } else if (semantic.equals(DeleteSemantic.ERROR_IF_ANY_EDGES)) {
+ if (inEdges.isEmpty() && outEdges.isEmpty()) {
+ result = true;
+ } else {
+ errorDetail = " Node cannot be deleted because it still has Edges and the " + semantic + " scope was used.\n";
+ aaiExceptionCode = "AAI_6110";
+ }
+ } else if (semantic.equals(DeleteSemantic.ERROR_IF_ANY_IN_EDGES) || semantic.equals(DeleteSemantic.ERROR_4_IN_EDGES_OR_CASCADE)) {
+
+ if (inEdges.isEmpty()) {
+ result = true;
+ } else {
+ //are there any cousin edges?
+ long children = 0;
+ for (Edge e : inEdges) {
+ if (e.<Boolean>property("isParent").orElse(false)) {
+ children++;
+ }
+ }
+
+ result = children == inEdges.size();
+ }
+
+ if (!result) {
+ errorDetail = " Node cannot be deleted because it still has Edges and the " + semantic + " scope was used.\n";
+ aaiExceptionCode = "AAI_6110";
+ }
+ } else if (semantic.equals(DeleteSemantic.THIS_NODE_ONLY)) {
+ if (outEdges.isEmpty() && inEdges.isEmpty()) {
+ result = true;
+ } else {
+ result = true;
+ for (Edge edge : outEdges) {
+ Object property = edge.<Boolean>property("isParent").orElse(null);
+ if (property != null && property.equals(Boolean.TRUE)) {
+ Vertex v = edge.inVertex();
+ String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ errorDetail = " Node cannot be deleted using scope = " + semantic +
+ " another node (type = " + vType + ") depends on it for uniqueness.";
+ aaiExceptionCode = "AAI_6110";
+ result = false;
+ break;
+ }
+ }
+
+ for (Edge edge : inEdges) {
+ Object property = edge.<Boolean>property("isParent-REV").orElse(null);
+ if (property != null && property.equals(Boolean.TRUE)) {
+ Vertex v = edge.outVertex();
+ String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ errorDetail = " Node cannot be deleted using scope = " + semantic +
+ " another node (type = " + vType + ") depends on it for uniqueness.";
+ aaiExceptionCode = "AAI_6110";
+ result = false;
+ break;
+ }
+ }
+ }
+ }
+
+
+ if (!result) {
+ throw new AAIException(aaiExceptionCode, errorDetail);
+ }
+ return result;
+ }
+
+ /**
+ * Verify resource version.
+ *
+ * @param action the action
+ * @param nodeType the node type
+ * @param currentResourceVersion the current resource version
+ * @param resourceVersion the resource version
+ * @param uri the uri
+ * @return true, if successful
+ * @throws AAIException the AAI exception
+ */
+ public boolean verifyResourceVersion(String action, String nodeType, String currentResourceVersion, String resourceVersion, String uri) throws AAIException {
+ String enabled = "";
+ String errorDetail = "";
+ String aaiExceptionCode = "";
+ if (currentResourceVersion == null) {
+ currentResourceVersion = "";
+ }
+
+ if (resourceVersion == null) {
+ resourceVersion = "";
+ }
+ try {
+ enabled = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG);
+ } catch (AAIException e) {
+ ErrorLogHelper.logException(e);
+ }
+ // We're only doing the resource version checks for v5 and later
+ if (enabled.equals("true") && this.version.compareTo(Version.v8) > 0) {
+ if (!currentResourceVersion.equals(resourceVersion)) {
+ if (action.equals("create") && !resourceVersion.equals("")) {
+ errorDetail = "resource-version passed for " + action + " of " + uri;
+ aaiExceptionCode = "AAI_6135";
+ } else if (resourceVersion.equals("")) {
+ errorDetail = "resource-version not passed for " + action + " of " + uri;
+ aaiExceptionCode = "AAI_6130";
+ } else {
+ errorDetail = "resource-version MISMATCH for " + action + " of " + uri;
+ aaiExceptionCode = "AAI_6131";
+ }
+
+ throw new AAIException(aaiExceptionCode, errorDetail);
+
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Convert from camel case.
+ *
+ * @param name the name
+ * @return the string
+ */
+ private String convertFromCamelCase (String name) {
+ String result = "";
+ result = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name);
+
+ NamingExceptions exceptions = NamingExceptions.getInstance();
+ result = exceptions.getDBName(result);
+
+ return result;
+ }
+
+ private boolean canModify(Introspector obj, String propName, String requestContext) {
+ final String readOnly = obj.getPropertyMetadata(propName).get(PropertyMetadata.READ_ONLY);
+ if (readOnly != null) {
+ final String[] items = readOnly.split(",");
+ for (String item : items) {
+ if (requestContext.equals(item)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private void executePreSideEffects(Introspector obj, Vertex self) throws AAIException {
+
+ SideEffectRunner runner = new SideEffectRunner
+ .Builder(this.engine, this).addSideEffect(DataCopy.class).build();
+
+ runner.execute(obj, self);
+ }
+
+ private void executePostSideEffects(Introspector obj, Vertex self) throws AAIException {
+
+ SideEffectRunner runner = new SideEffectRunner
+ .Builder(this.engine, this).addSideEffect(DataLinkWriter.class).build();
+
+ runner.execute(obj, self);
+ }
+
+ private void enrichData(Introspector obj, Vertex self) throws AAIException {
+
+ SideEffectRunner runner = new SideEffectRunner
+ .Builder(this.engine, this).addSideEffect(DataLinkReader.class).build();
+
+ runner.execute(obj, self);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/DeleteSemantic.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/DeleteSemantic.java
new file mode 100644
index 00000000..65a39497
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/DeleteSemantic.java
@@ -0,0 +1,40 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.db;
+
+
+/**
+ * Possible values for deleteScope can be:
+ * USE_DEFAULT - Get the scope from ref data for this node
+ * THIS_NODE_ONLY (but should fail if it there are nodes that depend on it for uniqueness)
+ * CASCADE_TO_CHILDREN - will look for OUT-Edges that have parentOf/hasDelTarget = true and follow those down
+ * ERROR_4_IN_EDGES_OR_CASCADE - combo of error-if-any-IN-edges + CascadeToChildren
+ * ERROR_IF_ANY_IN_EDGES - Fail if this node has any existing IN edges
+ * ERROR_IF_ANY_EDGES - Fail if this node has any existing edges at all!
+ */
+public enum DeleteSemantic {
+ USE_DEFAULT,
+ THIS_NODE_ONLY,
+ CASCADE_TO_CHILDREN,
+ ERROR_4_IN_EDGES_OR_CASCADE,
+ ERROR_IF_ANY_IN_EDGES,
+ ERROR_IF_ANY_EDGES,
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRule.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRule.java
new file mode 100644
index 00000000..d7abfdc0
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRule.java
@@ -0,0 +1,202 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.db;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tinkerpop.gremlin.structure.Direction;
+
+public class EdgeRule {
+
+ private String label = "";
+ private MultiplicityRule multiplicityRule = null;
+ private Direction direction = null;
+ private Map<String, String> edgeProperties = null;
+ private final String IS_PARENT = "isParent";
+ private final String USES_RESOURCE = "usesResource";
+ private final String HAS_DEL_TARGET = "hasDelTarget";
+ private final String SVC_INFRA = "SVC-INFRA";
+
+ /**
+ * Instantiates a new edge rule.
+ */
+ public EdgeRule() {
+ edgeProperties = new HashMap<>();
+ }
+
+ /**
+ * Gets the label.
+ *
+ * @return the label
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Sets the label.
+ *
+ * @param label the new label
+ */
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ /**
+ * Gets the multiplicity rule.
+ *
+ * @return the multiplicity rule
+ */
+ public MultiplicityRule getMultiplicityRule() {
+ return multiplicityRule;
+ }
+
+ /**
+ * Sets the multiplicity rule.
+ *
+ * @param multiplicityRule the new multiplicity rule
+ */
+ public void setMultiplicityRule(MultiplicityRule multiplicityRule) {
+ this.multiplicityRule = multiplicityRule;
+ }
+
+ /**
+ * Gets the direction.
+ *
+ * @return the direction
+ */
+ public Direction getDirection() {
+ return direction;
+ }
+
+ /**
+ * Sets the direction.
+ *
+ * @param direction the new direction
+ */
+ public void setDirection(Direction direction) {
+ this.direction = direction;
+ }
+
+ /**
+ * Gets the checks if is parent.
+ *
+ * @return the checks if is parent
+ */
+ public String getIsParent() {
+ return this.getProp(this.IS_PARENT);
+ }
+
+ /**
+ * Sets the checks if is parent.
+ *
+ * @param isParent the new checks if is parent
+ */
+ public void setIsParent(String isParent) {
+ this.setProp(this.IS_PARENT, isParent);
+ }
+
+ /**
+ * Gets the uses resource.
+ *
+ * @return the uses resource
+ */
+ public String getUsesResource() {
+ return this.getProp(this.USES_RESOURCE);
+ }
+
+ /**
+ * Sets the uses resource.
+ *
+ * @param usesResource the new uses resource
+ */
+ public void setUsesResource(String usesResource) {
+ this.setProp(this.USES_RESOURCE, usesResource);
+ }
+
+ /**
+ * Gets the checks for del target.
+ *
+ * @return the checks for del target
+ */
+ public String getHasDelTarget() {
+ return this.getProp(this.HAS_DEL_TARGET);
+ }
+
+ /**
+ * Sets the checks for del target.
+ *
+ * @param hasDelTarget the new checks for del target
+ */
+ public void setHasDelTarget(String hasDelTarget) {
+ this.setProp(this.HAS_DEL_TARGET, hasDelTarget);
+ }
+
+ /**
+ * Gets the service infrastructure.
+ *
+ * @return the service infrastructure
+ */
+ public String getServiceInfrastructure() {
+ return this.getProp(this.SVC_INFRA);
+ }
+
+ /**
+ * Sets the service infrastructure.
+ *
+ * @param serviceInfrastructure the new service infrastructure
+ */
+ public void setServiceInfrastructure(String serviceInfrastructure) {
+ this.setProp(this.SVC_INFRA, serviceInfrastructure);
+ }
+
+ /**
+ * Gets the edge properties.
+ *
+ * @return the edge properties
+ */
+ public Map<String, String> getEdgeProperties() {
+ return this.edgeProperties;
+ }
+
+ /**
+ * Sets the prop.
+ *
+ * @param key the key
+ * @param value the value
+ */
+ private void setProp(String key, String value) {
+ this.edgeProperties.put(key, value);
+ }
+
+ /**
+ * Gets the prop.
+ *
+ * @param key the key
+ * @return the prop
+ */
+ private String getProp(String key) {
+ return this.edgeProperties.get(key);
+ }
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRules.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRules.java
new file mode 100644
index 00000000..06dfe564
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRules.java
@@ -0,0 +1,379 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.db;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.dbmodel.DbEdgeRules;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+
+public class EdgeRules {
+
+ private Multimap<String, String> rules = DbEdgeRules.EdgeRules;
+ private Multimap<String, String> deleteScope = DbEdgeRules.DefaultDeleteScope;
+ private final int EDGE_NAME = 0;
+ private final int DIRECTION = 1;
+ private final int MULTIPLICITY_RULE = 2;
+ private final int IS_PARENT = 3;
+ private final int USES_RESOURCE = 4;
+ private final int HAS_DEL_TARGET = 5;
+ private final int SVC_INFRA = 6;
+
+ /**
+ * Instantiates a new edge rules.
+ */
+ private EdgeRules() {
+
+ }
+ private static class Helper {
+ private static final EdgeRules INSTANCE = new EdgeRules();
+
+ }
+
+ /**
+ * Gets the single instance of EdgeRules.
+ *
+ * @return single instance of EdgeRules
+ */
+ public static EdgeRules getInstance() {
+ return Helper.INSTANCE;
+
+ }
+
+ /**
+ * Adds the tree edge.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edge
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ public Edge addTreeEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
+ return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex);
+ }
+
+ /**
+ * Adds the edge.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edge
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ public Edge addEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
+ return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex);
+ }
+
+ /**
+ * Adds the edge.
+ *
+ * @param type the type
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edge
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ private Edge addEdge(EdgeType type, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException, NoEdgeRuleFoundException {
+
+ EdgeRule rule = this.getEdgeRule(type, aVertex, bVertex);
+
+ Edge e = null;
+ if (this.validateMultiplicity(rule, traversalSource, aVertex, bVertex)) {
+ if (rule.getDirection().equals(Direction.OUT)) {
+ e = aVertex.addEdge(rule.getLabel(), bVertex);
+ } else if (rule.getDirection().equals(Direction.IN)) {
+ e = bVertex.addEdge(rule.getLabel(), aVertex);
+ }
+
+ this.addProperties(e, rule);
+ }
+ return e;
+ }
+
+ /**
+ * Adds the properties.
+ *
+ * @param edge the edge
+ * @param rule the rule
+ */
+ public void addProperties(Edge edge, EdgeRule rule) {
+
+ // In DbEdgeRules.EdgeRules -- What we have as "edgeRule" is a comma-delimited set of strings.
+ // The first item is the edgeLabel.
+ // The second in the list is always "direction" which is always OUT for the way we've implemented it.
+ // Items starting at "firstTagIndex" and up are all assumed to be booleans that map according to
+ // tags as defined in EdgeInfoMap.
+ // Note - if they are tagged as 'reverse', that means they get the tag name with "-REV" on it
+ Map<String, String> propMap = rule.getEdgeProperties();
+
+ for (String key : propMap.keySet()) {
+ String revKeyname = key + "-REV";
+ String triple = propMap.get(key);
+ if(triple.equals("true")){
+ edge.property(key, true);
+ edge.property(revKeyname,false);
+ } else if (triple.equals("false")) {
+ edge.property(key, false);
+ edge.property(revKeyname,false);
+ } else if (triple.equals("reverse")) {
+ edge.property(key, false);
+ edge.property(revKeyname,true);
+ }
+ }
+ }
+
+ /**
+ * Checks for edge rule.
+ *
+ * @param outType the out type
+ * @param inType the in type
+ * @return true, if successful
+ */
+ public boolean hasEdgeRule(String outType, String inType) {
+
+ Collection<String> collection = rules.get(outType + "|" + inType);
+
+ return !collection.isEmpty();
+
+ }
+
+ /**
+ * Checks for edge rule.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return true, if successful
+ */
+ public boolean hasEdgeRule(Vertex aVertex, Vertex bVertex) {
+ String outType = (String)aVertex.<String>property("aai-node-type").orElse(null);
+ String inType = (String)bVertex.<String>property("aai-node-type").orElse(null);
+
+ return this.hasEdgeRule(outType, inType);
+
+ }
+
+ public Map<String, EdgeRule> getEdgeRules(String outType, String inType) throws AAIException {
+ Map<String, EdgeRule> result = new HashMap<>();
+ EdgeRule rule = null;
+ for (EdgeType type : EdgeType.values()) {
+ try {
+ rule = this.getEdgeRule(type, outType, inType);
+ result.put(rule.getLabel(), rule);
+ } catch (NoEdgeRuleFoundException e) {
+ continue;
+ }
+ }
+
+ return result;
+ }
+ /**
+ * Gets the edge rule.
+ *
+ * @param outType the out type
+ * @param inType the in type
+ * @return the edge rule
+ * @throws AAIException the AAI exception
+ */
+ public EdgeRule getEdgeRule(EdgeType type, String outType, String inType) throws AAIException {
+ EdgeRule rule = new EdgeRule();
+ Collection<String> collection = null;
+ boolean isFlipped = false;
+ if (this.hasEdgeRule(outType, inType) || this.hasEdgeRule(inType, outType)) {
+ } else {
+ String detail = "No EdgeRule found for passed nodeTypes: " + outType + ", " + inType + ".";
+ throw new AAIException("AAI_6120", detail);
+ }
+ String key = outType + "|" + inType;
+ collection = rules.get(key);
+
+ String[] info = null;
+ Iterator<String> iterator = collection.iterator();
+ info = this.findRuleForContext(type, key, iterator);
+ if (info == null) { //didn't find anything in that order, look again
+ key = inType + "|" + outType;
+ collection = rules.get(key);
+ iterator = collection.iterator();
+ info = this.findRuleForContext(type, key, iterator);
+ isFlipped = true;
+ }
+ if (info == null) {
+ throw new NoEdgeRuleFoundException("No EdgeRule found for EdgeType: " + type + " and node types: " + outType + " " + inType);
+ }
+ rule.setLabel(info[this.EDGE_NAME]);
+ rule.setMultiplicityRule(MultiplicityRule.valueOf(info[this.MULTIPLICITY_RULE].toUpperCase()));
+ rule.setHasDelTarget(info[this.HAS_DEL_TARGET]);
+ rule.setUsesResource(info[this.USES_RESOURCE]);
+ rule.setIsParent(info[this.IS_PARENT]);
+ rule.setServiceInfrastructure(info[this.SVC_INFRA]);
+ Direction direction = Direction.valueOf(info[this.DIRECTION]);
+ if (isFlipped && direction.equals(Direction.OUT)) {
+ rule.setDirection(Direction.IN);
+ } else if (isFlipped && direction.equals(Direction.IN)){
+ rule.setDirection(Direction.OUT);
+ } else {
+ rule.setDirection(direction);
+ }
+
+ return rule;
+ }
+
+ private String[] findRuleForContext (EdgeType type, String key, Iterator<String> itr) {
+ String[] result = null;
+ String s = "";
+ String isParent = "";
+ String[] info = new String[10];
+ while (itr.hasNext()) {
+ s = itr.next();
+ info = s.split(",");
+ isParent = info[this.IS_PARENT];
+ //lazily stop iterating if we find a match
+ //should there be a mismatch between type and isParent,
+ //the caller will receive something.
+ //this operates on the assumption that there are at most two rules
+ //for a given vertex pair
+ if (type.equals(EdgeType.TREE) && (isParent.equals("true") || isParent.equals("reverse"))) {
+ result = info;
+ break;
+ } else if (type.equals(EdgeType.COUSIN) && isParent.equals("false")) {
+ result = info;
+ break;
+ }
+ }
+
+
+ return result;
+ }
+ /**
+ * Gets the edge rule.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edge rule
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ public EdgeRule getEdgeRule(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException, NoEdgeRuleFoundException {
+ String outType = (String)aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ String inType = (String)bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+
+ return this.getEdgeRule(type, outType, inType);
+
+
+ }
+
+ /**
+ * Gets the delete semantic.
+ *
+ * @param nodeType the node type
+ * @return the delete semantic
+ */
+ public DeleteSemantic getDeleteSemantic(String nodeType) {
+ Collection<String> semanticCollection = deleteScope.get(nodeType);
+ String semantic = semanticCollection.iterator().next();
+
+ return DeleteSemantic.valueOf(semantic);
+
+ }
+
+ /**
+ * Validate multiplicity.
+ *
+ * @param rule the rule
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return true, if successful
+ * @throws AAIException the AAI exception
+ */
+ private boolean validateMultiplicity(EdgeRule rule, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
+
+ if (rule.getDirection().equals(Direction.OUT)) {
+
+ } else if (rule.getDirection().equals(Direction.IN)) {
+ Vertex tempV = bVertex;
+ bVertex = aVertex;
+ aVertex = tempV;
+ }
+
+ String aVertexType = aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ String bVertexType = bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ String label = rule.getLabel();
+ MultiplicityRule multiplicityRule = rule.getMultiplicityRule();
+ List<Edge> outEdges = traversalSource.V(aVertex).outE(label).where(__.inV().has(AAIProperties.NODE_TYPE, bVertexType)).toList();
+ List<Edge> inEdges = traversalSource.V(bVertex).inE(label).where(__.outV().has(AAIProperties.NODE_TYPE, aVertexType)).toList();
+ String detail = "";
+ if (multiplicityRule.equals(MultiplicityRule.ONE2ONE)) {
+ if (inEdges.size() >= 1 || outEdges.size() >= 1 ) {
+ detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType;
+ }
+ } else if (multiplicityRule.equals(MultiplicityRule.ONE2MANY)) {
+ if (inEdges.size() >= 1) {
+ detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType;
+ }
+ } else if (multiplicityRule.equals(MultiplicityRule.MANY2ONE)) {
+ if (outEdges.size() >= 1) {
+ detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType;
+ }
+ } else {
+
+ }
+
+ if (!detail.equals("")) {
+ throw new AAIException("AAI_6140", detail);
+ }
+
+ return true;
+
+ }
+
+ public Multimap<String, EdgeRule> getAllRules() throws AAIException {
+
+ Multimap<String, EdgeRule> result = ArrayListMultimap.create();
+
+ for (String key : this.rules.keySet()) {
+ String outType = "";
+ String inType = "";
+ String[] split = key.split("\\|");
+ outType = split[0];
+ inType = split[1];
+ result.putAll(key,this.getEdgeRules(outType, inType).values());
+ }
+
+ return result;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeType.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeType.java
new file mode 100644
index 00000000..aabd74fe
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeType.java
@@ -0,0 +1,26 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.db;
+
+public enum EdgeType {
+ COUSIN,
+ TREE;
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/GetAllPool.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/GetAllPool.java
new file mode 100644
index 00000000..356f70ae
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/GetAllPool.java
@@ -0,0 +1,46 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.db;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class GetAllPool {
+
+ private ExecutorService pool;
+
+ private GetAllPool() {
+ pool = Executors.newWorkStealingPool(Runtime.getRuntime().availableProcessors());
+ }
+
+ private static class Helper {
+ private static final GetAllPool INSTANCE = new GetAllPool();
+ }
+
+ public static GetAllPool getInstance() {
+ return Helper.INSTANCE;
+ }
+
+ public ExecutorService getPool() {
+
+ return this.pool;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/GraphSingleton.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/GraphSingleton.java
new file mode 100644
index 00000000..9f226dc1
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/GraphSingleton.java
@@ -0,0 +1,69 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.db;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.openecomp.aai.dbmap.AAIGraph;
+import org.openecomp.aai.dbmap.DBConnectionType;
+import com.thinkaurelius.titan.core.TitanGraph;
+
+/* This class simply calls AAIGraph under the covers for now */
+public class GraphSingleton {
+
+ protected AtomicInteger totalCount = new AtomicInteger();
+
+ private static class Helper {
+ private static final GraphSingleton INSTANCE = new GraphSingleton();
+ }
+
+ /**
+ * Gets the single instance of GraphSingleton.
+ *
+ * @return single instance of GraphSingleton
+ */
+ public static GraphSingleton getInstance() {
+ return Helper.INSTANCE;
+
+ }
+
+ /**
+ * Gets the count.
+ *
+ * @return the count
+ */
+ public AtomicInteger getCount() {
+ return totalCount;
+ }
+
+ /**
+ * Gets the tx graph.
+ *
+ * @return the tx graph
+ */
+ public TitanGraph getTxGraph() {
+ return AAIGraph.getInstance().getGraph();
+ }
+
+ public TitanGraph getTxGraph(DBConnectionType connectionType) {
+ return AAIGraph.getInstance().getGraph(connectionType);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/LegacyDBSerializer.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/LegacyDBSerializer.java
new file mode 100644
index 00000000..841b1b74
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/LegacyDBSerializer.java
@@ -0,0 +1,35 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.db;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.ModelType;
+import org.openecomp.aai.introspection.Version;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+
+public class LegacyDBSerializer extends DBSerializer {
+
+ public LegacyDBSerializer(Version version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException {
+ super(version, engine, introspectionType, sourceOfTruth);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/MultiplicityRule.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/MultiplicityRule.java
new file mode 100644
index 00000000..734a44bc
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/MultiplicityRule.java
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.db;
+
+public enum MultiplicityRule {
+ MANY2ONE,
+ ONE2MANY,
+ ONE2ONE,
+ MANY2MANY
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/TitanGraphSingleton.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/TitanGraphSingleton.java
new file mode 100644
index 00000000..bca2d70c
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/TitanGraphSingleton.java
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.db;
+
+/* This is class is just a wrapper of its parent */
+public class TitanGraphSingleton extends GraphSingleton {
+
+ private static class Helper {
+ private static final TitanGraphSingleton INSTANCE = new TitanGraphSingleton();
+ }
+
+ /**
+ * Gets the single instance of TitanGraphSingleton.
+ *
+ * @return single instance of TitanGraphSingleton
+ */
+ public static TitanGraphSingleton getInstance() {
+ return Helper.INSTANCE;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/exceptions/NoEdgeRuleFoundException.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/exceptions/NoEdgeRuleFoundException.java
new file mode 100644
index 00000000..6647f4d5
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/exceptions/NoEdgeRuleFoundException.java
@@ -0,0 +1,40 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.db.exceptions;
+
+import org.openecomp.aai.exceptions.AAIException;
+
+public class NoEdgeRuleFoundException extends AAIException {
+
+ private static final long serialVersionUID = -906843868234976763L;
+
+ public NoEdgeRuleFoundException(String message) {
+ super("AAI_6129", message);
+ }
+
+ public NoEdgeRuleFoundException(Throwable cause) {
+ super("AAI_6129",cause);
+ }
+
+ public NoEdgeRuleFoundException(String message, Throwable cause) {
+ super("AAI_6129", cause, message);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/engines/QueryStyle.java b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/QueryStyle.java
new file mode 100644
index 00000000..acec8dff
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/QueryStyle.java
@@ -0,0 +1,25 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.engines;
+
+public enum QueryStyle {
+ GREMLIN_TRAVERSAL, GREMLIN_UNIQUE, GREMLINPIPELINE_TRAVERSAL, TRAVERSAL
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/engines/TitanDBEngine.java b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/TitanDBEngine.java
new file mode 100644
index 00000000..e3e0e857
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/TitanDBEngine.java
@@ -0,0 +1,103 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.engines;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+
+import org.openecomp.aai.dbmap.DBConnectionType;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.serialization.db.TitanGraphSingleton;
+import com.thinkaurelius.titan.core.TitanVertex;
+
+public class TitanDBEngine extends TransactionalGraphEngine {
+
+ /**
+ * Instantiates a new titan DB engine.
+ *
+ * @param style the style
+ * @param loader the loader
+ */
+ public TitanDBEngine(QueryStyle style, DBConnectionType connectionType, Loader loader) {
+ super(style, loader, connectionType, TitanGraphSingleton.getInstance());
+ }
+
+ /**
+ * Instantiates a new titan DB engine.
+ *
+ * @param style the style
+ * @param loader the loader
+ * @param connect the connect
+ */
+ public TitanDBEngine(QueryStyle style, Loader loader, boolean connect) {
+ super(style, loader);
+ if (connect) {
+ this.singleton = TitanGraphSingleton.getInstance();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean setListProperty(Vertex v, String name, List<?> objs) {
+
+ //clear out list full replace style
+
+ Iterator<VertexProperty<Object>> iterator = v.properties(name);
+ while (iterator.hasNext()) {
+ iterator.next().remove();
+ }
+ if (objs != null) {
+ for (Object obj : objs) {
+ v.property(name, obj);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Object> getListProperty(Vertex v, String name) {
+
+ List<Object> result = new ArrayList<Object>();
+
+ Iterator<VertexProperty<Object>> iterator = v.properties(name);
+
+ while (iterator.hasNext()) {
+ result.add(iterator.next().value());
+ }
+
+ if (result.size() == 0) {
+ result = null;
+ }
+
+ return result;
+
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/engines/TransactionalGraphEngine.java b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/TransactionalGraphEngine.java
new file mode 100644
index 00000000..7f63c055
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/TransactionalGraphEngine.java
@@ -0,0 +1,234 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.engines;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.dbmap.DBConnectionType;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.query.builder.GremlinTraversal;
+import org.openecomp.aai.query.builder.GremlinUnique;
+import org.openecomp.aai.query.builder.QueryBuilder;
+import org.openecomp.aai.query.builder.TraversalQuery;
+import org.openecomp.aai.serialization.db.GraphSingleton;
+import org.openecomp.aai.serialization.engines.query.GraphTraversalQueryEngine;
+import org.openecomp.aai.serialization.engines.query.QueryEngine;
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.thinkaurelius.titan.core.TitanTransaction;
+import com.thinkaurelius.titan.core.schema.TitanManagement;
+
+public abstract class TransactionalGraphEngine {
+
+ protected GraphSingleton singleton = null;
+ protected QueryEngine queryEngine = null;
+ protected QueryBuilder queryBuilder = null;
+ protected QueryStyle style = null;
+ protected final DBConnectionType connectionType;
+ protected final Loader loader;
+ protected TitanTransaction currentTx = null;
+ protected GraphTraversalSource currentTraversal = null;
+ protected GraphTraversalSource readOnlyTraversal = null;
+ private final Admin admin;
+ /**
+ * Instantiates a new transactional graph engine.
+ *
+ * @param style the style
+ * @param loader the loader
+ */
+ public TransactionalGraphEngine (QueryStyle style, Loader loader, DBConnectionType connectionType, GraphSingleton singleton) {
+ this.loader = loader;
+ this.style = style;
+ this.singleton = singleton;
+ this.connectionType = connectionType;
+ admin = new Admin();
+
+ }
+
+ public TransactionalGraphEngine (QueryStyle style, Loader loader) {
+ this.loader = loader;
+ this.style = style;
+ this.connectionType = DBConnectionType.REALTIME;
+ admin = new Admin();
+ }
+
+ /**
+ * Sets the list property.
+ *
+ * @param v the v
+ * @param name the name
+ * @param obj the obj
+ * @return true, if successful
+ */
+ public abstract boolean setListProperty(Vertex v, String name, List<?> obj);
+
+ /**
+ * Gets the list property.
+ *
+ * @param v the v
+ * @param name the name
+ * @return the list property
+ */
+ public abstract List<Object> getListProperty(Vertex v, String name);
+
+ /**
+ * Gets the graph.
+ *
+ * @return the graph
+ */
+ private TitanGraph getGraph() {
+ return singleton.getTxGraph(this.connectionType);
+ }
+
+ /**
+ * Gets the count.
+ *
+ * @return the count
+ */
+ public AtomicInteger getCount() {
+ return singleton.getCount();
+ }
+
+
+ /**
+ * Gets the query engine.
+ *
+ * @return the query engine
+ */
+ public QueryEngine getQueryEngine() {
+ QueryEngine engine = null;
+ if (style.equals(QueryStyle.GREMLIN_TRAVERSAL)) {
+ //this.queryEngine = new GremlinQueryEngine(this);
+ } else if (style.equals(QueryStyle.GREMLIN_UNIQUE)) {
+ //this.queryEngine = new GremlinQueryEngine(this);
+ } else if (style.equals(QueryStyle.GREMLINPIPELINE_TRAVERSAL)) {
+ //this.queryEngine = new GremlinPipelineQueryEngine(this);
+ } else if (style.equals(QueryStyle.TRAVERSAL)) {
+
+ return new GraphTraversalQueryEngine(this.asAdmin().getTraversalSource());
+
+ } else {
+ throw new IllegalArgumentException("Query Engine type not recognized");
+ }
+
+ return engine;
+ }
+
+ /**
+ * Gets the query builder.
+ *
+ * @return the query builder
+ */
+ public QueryBuilder getQueryBuilder() {
+ return getQueryBuilder(this.loader);
+ }
+
+ public QueryBuilder getQueryBuilder(Loader loader) {
+ if (style.equals(QueryStyle.GREMLIN_TRAVERSAL)) {
+ return new GremlinTraversal(loader, this.asAdmin().getTraversalSource());
+ } else if (style.equals(QueryStyle.GREMLIN_UNIQUE)) {
+ return new GremlinUnique(loader, this.asAdmin().getTraversalSource());
+ } else if (style.equals(QueryStyle.GREMLINPIPELINE_TRAVERSAL)) {
+ //return new GremlinPipelineTraversal(loader);
+ } else if (style.equals(QueryStyle.TRAVERSAL)) {
+ return new TraversalQuery(loader, this.asAdmin().getTraversalSource());
+ } else {
+ throw new IllegalArgumentException("Query Builder type not recognized");
+ }
+ return queryBuilder;
+ }
+ /**
+ * Gets the query builder.
+ *
+ * @param start the start
+ * @return the query builder
+ */
+ public QueryBuilder getQueryBuilder(Vertex start) {
+ return getQueryBuilder(this.loader, start);
+ }
+
+ public QueryBuilder getQueryBuilder(Loader loader, Vertex start) {
+ if (style.equals(QueryStyle.GREMLIN_TRAVERSAL)) {
+ return new GremlinTraversal(loader, this.asAdmin().getTraversalSource(), start);
+ } else if (style.equals(QueryStyle.GREMLIN_UNIQUE)) {
+ return new GremlinUnique(loader, this.asAdmin().getTraversalSource(), start);
+ } else if (style.equals(QueryStyle.GREMLINPIPELINE_TRAVERSAL)) {
+ //return new GremlinPipelineTraversal(loader,start);
+ } else if (style.equals(QueryStyle.TRAVERSAL)) {
+ return new TraversalQuery(loader, this.asAdmin().getTraversalSource(), start);
+ } else {
+ throw new IllegalArgumentException("Query Builder type not recognized");
+ }
+ return queryBuilder;
+ }
+
+ public TitanTransaction startTransaction() {
+ if (this.tx() == null) {
+ this.currentTx = this.getGraph().newTransaction();
+ this.currentTraversal = this.tx().traversal();
+ this.readOnlyTraversal = this.tx().traversal(GraphTraversalSource.build().with(ReadOnlyStrategy.instance()));
+ }
+ return currentTx;
+ }
+
+ public void rollback() {
+ if (this.tx() != null) {
+ this.tx().rollback();
+ this.currentTx = null;
+ this.currentTraversal = null;
+ this.readOnlyTraversal = null;
+ }
+ }
+ public void commit() {
+ if (this.tx() != null) {
+ this.tx().commit();
+ this.currentTx = null;
+ this.currentTraversal = null;
+ this.readOnlyTraversal = null;
+ }
+ }
+
+ public TitanTransaction tx() {
+ return this.currentTx;
+ }
+
+ public Admin asAdmin() {
+ return admin;
+ }
+
+ public class Admin {
+
+ public GraphTraversalSource getTraversalSource() {
+ return currentTraversal;
+ }
+ public GraphTraversalSource getReadOnlyTraversalSource() {
+ return readOnlyTraversal;
+ }
+
+ public TitanManagement getManagementSystem() {
+ return getGraph().openManagement();
+ }
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/GraphTraversalQueryEngine.java b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/GraphTraversalQueryEngine.java
new file mode 100644
index 00000000..2f485b10
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/GraphTraversalQueryEngine.java
@@ -0,0 +1,170 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.engines.query;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.introspection.Loader;
+
+/*
+ * This class needs some big explanation despite its compact size.
+ * This controls all the queries performed by the CRUD API in A&AI.
+ * findParents, findChildren, and findDeletable require special attention
+ * These methods use 'repeat'. You cannot use 'emit' with repeat currently
+ * as it is extremely buggy as of tinkerpop-3.0.1-incubating. The way around
+ * it (for now) is to sideEffect all the vertices we traverse into an ArrayList.
+ *
+ */
+public class GraphTraversalQueryEngine extends QueryEngine {
+
+ /**
+ * Instantiates a new graph traversal query engine.
+ *
+ * @param graphEngine the graph engine
+ */
+ public GraphTraversalQueryEngine(GraphTraversalSource g) {
+ super(g);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Vertex> findParents(Vertex start) {
+
+ final GraphTraversal<Vertex, Vertex> pipe = this.g.V(start).emit(v -> true).repeat(__.inE().has("isParent", true).outV());
+ return pipe.toList();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Vertex> findAllChildren(Vertex start) {
+
+ GraphTraversal<Vertex, Vertex> pipe = this.g
+ .V(start).emit(v -> true).repeat(__.outE().has("isParent", true).inV());
+
+
+ return pipe.toList();
+
+ }
+
+ public List<Vertex> findChildrenOfType(Vertex start, String type) {
+ GraphTraversal<Vertex, Vertex> pipe = this.g.V(start).union(
+ __.outE().has("isParent", true).inV(),
+ __.inE().has("isParent-REV", true).outV()
+ ).has(AAIProperties.NODE_TYPE, type).dedup();
+
+ return pipe.toList();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Vertex> findDeletable(Vertex start) {
+ GraphTraversal<Vertex, Vertex> pipe = this.g
+ .V(start).emit(v -> true).repeat(__.outE().or(
+ __.has("isParent", true),
+ __.has("hasDelTarget", true)).inV());
+
+ return pipe.toList();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Vertex> findRelatedVertices(Vertex start, Direction direction, String label, String nodeType) {
+ GraphTraversal<Vertex, Vertex> pipe = this.g.V(start);
+ switch (direction) {
+ case OUT:
+ pipe.out(label);
+ break;
+ case IN:
+ pipe.in(label);
+ break;
+ case BOTH:
+ pipe.both(label);
+ break;
+ default:
+ break;
+ }
+
+ pipe.has(AAIProperties.NODE_TYPE, nodeType).dedup();
+ return pipe.toList();
+ }
+
+ @Override
+ public Tree<Element> findSubGraph(Vertex start, int iterations, boolean nodeOnly) {
+ final GraphTraversal<Vertex, ?> t = this.g.V(start).emit(v -> true).times(iterations).repeat(
+ __.outE().has("isParent", true).inV());
+
+ if (!nodeOnly) {
+ t.union(
+ __.identity(),
+ __.bothE().has("isParent", false).dedup().otherV()
+ );
+ }
+ t.tree();
+ if (t.hasNext()) {
+ return (Tree)t.next();
+ } else {
+ return new Tree();
+ }
+ }
+
+ @Override
+ public List<Edge> findEdgesForVersion(Vertex start, Loader loader) {
+ final Set<String> objects = loader.getAllObjects().keySet();
+ GraphTraversal<Vertex, Edge> pipeline = this.g.V(start).union(
+ __.inE().has("isParent", false).has("isParent-REV", false).where(__.outV().has(AAIProperties.NODE_TYPE, P.within(objects))),
+ __.outE().has("isParent", false).has("isParent-REV", false).where(__.inV().has(AAIProperties.NODE_TYPE, P.within(objects)))
+ ).dedup();
+
+ return pipeline.toList();
+ }
+
+
+ @Override
+ public List<Vertex> findCousinVertices(Vertex start) {
+ GraphTraversal<Vertex, Vertex> pipeline = this.g.V(start).union(
+ __.inE().has("isParent", false).has("isParent-REV", false),
+ __.outE().has("isParent", false).has("isParent-REV", false)).otherV().dedup();
+
+ return pipeline.toList();
+ }
+
+}
+
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/GremlinPipelineQueryEngine.java b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/GremlinPipelineQueryEngine.java
new file mode 100644
index 00000000..adf5d405
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/GremlinPipelineQueryEngine.java
@@ -0,0 +1,185 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+package org.openecomp.aai.serialization.engines.query;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.query.builder.QueryBuilder;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.TransactionalGraph;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.gremlin.java.GremlinPipeline;
+import com.tinkerpop.pipes.IdentityPipe;
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.branch.LoopPipe;
+
+public class GremlinPipelineQueryEngine extends QueryEngine {
+
+ public GremlinPipelineQueryEngine(TransactionalGraphEngine graphEngine) {
+ super(graphEngine);
+ }
+
+ @Override
+ public List<Vertex> executeQuery(TransactionalGraph g, QueryBuilder query) {
+ List<Vertex> results = null;
+ Vertex start = query.getStart();
+ if (start != null) {
+ results = ((GremlinPipeline)query.getQuery()).cast(Vertex.class).toList();
+ } else {
+ GremlinPipeline pipe = new GremlinPipeline(g);
+ results = process(pipe, (GremlinPipeline)query.getQuery());
+
+ }
+ return results;
+ }
+
+ @Override
+ public List<Vertex> executeParentQuery(TransactionalGraph g, QueryBuilder query) {
+ List<Vertex> results = null;
+ Vertex start = query.getStart();
+ if (start != null) {
+ results = ((GremlinPipeline)query.getParentQuery()).cast(Vertex.class).toList();
+ } else {
+ GremlinPipeline pipe = new GremlinPipeline(g);
+ results = process(pipe, (GremlinPipeline)query.getParentQuery());
+
+ }
+ return results;
+ }
+
+ @Override
+ public List<Vertex> findParents(Vertex start) {
+ GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline(start).as("x").inE()
+ .has("isParent", true).outV().loop("x", new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() {
+
+ @Override
+ public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
+ GremlinPipeline<Vertex, Long> pipe = new GremlinPipeline<>(argument.getObject());
+ return pipe.inE().has("isParent", true).count() == 1 || argument.getLoops() < 100;
+ }
+
+ }, new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() {
+
+ @Override
+ public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
+ return true;
+ }
+
+ });
+
+ List<Vertex> results = pipe.toList();
+ results.add(0, start);
+ return results;
+ }
+
+ @Override
+ public List<Vertex> findChildren(Vertex start) {
+ Set<Vertex> seen = new HashSet<>();
+ seen.add(start);
+ GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline(start).as("x").outE().has("isParent", true).inV()
+ .except(seen).store(seen).loop("x", new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() {
+
+ @Override
+ public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
+ GremlinPipeline<Vertex, Long> pipe = new GremlinPipeline<>(argument.getObject());
+ return pipe.outE().has("isParent", true).count() >= 1 || argument.getLoops() < 100;
+ }
+
+ }, new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() {
+
+ @Override
+ public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
+ return true;
+ }
+
+ });
+
+ List<Vertex> results = pipe.toList();
+ results.add(0, start);
+ return results;
+ }
+
+ @Override
+ public List<Vertex> findDeletable(Vertex start) {
+ Set<Vertex> seen = new HashSet<>();
+ seen.add(start);
+ GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>(start).as("x").outE().or(
+ new GremlinPipeline(new IdentityPipe()).has("isParent", true),
+ new GremlinPipeline(new IdentityPipe()).has("hasDelTarget", true)).inV()
+ .except(seen).store(seen).loop("x", new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() {
+
+ @Override
+ public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
+ GremlinPipeline<Vertex, Long> pipe = new GremlinPipeline<>(argument.getObject());
+ return pipe.outE().or(
+ new GremlinPipeline(new IdentityPipe()).has("isParent", true),
+ new GremlinPipeline(new IdentityPipe()).has("hasDelTarget", true)).count() >= 1 || argument.getLoops() < 100;
+ }
+
+ }, new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() {
+
+ @Override
+ public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
+ return true;
+ }
+
+ });
+ List<Vertex> results = pipe.toList();
+ results.add(0, start);
+
+ return results;
+ }
+
+ private List<Vertex> process(GremlinPipeline start, GremlinPipeline pipe) {
+
+
+ return start.add(pipe).cast(Vertex.class).toList();
+ }
+
+ @Override
+ public List<Vertex> findRelatedVertices(Vertex start, Direction direction, String label, String nodeType) {
+ GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>(start);
+ switch (direction) {
+ case OUT:
+ pipe.out(label);
+ break;
+ case IN:
+ pipe.in(label);
+ break;
+ case BOTH:
+ pipe.both(label);
+ break;
+ default:
+ break;
+ }
+
+ pipe.has(AAIProperties.NODE_TYPE, nodeType).dedup();
+ List<Vertex> result = pipe.toList();
+ return result;
+ }
+
+}
+*/
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/QueryEngine.java b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/QueryEngine.java
new file mode 100644
index 00000000..bff6f082
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/engines/query/QueryEngine.java
@@ -0,0 +1,92 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.engines.query;
+
+import java.util.List;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.introspection.Loader;
+
+public abstract class QueryEngine {
+
+ final protected GraphTraversalSource g;
+
+ /**
+ * Instantiates a new query engine.
+ *
+ * @param graphEngine the graph engine
+ */
+ public QueryEngine (GraphTraversalSource g) {
+ this.g = g;
+ }
+
+ /**
+ * Find parents.
+ *
+ * @param start the start
+ * @return the list
+ */
+ public abstract List<Vertex> findParents(Vertex start);
+
+ /**
+ * Find children.
+ *
+ * @param start the start
+ * @return the list
+ */
+ public abstract List<Vertex> findAllChildren(Vertex start);
+
+ public abstract List<Vertex> findChildrenOfType(Vertex start, String type);
+ /**
+ * Find deletable.
+ *
+ * @param start the start
+ * @return the list
+ */
+ public abstract List<Vertex> findDeletable(Vertex start);
+
+ public Tree<Element> findSubGraph(Vertex start) {
+ return findSubGraph(start, AAIProperties.MAXIMUM_DEPTH, false);
+ }
+ public abstract Tree<Element> findSubGraph(Vertex start, int iterations, boolean nodeOnly);
+ /**
+ * Find related vertices.
+ *
+ * @param start the start
+ * @param direction the direction
+ * @param label the label
+ * @param nodeType the node type
+ * @return the list
+ */
+ public abstract List<Vertex> findRelatedVertices(Vertex start, Direction direction, String label, String nodeType);
+
+ public abstract List<Edge> findEdgesForVersion(Vertex start, Loader loader);
+
+ public abstract List<Vertex> findCousinVertices(Vertex start);
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Console.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Console.java
new file mode 100644
index 00000000..7aaf02c8
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Console.java
@@ -0,0 +1,42 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.queryformats;
+
+import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+import com.google.gson.JsonObject;
+
+public class Console implements FormatMapper {
+
+ @Override
+ public JsonObject formatObject(Object v) throws AAIFormatVertexException {
+
+ JsonObject json = new JsonObject();
+ json.addProperty("result", v.toString());
+
+ return json;
+ }
+
+ @Override
+ public int parallelThreshold() {
+ return 100;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Format.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Format.java
new file mode 100644
index 00000000..e3618917
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Format.java
@@ -0,0 +1,29 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.queryformats;
+
+public enum Format {
+ graphson,
+ pathed, id, resource,
+ simple,
+ resource_and_url,
+ console
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/FormatFactory.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/FormatFactory.java
new file mode 100644
index 00000000..d00b5cda
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/FormatFactory.java
@@ -0,0 +1,72 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.queryformats;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.queryformats.utils.UrlBuilder;
+
+public class FormatFactory {
+
+ private final Loader loader;
+ private final DBSerializer serializer;
+ private final UrlBuilder urlBuilder;
+ public FormatFactory (Loader loader, DBSerializer serializer) throws AAIException {
+ this.loader = loader;
+ this.serializer = serializer;
+ this.urlBuilder = new UrlBuilder(loader.getVersion(), serializer);
+ }
+
+ public Formatter get(Format format) throws AAIException {
+
+ Formatter formattter = null;
+
+ switch (format) {
+ case graphson :
+ formattter = new Formatter(new GraphSON());
+ break;
+ case pathed :
+ formattter = new Formatter(new PathedURL(loader, urlBuilder));
+ break;
+ case id :
+ formattter = new Formatter(new IdURL(loader, urlBuilder));
+ break;
+ case resource :
+ formattter = new Formatter(new Resource.Builder(loader, serializer, urlBuilder).build());
+ break;
+ case resource_and_url :
+ formattter = new Formatter(new Resource.Builder(loader, serializer, urlBuilder).includeUrl().build());
+ break;
+ case simple :
+ formattter = new Formatter(new SimpleFormat(urlBuilder));
+ break;
+ case console :
+ formattter = new Formatter(new Console());
+ break;
+ default :
+ break;
+ }
+
+ return formattter;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/FormatMapper.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/FormatMapper.java
new file mode 100644
index 00000000..def68e0f
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/FormatMapper.java
@@ -0,0 +1,31 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.queryformats;
+
+import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+import com.google.gson.JsonObject;
+
+public interface FormatMapper {
+
+ public JsonObject formatObject(Object v) throws AAIFormatVertexException;
+
+ public int parallelThreshold();
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Formatter.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Formatter.java
new file mode 100644
index 00000000..f2bafe24
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Formatter.java
@@ -0,0 +1,75 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.queryformats;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+public class Formatter {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(Formatter.class);
+
+ protected JsonParser parser = new JsonParser();
+ protected final FormatMapper format;
+ public Formatter(FormatMapper format) {
+ this.format = format;
+ }
+
+ public JsonObject output(List<Object> vertices) {
+ Stream<Object> stream = null;
+ JsonObject result = new JsonObject();
+ JsonArray body = new JsonArray();
+ if (vertices.size() >= format.parallelThreshold()) {
+ stream = vertices.parallelStream();
+ } else {
+ stream = vertices.stream();
+ }
+
+ stream.map(v -> {
+ try {
+ return Optional.<JsonObject>of(format.formatObject(v));
+ } catch (AAIFormatVertexException e) {
+ LOGGER.warn("Failed to format vertex, returning a partial list", e);
+ }
+
+ return Optional.<JsonObject>empty();
+ }).forEach(obj -> {
+ if (obj.isPresent()) {
+ synchronized (body) {
+ body.add(obj.get());
+ }
+ }
+ });
+
+ result.add("results", body);
+
+ return result.getAsJsonObject();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/GraphSON.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/GraphSON.java
new file mode 100644
index 00000000..69bd1b24
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/GraphSON.java
@@ -0,0 +1,63 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.queryformats;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONWriter;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.thinkaurelius.titan.graphdb.tinkerpop.TitanIoRegistry;
+
+public class GraphSON implements FormatMapper {
+
+ private final GraphSONMapper mapper = GraphSONMapper.build().addRegistry(TitanIoRegistry.INSTANCE).create();
+ private final GraphSONWriter writer = GraphSONWriter.build().mapper(mapper).create();
+ protected JsonParser parser = new JsonParser();
+
+ @Override
+ public JsonObject formatObject(Object v) {
+ OutputStream os = new ByteArrayOutputStream();
+ String result = "";
+ try {
+ writer.writeVertex(os, (Vertex)v, Direction.BOTH);
+
+ result = os.toString();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ return parser.parse(result).getAsJsonObject();
+
+ }
+
+ @Override
+ public int parallelThreshold() {
+ return 50;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/IdURL.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/IdURL.java
new file mode 100644
index 00000000..a7d641dd
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/IdURL.java
@@ -0,0 +1,71 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.queryformats;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+import org.openecomp.aai.serialization.queryformats.utils.UrlBuilder;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class IdURL implements FormatMapper {
+
+ private final UrlBuilder urlBuilder;
+ private final JsonParser parser;
+ private final Loader loader;
+
+ public IdURL (Loader loader, UrlBuilder urlBuilder) throws AAIException {
+ this.urlBuilder = urlBuilder;
+ this.parser = new JsonParser();
+ this.loader = loader;
+ }
+
+ @Override
+ public int parallelThreshold() {
+ return 2500;
+ }
+
+ @Override
+ public JsonObject formatObject(Object input) throws AAIFormatVertexException {
+ Vertex v = (Vertex)input;
+ try {
+ final Introspector searchResult = this.loader.introspectorFromName("result-data");
+
+ searchResult.setValue("resource-type", v.value(AAIProperties.NODE_TYPE));
+ searchResult.setValue("resource-link", this.urlBuilder.id(v));
+
+ final String json = searchResult.marshal(false);
+
+ return parser.parse(json).getAsJsonObject();
+
+ } catch (AAIUnknownObjectException e) {
+ throw new RuntimeException("Fatal error - result-data object does not exist!");
+ }
+
+
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/PathedURL.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/PathedURL.java
new file mode 100644
index 00000000..dda9f4af
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/PathedURL.java
@@ -0,0 +1,70 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.queryformats;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+import org.openecomp.aai.serialization.queryformats.utils.UrlBuilder;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public final class PathedURL implements FormatMapper {
+
+ private final UrlBuilder urlBuilder;
+ private final JsonParser parser;
+ private final Loader loader;
+
+ public PathedURL (Loader loader, UrlBuilder urlBuilder) throws AAIException {
+ this.urlBuilder = urlBuilder;
+ this.parser = new JsonParser();
+ this.loader = loader;
+ }
+
+ @Override
+ public int parallelThreshold() {
+ return 20;
+ }
+
+ @Override
+ public JsonObject formatObject(Object input) throws AAIFormatVertexException {
+ Vertex v = (Vertex)input;
+ try {
+ final Introspector searchResult = this.loader.introspectorFromName("result-data");
+
+ searchResult.setValue("resource-type", v.value(AAIProperties.NODE_TYPE));
+
+ searchResult.setValue("resource-link", this.urlBuilder.pathed(v));
+ final String json = searchResult.marshal(false);
+ return this.parser.parse(json).getAsJsonObject();
+
+ } catch (AAIUnknownObjectException e) {
+ throw new RuntimeException("Fatal error - result-data does not exist!", e);
+ }
+
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Resource.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Resource.java
new file mode 100644
index 00000000..7859719e
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/Resource.java
@@ -0,0 +1,142 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.queryformats;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+import org.openecomp.aai.serialization.queryformats.utils.UrlBuilder;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class Resource implements FormatMapper {
+
+ private final Loader loader;
+ private final DBSerializer serializer;
+ private final JsonParser parser;
+ private final UrlBuilder urlBuilder;
+ private final boolean includeUrl;
+
+ private Resource (Builder builder) {
+ this.parser = new JsonParser();
+ this.loader = builder.getLoader();
+ this.serializer = builder.getSerializer();
+ this.urlBuilder = builder.getUrlBuilder();
+ this.includeUrl = builder.isIncludeUrl();
+ }
+
+ @Override
+ public JsonObject formatObject(Object input) throws AAIFormatVertexException {
+ Vertex v = (Vertex)input;
+ JsonObject json = new JsonObject();
+
+ if (this.includeUrl) {
+ json.addProperty("url", this.urlBuilder.pathed(v));
+ }
+ json.add(v.<String>property(AAIProperties.NODE_TYPE)
+ .orElse(null), this.vertexToJsonObject(v));
+
+ return json;
+ }
+
+ protected JsonObject vertexToJsonObject(Vertex v) throws AAIFormatVertexException {
+ try {
+ final Introspector obj = getLoader().introspectorFromName(
+ v.<String>property(AAIProperties.NODE_TYPE)
+ .orElse(null)
+ );
+
+ final List<Vertex> wrapper = new ArrayList<>();
+
+ wrapper.add(v);
+
+ try {
+ getSerializer().dbToObject(wrapper, obj, 1, false, "false");
+ } catch (AAIException | UnsupportedEncodingException e) {
+ throw new AAIFormatVertexException("Failed to format vertex - error while serializing: " + e.getMessage(), e);
+ }
+
+ final String json = obj.marshal(false);
+
+ return getParser().parse(json).getAsJsonObject();
+ } catch (AAIUnknownObjectException e) {
+ throw new AAIFormatVertexException("Failed to format vertex - unknown object", e);
+ }
+ }
+
+ @Override
+ public int parallelThreshold() {
+ return 20;
+ }
+
+ private Loader getLoader() { return loader; }
+ private DBSerializer getSerializer() { return serializer; }
+ private JsonParser getParser() { return parser; }
+
+ public static class Builder {
+
+ private final Loader loader;
+ private final DBSerializer serializer;
+ private final UrlBuilder urlBuilder;
+ private boolean includeUrl = false;
+
+ public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder) {
+ this.loader = loader;
+ this.serializer = serializer;
+ this.urlBuilder = urlBuilder;
+ }
+
+ protected Loader getLoader() {
+ return this.loader;
+ }
+
+ protected DBSerializer getSerializer() {
+ return this.serializer;
+ }
+
+ protected UrlBuilder getUrlBuilder() {
+ return this.urlBuilder;
+ }
+
+ public Builder includeUrl() {
+ this.includeUrl = true;
+ return this;
+ }
+
+ protected boolean isIncludeUrl() {
+ return this.includeUrl;
+ }
+
+ public Resource build() {
+ return new Resource(this);
+ }
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/SimpleFormat.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/SimpleFormat.java
new file mode 100644
index 00000000..222b0922
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/SimpleFormat.java
@@ -0,0 +1,114 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.queryformats;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+import org.openecomp.aai.serialization.queryformats.utils.UrlBuilder;
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+
+public class SimpleFormat implements FormatMapper {
+
+ private final UrlBuilder urlBuilder;
+ private final Set<String> blacklist;
+ private final Collection<String> props = Arrays.asList(AAIProperties.AAI_URI, AAIProperties.NODE_TYPE);
+ public SimpleFormat(UrlBuilder urlBuilder) {
+ this.urlBuilder = urlBuilder;
+ this.blacklist = new HashSet<>();
+ blacklist.addAll(props);
+ }
+
+ @Override
+ public JsonObject formatObject(Object input) throws AAIFormatVertexException {
+ Vertex v = (Vertex)input;
+ JsonObject json = new JsonObject();
+ json.addProperty("id", v.id().toString());
+ json.addProperty("node-type", v.<String>value(AAIProperties.NODE_TYPE));
+ json.addProperty("url", this.urlBuilder.pathed(v));
+ json.add("properties", this.createPropertiesObject(v));
+ json.add("related-to", this.createRelationshipObject(v));
+
+ return json;
+ }
+
+ @Override
+ public int parallelThreshold() {
+ return 100;
+ }
+
+ private JsonObject createPropertiesObject(Vertex v) {
+ JsonObject json = new JsonObject();
+ Iterator<VertexProperty<Object>> iter = v.properties();
+
+ while (iter.hasNext()) {
+ VertexProperty<Object> prop = iter.next();
+ if (!blacklist.contains(prop.key())) {
+ if (prop.value() instanceof String) {
+ json.addProperty(prop.key(), (String)prop.value());
+ } else if (prop.value() instanceof Boolean) {
+ json.addProperty(prop.key(), (Boolean)prop.value());
+ } else if (prop.value() instanceof Number) {
+ json.addProperty(prop.key(), (Number)prop.value());
+ } else if (prop.value() instanceof List) {
+ Gson gson = new Gson();
+ String list = gson.toJson(prop.value());
+
+ json.addProperty(prop.key(), list);
+ } else {
+ //throw exception?
+ return null;
+ }
+ }
+ }
+
+ return json;
+ }
+
+ private JsonArray createRelationshipObject(Vertex v) throws AAIFormatVertexException {
+ JsonArray jarray = new JsonArray();
+ Iterator<Vertex> iter = v.vertices(Direction.BOTH);
+
+ while (iter.hasNext()) {
+ Vertex related = iter.next();
+
+ JsonObject json = new JsonObject();
+ json.addProperty("id", related.id().toString());
+ json.addProperty("node-type", related.<String>value(AAIProperties.NODE_TYPE));
+ json.addProperty("url", this.urlBuilder.pathed(related));
+ jarray.add(json);
+ }
+
+ return jarray;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/SubGraphStyle.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/SubGraphStyle.java
new file mode 100644
index 00000000..7fa30431
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/SubGraphStyle.java
@@ -0,0 +1,27 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.queryformats;
+
+public enum SubGraphStyle {
+ star,
+ prune,
+ no_op
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/exceptions/AAIFormatVertexException.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/exceptions/AAIFormatVertexException.java
new file mode 100644
index 00000000..692f4f65
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/exceptions/AAIFormatVertexException.java
@@ -0,0 +1,40 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.queryformats.exceptions;
+
+public class AAIFormatVertexException extends Exception {
+
+ private static final long serialVersionUID = -5814240841844624097L;
+
+ public AAIFormatVertexException() {}
+
+ public AAIFormatVertexException(String message) {
+ super(message);
+ }
+
+ public AAIFormatVertexException(Throwable cause) {
+ super(cause);
+ }
+
+ public AAIFormatVertexException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/utils/UrlBuilder.java b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/utils/UrlBuilder.java
new file mode 100644
index 00000000..1c79d24b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/queryformats/utils/UrlBuilder.java
@@ -0,0 +1,74 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.queryformats.utils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Version;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+import org.openecomp.aai.util.AAIApiServerURLBase;
+import org.openecomp.aai.workarounds.LegacyURITransformer;
+
+public class UrlBuilder {
+
+ private final DBSerializer serializer;
+ private final Version version;
+ private final String serverBase;
+
+ public UrlBuilder (Version version, DBSerializer serializer) throws AAIException {
+ this.serializer = serializer;
+ this.version = version;
+ this.serverBase = AAIApiServerURLBase.get(AAIProperties.LATEST);
+ }
+
+ public String pathed(Vertex v) throws AAIFormatVertexException {
+
+ try {
+ final StringBuilder result = new StringBuilder();
+ final URI uri = this.serializer.getURIForVertex(v);
+
+ result.append(this.serverBase);
+ result.append(this.version);
+ result.append(uri.getRawPath());
+
+ return result.toString();
+ } catch (UnsupportedEncodingException | IllegalArgumentException | SecurityException e) {
+ throw new AAIFormatVertexException(e);
+ }
+ }
+
+ public String id(Vertex v) {
+ final StringBuilder result = new StringBuilder();
+
+ result.append("/resources/id/" + v.id());
+ result.insert(0, this.version);
+ result.insert(0, this.serverBase);
+
+ return result.toString();
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/tinkerpop/TreeBackedEdge.java b/aai-core/src/main/java/org/openecomp/aai/serialization/tinkerpop/TreeBackedEdge.java
new file mode 100644
index 00000000..36fb6a87
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/tinkerpop/TreeBackedEdge.java
@@ -0,0 +1,80 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.tinkerpop;
+
+import java.util.Iterator;
+
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+
+
+/**
+ * Represents a {@link Edge} that is disconnected from a {@link Graph} however,
+ * traversals are supported as they are backed by a Tree with saturated {@link Vertex} and {@link Edge} objects.
+ * These objects are not mutable and can only be used to read information out.
+ *
+ */
+public class TreeBackedEdge extends DetachedEdge implements Edge {
+
+ private static final long serialVersionUID = 5419650145562077538L;
+ private TreeBackedVertex inVertex;
+ private TreeBackedVertex outVertex;
+ public TreeBackedEdge(Edge edge, TreeBackedVertex inVertex, TreeBackedVertex outVertex) {
+ super(edge, true);
+ this.inVertex = inVertex;
+ this.outVertex = outVertex;
+ }
+
+ @Override
+ public Vertex inVertex() {
+ return this.inVertex;
+ }
+
+ @Override
+ public Vertex outVertex() {
+ return this.outVertex;
+ }
+
+ @Override
+ public Iterator<Vertex> bothVertices() {
+ return this.vertices(Direction.BOTH);
+ }
+
+ @Override
+ public Iterator<Vertex> vertices(Direction direction) {
+ switch (direction) {
+ case OUT:
+ return IteratorUtils.of(this.outVertex);
+ case IN:
+ return IteratorUtils.of(this.inVertex);
+ default:
+ return IteratorUtils.of(this.outVertex, this.inVertex);
+ }
+ }
+
+
+
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/tinkerpop/TreeBackedVertex.java b/aai-core/src/main/java/org/openecomp/aai/serialization/tinkerpop/TreeBackedVertex.java
new file mode 100644
index 00000000..92655803
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/serialization/tinkerpop/TreeBackedVertex.java
@@ -0,0 +1,166 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.serialization.tinkerpop;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+
+/**
+ * Represents a {@link Vertex} that is disconnected from a {@link Graph} however,
+ * traversals are supported as they are backed by a Tree with saturated {@link Vertex} and {@link Edge} objects.
+ * These objects are not mutable and can only be used to read information out.
+ *
+ */
+
+public class TreeBackedVertex extends DetachedVertex implements Vertex {
+
+ private static final long serialVersionUID = -976854460992756953L;
+ private final Tree<Element> tree;
+ private final Vertex self;
+ public TreeBackedVertex (Vertex v, Tree<Element> tree) {
+ super(v, true);
+ this.self = v;
+ this.tree = tree;
+ }
+
+ @Override
+ public Iterator<Edge> edges(final Direction direction, final String... edgeLabels) {
+ final List<Element> edges = tree.getObjectsAtDepth(2);
+ final List<Tree<Element>> trees = tree.getTreesAtDepth(2);
+ final List<Tree<Element>> vTrees = tree.getTreesAtDepth(3);
+ return edges.stream().map( ele -> (Edge)ele).filter(e -> {
+ if (Direction.IN.equals(direction)) {
+ return e.inVertex().equals(self);
+ } else if (Direction.OUT.equals(direction)) {
+ return e.outVertex().equals(self);
+ } else {
+ return true;
+ }
+ }).filter(e -> {
+ boolean result = false;
+ if (edgeLabels.length == 0) {
+ return true;
+ }
+ for (String label : edgeLabels) {
+ if (label.equals(e.label())) {
+ result = true;
+ break;
+ }
+ }
+ return result;
+ }).map(e -> {
+ Tree<Element> eTree = new Tree<>();
+ for (Tree<Element> tree : trees) {
+ if (tree.keySet().contains(e)) {
+ eTree = tree;
+ break;
+ }
+ }
+ TreeBackedVertex in = null;
+ TreeBackedVertex out = null;
+ if (e.inVertex().equals(self)) {
+ in = this;
+ out = this.createForVertex(e.outVertex(), vTrees);
+ } else if (e.outVertex().equals(self)) {
+ out = this;
+ in = this.createForVertex(e.inVertex(), vTrees);
+ }
+ return (Edge)new TreeBackedEdge(e, in, out);
+ }).iterator();
+
+ }
+
+ private TreeBackedVertex createForVertex(Vertex v, List<Tree<Element>> trees) {
+ Tree<Element> vTree = new Tree<>();
+ for (Tree<Element> tree : trees) {
+ if (tree.keySet().contains(v)) {
+ vTree = tree;
+ break;
+ }
+ }
+
+ return new TreeBackedVertex((Vertex)vTree.keySet().iterator().next(), vTree);
+ }
+ @Override
+ public Iterator<Vertex> vertices(final Direction direction, final String... labels) {
+ final List<Tree<Element>> vertexElements = tree.getTreesAtDepth(3);
+ final List<Element> edgeElements = tree.getObjectsAtDepth(2);
+ return edgeElements.stream().map( ele -> (Edge)ele).filter(e -> {
+ boolean result = false;
+ if (labels.length == 0) {
+ return true;
+ }
+ for (String label : labels) {
+ if (label.equals(e.label())) {
+ result = true;
+ break;
+ }
+ }
+ return result;
+ }).filter(e -> {
+ if (Direction.IN.equals(direction) && e.inVertex().equals(self)) {
+ return true;
+ } else if (Direction.OUT.equals(direction) && e.outVertex().equals(self)) {
+ return true;
+ } else if (Direction.BOTH.equals(direction)){
+ return true;
+ } else {
+ return false;
+ }
+ }).map(e -> {
+ final List<Vertex> list;
+ if (Direction.IN.equals(direction)) {
+ list = Collections.singletonList(e.outVertex());
+ } else if (Direction.OUT.equals(direction)){
+ list = Collections.singletonList(e.inVertex());
+ } else {
+ list = new ArrayList<>();
+ Iterator<Vertex> itr = e.bothVertices();
+ while (itr.hasNext()) {
+ list.add(itr.next());
+ }
+ }
+ return list;
+
+ }).flatMap(list -> list.stream()).map(v -> {
+ Tree<Element> vTree = new Tree<Element>();
+ for (Tree<Element> tree : vertexElements) {
+ if (tree.keySet().contains(v)) {
+ vTree = tree;
+ break;
+ }
+ }
+
+ return (Vertex)new TreeBackedVertex(v, vTree);
+ }).iterator();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/tasks/ScheduledTasks.java b/aai-core/src/main/java/org/openecomp/aai/tasks/ScheduledTasks.java
new file mode 100644
index 00000000..7cb17cf8
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/tasks/ScheduledTasks.java
@@ -0,0 +1,90 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.tasks;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.UUID;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.comparator.LastModifiedFileComparator;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import org.openecomp.aai.logging.LoggingContext;
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+@Component
+public class ScheduledTasks {
+
+ private static EELFLogger LOGGER = EELFManager.getInstance().getLogger(ScheduledTasks.class);
+
+ private static final String COMPONENT = "Scheduler";
+ private static final String FROM_APP_ID = "CronApp";
+ private static final long PROPERTY_READ_INTERVAL = 60000; // every minute
+
+ private String GlobalPropFileName = AAIConstants.AAI_CONFIG_FILENAME;
+
+ // for read and possibly reloading aaiconfig.properties and other
+ /**
+ * Load AAI properties.
+ */
+ // configuration properties files
+ @Scheduled(fixedRate = PROPERTY_READ_INTERVAL)
+ public void loadAAIProperties() {
+ final UUID transId = UUID.randomUUID();
+
+ LoggingContext.requestId(transId);
+ LoggingContext.partnerName(FROM_APP_ID);
+ LoggingContext.component(COMPONENT);
+
+ String dir = FilenameUtils.getFullPathNoEndSeparator(GlobalPropFileName);
+ if (dir == null || dir.length() < 3) {
+ dir = "/opt/aai/etc";
+ }
+
+ File pdir = new File(dir);
+ File[] files = pdir.listFiles();
+ Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
+ String fn;
+
+ // leave this loop here since we may want to check other configurable
+ // property files in the SAME directory
+ for (File file : files) {
+ fn = file.getName();
+ if (fn.equals("aaiconfig.properties")) {
+ Date lastMod = new Date(file.lastModified());
+ long lastModTm = lastMod.getTime();
+ Date curTS = new Date();
+ long curTSTm = curTS.getTime();
+ if (curTSTm - lastModTm < PROPERTY_READ_INTERVAL + 1000) {
+ AAIConfig.reloadConfig();
+ LOGGER.info("reloaded from aaiconfig.properties");
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIApiServerURLBase.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIApiServerURLBase.java
new file mode 100644
index 00000000..da3bb11e
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIApiServerURLBase.java
@@ -0,0 +1,80 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.PhaseInterceptorChain;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Version;
+
+public class AAIApiServerURLBase {
+
+ /**
+ * Gets the.
+ *
+ * @return the string
+ * @throws AAIException the AAI exception
+ */
+ public static String get() throws AAIException {
+
+ String hostName = null;
+ try {
+ Message message = PhaseInterceptorChain.getCurrentMessage();
+ Map<String, List<String>> headers = CastUtils.cast((Map) message.get(Message.PROTOCOL_HEADERS));
+ List sa = null;
+ if (headers != null) {
+ sa = headers.get("host");
+ }
+
+ if (sa != null && sa.size() == 1) {
+ hostName = "https://"+ sa.get(0).toString() + "/aai/";
+ }
+ } catch (Exception e) {
+ // TODO: we may want to log an error here
+ }
+ // TODO: should this check the value a little closer and look for a pattern?
+ if (hostName == null) {
+ hostName = AAIConfig.get(AAIConstants.AAI_SERVER_URL_BASE);
+ //AAIConstants.AAI_SERVER_URL_BASE;
+ }
+ return hostName;
+ }
+
+ /**
+ * Gets the.
+ *
+ * @param v the v
+ * @return the string
+ * @throws AAIException the AAI exception
+ */
+ public static String get(Version v) throws AAIException {
+ String hostName = null;
+ hostName = AAIApiServerURLBase.get();
+
+ return hostName;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIApiVersion.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIApiVersion.java
new file mode 100644
index 00000000..56687244
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIApiVersion.java
@@ -0,0 +1,74 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.PhaseInterceptorChain;
+
+import org.openecomp.aai.exceptions.AAIException;
+
+public class AAIApiVersion {
+
+ private static final Pattern versionPattern = Pattern.compile("(^|\\/)(v\\d+)\\/");
+
+ private static final Pattern latestVersionPattern = Pattern.compile("(^|\\/)(latest)\\/");
+
+ /**
+ * Gets the.
+ *
+ * @return the string
+ * @throws AAIException the AAI exception
+ */
+ public static String get() throws AAIException {
+
+ String apiVersion = null;
+ try {
+ Message message = PhaseInterceptorChain.getCurrentMessage();
+ String requestURI = (String) message.get(Message.REQUEST_URI);
+
+ if (requestURI != null) {
+ Matcher matcher = versionPattern.matcher(requestURI);
+ if (matcher.find() && matcher.groupCount() >= 2) {
+ apiVersion = matcher.group(2);
+ }
+ if (apiVersion == null) {
+ Matcher latestMatcher = latestVersionPattern.matcher(requestURI);
+ if (latestMatcher.find() && latestMatcher.groupCount() >= 2) {
+ apiVersion = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP, AAIConstants.AAI_DEFAULT_API_VERSION);
+ }
+ }
+
+ }
+
+ } catch (Exception e) {
+ // TODO: we may want to log an error here
+ }
+ // TODO: should this check the value a little closer and look for a pattern?
+ if (apiVersion == null || !apiVersion.startsWith("v")) {
+ apiVersion = AAIConfig.get (AAIConstants.AAI_DEFAULT_API_VERSION_PROP, AAIConstants.AAI_DEFAULT_API_VERSION);
+ //apiVersion = AAIConstants.AAI_DEFAULT_API_VERSION;
+ }
+ return apiVersion;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAICSVWriter.java b/aai-core/src/main/java/org/openecomp/aai/util/AAICSVWriter.java
new file mode 100644
index 00000000..63383194
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/AAICSVWriter.java
@@ -0,0 +1,167 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ *
+ */
+package org.openecomp.aai.util;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+import com.opencsv.CSVWriter;
+
+/**
+ * had to overwrite the separate character to separate string
+ * Based on the public - A very simple CSV writer released under a commercial-friendly license.
+ *
+
+ */
+public class AAICSVWriter extends CSVWriter {
+
+ private String separatorStr;
+ private char overridequotechar;
+ private String overridelineEnd;
+ private Writer rawWriter;
+ private PrintWriter pw;
+
+ /**
+ * Instantiates a new AAICSV writer.
+ *
+ * @param writer the writer
+ */
+ public AAICSVWriter(Writer writer) {
+ super(writer);
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * Constructs AAICSVWriter with supplied separator string and quote char.
+ *
+ * @param writer the writer to an underlying CSV source.
+ * @param overrideseparator the overrideseparator
+ * @param quotechar the character to use for quoted elements
+ * @param lineEnd the line feed terminator to use
+ */
+ public AAICSVWriter(Writer writer, String overrideseparator, char quotechar, String lineEnd) {
+ super(writer, CSVWriter.DEFAULT_SEPARATOR, quotechar, DEFAULT_ESCAPE_CHARACTER, lineEnd);
+ separatorStr = overrideseparator;
+ overridequotechar = quotechar;
+ overridelineEnd = lineEnd;
+ this.rawWriter = writer;
+ this.pw = new PrintWriter(writer);
+ }
+
+ /**
+ * String contains special characters.
+ *
+ * @param line the line
+ * @return true, if successful
+ */
+ private boolean stringContainsSpecialCharacters(String line) {
+ return line.indexOf(overridequotechar) != -1 || line.indexOf(DEFAULT_ESCAPE_CHARACTER) != -1 || line.indexOf(separatorStr) != -1 || line.contains("\n") || line.contains("\r");
+ }
+
+ /**
+ * Close the underlying stream writer flushing any buffered content.
+ *
+ * @throws IOException if bad things happen
+ */
+ public void close() throws IOException {
+ flush();
+ pw.close();
+ rawWriter.close();
+ }
+
+ /**
+ * Writes the next line to the file.
+ *
+ * @param nextLine a string array with each comma-separated element as a separate
+ * entry.
+ * @param applyQuotesToAll true if all values are to be quoted. false applies quotes only
+ * to values which contain the separator, escape, quote or new line characters.
+ */
+ public void writeNext(String[] nextLine, boolean applyQuotesToAll) {
+
+ if (nextLine == null)
+ return;
+
+ StringBuilder sb = new StringBuilder(INITIAL_STRING_SIZE);
+ for (int i = 0; i < nextLine.length; i++) {
+
+ if (i != 0) {
+ sb.append(separatorStr);
+ }
+
+ String nextElement = nextLine[i];
+
+ if (nextElement == null)
+ continue;
+
+ Boolean stringContainsSpecialCharacters = stringContainsSpecialCharacters(nextElement);
+
+ if ((applyQuotesToAll || stringContainsSpecialCharacters) && overridequotechar != NO_QUOTE_CHARACTER)
+ sb.append(overridequotechar);
+
+ if (stringContainsSpecialCharacters) {
+ sb.append(processLine(nextElement));
+ } else {
+ sb.append(nextElement);
+ }
+
+ if ((applyQuotesToAll || stringContainsSpecialCharacters) && overridequotechar != NO_QUOTE_CHARACTER)
+ sb.append(overridequotechar);
+ }
+
+ sb.append(overridelineEnd);
+ pw.write(sb.toString());
+ }
+
+
+ /**
+ * Writes the next line to the file ignoring all exceptions.
+ *
+ * @param nextLine a string array with each comma-separated element as a separate
+ * entry.
+ */
+ public void writeColumn(String[] nextLine) {
+
+ if (nextLine == null)
+ return;
+
+ StringBuilder sb = new StringBuilder(INITIAL_STRING_SIZE);
+ for (int i = 0; i < nextLine.length; i++) {
+
+
+ String nextElement = nextLine[i];
+
+ if (nextElement == null)
+ continue;
+
+ sb.append(nextElement);
+
+
+ }
+
+ sb.append(overridelineEnd);
+ pw.write(sb.toString());
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIConfig.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIConfig.java
new file mode 100644
index 00000000..eaea46e3
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIConfig.java
@@ -0,0 +1,265 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.eclipse.jetty.util.security.Password;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.logging.ErrorLogHelper;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.Timer;
+
+
+public class AAIConfig {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIConfig.class);
+ private static final String GLOBAL_PROP_FILE_NAME = AAIConstants.AAI_CONFIG_FILENAME;
+ private static Properties serverProps;
+ private static boolean propsInitialized = false;
+
+ // this (probably) won't change between releases, put it in the config if it gets annoying...
+ private static HashMap<String,ArrayList<String>> defaultBools = new HashMap<String,ArrayList<String>>();
+ private static Timer timer = new Timer();
+
+ /**
+ * Instantiates a new AAI config.
+ */
+ // Don't instantiate
+ private AAIConfig() {}
+
+ /**
+ * Inits the.
+ *
+ * @throws AAIException the AAI exception
+ */
+ public synchronized static void init() throws AAIException {
+ LOGGER.info("Initializing AAIConfig");
+
+ ArrayList<String> genericVnfBools = new ArrayList<String>();
+ ArrayList<String> l3NetworkBools = new ArrayList<String>();
+ ArrayList<String> pserverBools = new ArrayList<String>();
+ ArrayList<String> subnetBools = new ArrayList<String>();
+ ArrayList<String> vserverBools = new ArrayList<String>();
+ ArrayList<String> vnfcBools = new ArrayList<String>();
+
+ genericVnfBools.add("in-maint");
+ genericVnfBools.add("is-closed-loop-disabled");
+ l3NetworkBools.add("is-bound-to-vpn");
+ pserverBools.add("in-maint");
+ subnetBools.add("dhcp-enabled");
+ vserverBools.add("in-maint");
+ vserverBools.add("is-closed-loop-disabled");
+ vnfcBools.add("in-maint");
+ vnfcBools.add("is-closed-loop-disabled");
+
+ defaultBools.put("generic-vnf", genericVnfBools);
+ defaultBools.put("l3-network", l3NetworkBools);
+ defaultBools.put("pserver", pserverBools);
+ defaultBools.put("subnet", subnetBools);
+ defaultBools.put("vserver", vserverBools);
+ defaultBools.put("vnfc", vnfcBools);
+
+ AAIConfig.getConfigFile();
+ AAIConfig.reloadConfig();
+
+ if (AAIConstants.AAI_NODENAME == null || AAIConstants.AAI_NODENAME == "") {
+ ErrorLogHelper.logError("AAI_4005", " AAI_NODENAME is not defined");
+ } else {
+ LOGGER.info("A&AI Server Node Name = " + AAIConstants.AAI_NODENAME);
+ }
+ }
+
+ /**
+ * Gets the default bools.
+ *
+ * @return the default bools
+ */
+ public static HashMap<String,ArrayList<String>> getDefaultBools() {
+ return defaultBools;
+ }
+
+ /**
+ * Cleanup.
+ */
+ public static void cleanup() {
+ timer.cancel();
+ }
+
+ /**
+ * Gets the config file.
+ *
+ * @return the config file
+ */
+ public static String getConfigFile() {
+// if (GlobalPropFileName == null) {
+// String nc = System.getProperty("aaiconfig");
+// if (nc == null) nc = "/home/aaiadmin/etc/aaiconfig.props";
+// logger.info( "aaiconfig = " + nc==null?"null":nc);
+// GlobalPropFileName = nc;
+// }
+ return GLOBAL_PROP_FILE_NAME;
+ }
+
+ /**
+ * Reload config.
+ */
+ public synchronized static void reloadConfig() {
+
+ String propFileName = GLOBAL_PROP_FILE_NAME;
+ Properties newServerProps = null;
+
+ LOGGER.info("Reloading config from " + propFileName);
+
+ try {
+ InputStream is = new FileInputStream(propFileName);
+ newServerProps = new Properties();
+ newServerProps.load(is);
+ propsInitialized = true;
+
+ serverProps = newServerProps;
+ newServerProps = null;
+
+ } catch (FileNotFoundException fnfe) {
+ ErrorLogHelper.logError("AAI_4001", " " + propFileName + ". Exception: "+fnfe.getMessage());
+ } catch (IOException e) {
+ ErrorLogHelper.logError("AAI_4002", " " + propFileName + ". IOException: "+e.getMessage());
+ }
+ }
+
+ /**
+ * Gets the.
+ *
+ * @param key the key
+ * @param defaultValue the default value
+ * @return the string
+ */
+ public static String get(String key, String defaultValue) {
+ String result = defaultValue;
+ try {
+ result = get (key);
+ }
+ catch ( AAIException a ) {
+
+ }
+ return ( result );
+ }
+
+ /**
+ * Gets the.
+ *
+ * @param key the key
+ * @return the string
+ * @throws AAIException the AAI exception
+ */
+ public static String get(String key) throws AAIException {
+ String response = null;
+
+ if (key.equals(AAIConstants.AAI_NODENAME)) {
+ // Get this from InetAddress rather than the properties file
+ String nodeName = getNodeName();
+ if (nodeName != null) {
+ return nodeName;
+ }
+ // else get from property file
+ }
+
+ if (!propsInitialized || (serverProps == null)) {
+ reloadConfig();
+ }
+
+ if ((key.endsWith("password") || key.endsWith("passwd") || key.endsWith("apisecret")) && serverProps.containsKey(key+".x")) {
+ String valx = serverProps.getProperty(key+".x");
+ return Password.deobfuscate(valx);
+ }
+
+ if (!serverProps.containsKey(key)) {
+ throw new AAIException("AAI_4005", "Property key "+key+" cannot be found");
+ } else {
+ response = serverProps.getProperty(key);
+ if (response == null || response.isEmpty()) {
+ throw new AAIException("AAI_4005", "Property key "+key+" is null or empty");
+ }
+ }
+ return response;
+ }
+
+ /**
+ * Gets the int.
+ *
+ * @param key the key
+ * @return the int
+ * @throws AAIException the AAI exception
+ */
+ public static int getInt(String key) throws AAIException {
+ return Integer.valueOf(AAIConfig.get(key));
+ }
+
+ /**
+ * Gets the server props.
+ *
+ * @return the server props
+ */
+ public static Properties getServerProps() {
+ return serverProps;
+ }
+
+ /**
+ * Gets the node name.
+ *
+ * @return the node name
+ */
+ public static String getNodeName() {
+ try {
+ InetAddress ip = InetAddress.getLocalHost();
+ if (ip != null) {
+ String hostname = ip.getHostName();
+ if (hostname != null) {
+ return hostname;
+ }
+ }
+ } catch (Exception e) {
+ return null;
+ }
+ return null;
+ }
+
+
+ /**
+ * Check if a null or an Empty string is passed in.
+ *
+ * @param s the s
+ * @return boolean
+ */
+ public static boolean isEmpty(String s)
+ {
+ return (s == null || s.length() == 0);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIConfigCommandLinePropGetter.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIConfigCommandLinePropGetter.java
new file mode 100644
index 00000000..8844e824
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIConfigCommandLinePropGetter.java
@@ -0,0 +1,66 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import org.openecomp.aai.exceptions.AAIException;
+
+/*
+ * The script deobfuscatePW.sh needs to retrieve pws from the AAIConfig file.
+ * As AAIConfig has no main to be callable on the command line, this class helps
+ * by providing one for accessing AAIConfig that way.
+ * (AAIConfig deobfuscates pws itself, so we just need to call its .get() on the desired pw.)
+ *
+ * This could be used to get any property from AAIConfig via the command line,
+ * not just the pws, even though it was made for pw-related needs.
+ */
+public class AAIConfigCommandLinePropGetter {
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ /*
+ * usage:
+ * AAIConfigCommandLinePropGetter propertyname
+ */
+ public static void main(String[] args) {
+ if (args.length != 1) {
+ System.out.println("only one property may be requested at a time");
+ System.out.println("usage: AAIConfigCommandLinePropGetter propertyname");
+ }
+ try {
+ AAIConfig.init();
+ String value = AAIConfig.get(args[0]);
+ if (value != null) {
+ System.out.println(value); //bc this utility used by a shell script so it needs the result sent to stdout
+ } else {
+ System.out.println("requested property could not be found");
+ }
+ } catch(AAIException e) {
+ System.out.println("exception:" + e.toString()); //TODO is this reasonable?
+ } finally {
+ System.exit(0);
+ }
+
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIConstants.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIConstants.java
new file mode 100644
index 00000000..825a5eba
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIConstants.java
@@ -0,0 +1,153 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+public final class AAIConstants {
+
+ //
+ //
+ /** Default to unix file separator if system property file.separator is null */
+ public static final String AAI_FILESEP = (System.getProperty("file.separator") == null) ? "/" : System.getProperty("file.separator");
+ //
+ /** Default to opt aai if system property aai.home is null, using file.separator */
+ public static final String AAI_HOME = (System.getProperty("AJSC_HOME") == null) ? AAI_FILESEP + "opt" + AAI_FILESEP + "app" + AAI_FILESEP +"aai" : System.getProperty("AJSC_HOME");
+ public static final String AAI_BUNDLECONFIG_NAME = (System.getProperty("BUNDLECONFIG_DIR") == null) ? "bundleconfig" : System.getProperty("BUNDLECONFIG_DIR");
+ public static final String AAI_HOME_BUNDLECONFIG = (System.getProperty("AJSC_HOME") == null) ? AAI_FILESEP + "opt" + AAI_FILESEP + "app" + AAI_FILESEP + "aai" + AAI_FILESEP + AAI_BUNDLECONFIG_NAME : System.getProperty("AJSC_HOME")+ AAI_FILESEP + AAI_BUNDLECONFIG_NAME;
+
+ /** etc directory, relative to AAI_HOME */
+ public static final String AAI_HOME_ETC = AAI_HOME_BUNDLECONFIG + AAI_FILESEP + "etc" + AAI_FILESEP;
+ public static final String AAI_HOME_ETC_APP_PROPERTIES = AAI_HOME_ETC + "appprops" + AAI_FILESEP;
+ public static final String AAI_V2_OUTPUT_TRANSFORMS = AAIConstants.AAI_HOME_ETC_APP_PROPERTIES + AAIConstants.AAI_FILESEP + "output" + AAIConstants.AAI_FILESEP;
+ public static final String AAI_HOME_ETC_AUTH = AAI_HOME_ETC + "auth" + AAI_FILESEP;
+ public static final String AAI_CONFIG_FILENAME = AAI_HOME_ETC_APP_PROPERTIES + "aaiconfig.properties";
+ public static final String AAI_AUTH_CONFIG_FILENAME = AAI_HOME_ETC_AUTH + "aai_policy.json";
+ public static final String AAI_MECHID_CONFIG_FILENAME = AAI_HOME_ETC_APP_PROPERTIES + "mechIds.json";
+ public static final String AAI_HOME_ETC_QUERY = AAI_HOME_ETC + "query" + AAI_FILESEP + "stored-queries.properties";
+ public static final String REALTIME_DB_CONFIG = AAI_HOME_ETC_APP_PROPERTIES + "titan-realtime.properties";
+ public static final String CACHED_DB_CONFIG = AAI_HOME_ETC_APP_PROPERTIES + "titan-cached.properties";
+ public static final String AAI_HOME_ETC_OXM = AAI_HOME_ETC + "oxm" + AAI_FILESEP;
+ public static final String AAI_EVENT_DMAAP_PROPS = AAI_HOME_ETC_APP_PROPERTIES + "aaiEventDMaaPPublisher.properties";
+
+ public static final String AAI_PROV_LOGBACK_PROPS = "prov-logback.xml";
+ public static final String AAI_GETRES_LOGBACK_PROPS = "getres-logback.xml";
+ public static final String AAI_DELTOOL_LOGBACK_PROPS = "deltool-logback.xml";
+ public static final String AAI_UPDTOOL_LOGBACK_PROPS = "updtool-logback.xml";
+ public static final String AAI_PUTTOOL_LOGBACK_PROPS = "puttool-logback.xml";
+ public static final String AAI_POSTTOOL_LOGBACK_PROPS = "posttool-logback.xml";
+ public static final String AAI_NOTIFYSDNCTOOL_LOGBACK_PROPS = "notifysdnctool-logback.xml";
+ public static final String AAI_RSHIPTOOL_LOGBACK_PROPS = "rshiptool-logback.xml";
+ public static final String AAI_LOGBACK_PROPS = "logback.xml";
+
+
+ public static final String AAI_CREATE_DB_SCHEMA_LOGBACK_PROPS = "createDBSchema-logback.xml";
+ public static final String AAI_PULL_INV_DATA_LOGBACK_PROPS = "pullInvData-logback.xml";
+ public static final String AAI_DATA_GROOMING_LOGBACK_PROPS = "dataGrooming-logback.xml";
+ public static final String AAI_DATA_SNAPSHOT_LOGBACK_PROPS = "dataSnapshot-logback.xml";
+ public static final String AAI_SCHEMA_MOD_LOGBACK_PROPS = "schemaMod-logback.xml";
+ public static final String AAI_FORCE_DELETE_LOGBACK_PROPS = "forceDelete-logback.xml";
+
+ public static final String AAI_LOAD_DATA_DHV_LOGBACK_PROPS = "loadDataForDHV-logback.xml";
+
+ public static final String AVPN_INTERIM_LAG_INTERFACE = "aai.avpn.interim.laginterface";
+
+ public static final String AAI_TRUSTSTORE_FILENAME = "aai.truststore.filename";
+ public static final String AAI_TRUSTSTORE_PASSWD = "aai.truststore.passwd";
+ public static final String AAI_KEYSTORE_FILENAME = "aai.keystore.filename";
+ public static final String AAI_KEYSTORE_PASSWD = "aai.keystore.passwd";
+
+ public static final String AAI_OLDSERVER_URL_BASE = "aai.oldserver.url.base";
+ public static final String AAI_SERVER_URL_BASE = "aai.server.url.base";
+ public static final String AAI_SERVER_URL = "aai.server.url";
+ public static final String AAI_OLDSERVER_URL = "aai.oldserver.url";
+ public static final String AAI_GLOBAL_CALLBACK_URL = "aai.global.callback.url";
+
+ public static final String AAI_DEFAULT_API_VERSION = "v7";
+ public static final String AAI_DEFAULT_API_VERSION_PROP = "aai.default.api.version";
+ public static final String AAI_NOTIFICATION_CURRENT_VERSION = "aai.notification.current.version";
+
+ public static final String AAI_NODENAME = "aai.config.nodename";
+
+ public static final String AAI_LOGGING_HBASE_INTERCEPTOR = "aai.logging.hbase.interceptor";
+ public static final String AAI_LOGGING_HBASE_ENABLED = "aai.logging.hbase.enabled";
+ public static final String AAI_LOGGING_HBASE_LOGREQUEST = "aai.logging.hbase.logrequest";
+ public static final String AAI_LOGGING_HBASE_LOGRESPONSE = "aai.logging.hbase.logresponse";
+
+ public static final String AAI_LOGGING_TRACE_ENABLED = "aai.logging.trace.enabled";
+ public static final String AAI_LOGGING_TRACE_LOGREQUEST = "aai.logging.trace.logrequest";
+ public static final String AAI_LOGGING_TRACE_LOGRESPONSE = "aai.logging.trace.logresponse";
+
+ public static final String AAI_CONFIG_CHECKINGTIME = "aai.config.checktime";
+ public static final String AAI_DBMODEL_FILENAME = "aai.dbmodel.filename";
+ public static final String AAI_RESVERSION_ENABLEFLAG = "aai.resourceversion.enableflag";
+
+ public static final String ECM_OPENSTACK_TENANTID = "ecm.openstack.tenantid";
+
+ public static final String HBASE_TABLE_NAME = "hbase.table.name";
+ public static final String HBASE_NOTIFICATION_TABLE_NAME = "hbase.notificationTable.name";
+ public static final String HBASE_TABLE_TIMESTAMP_FORMAT = "hbase.table.timestamp.format";
+ public static final String HBASE_CONFIGURATION_ZOOKEEPER_QUORUM = "hbase.zookeeper.quorum";
+ public static final String HBASE_CONFIGURATION_ZOOKEEPER_CLIENTPORT = "hbase.zookeeper.property.clientPort";
+ public static final String HBASE_ZOOKEEPER_ZNODE_PARENT = "hbase.zookeeper.znode.parent";
+ public static final String ZOOKEEPER_ZNODE_PARENT = "zookeeper.znode.parent";
+
+ public static final int AAI_MAX_TRANS_RETRIES = 5;
+ public static final long AAI_TRANS_RETRY_SLEEP_MSEC = 500;
+
+ public static final int AAI_GROOMING_DEFAULT_MAX_FIX = 150;
+ public static final int AAI_GROOMING_DEFAULT_SLEEP_MINUTES = 7;
+
+ public static final int AAI_DUPETOOL_DEFAULT_MAX_FIX = 25;
+ public static final int AAI_DUPETOOL_DEFAULT_SLEEP_MINUTES = 7;
+
+ public static final String LOGGING_MAX_STACK_TRACE_ENTRIES = "aai.logging.maxStackTraceEntries";
+
+ /** Default to skipping real-time grooming unless system property aai.skiprealtime.grooming is set to "false" */
+ public static final String AAI_SKIPREALTIME_GROOMING = (System.getProperty("aai.skiprealtime.grooming") == null) ? "true" : System.getProperty("aai.skiprealtime.grooming");
+
+
+ /*** UEB ***/
+ public static final String UEB_PUB_PARTITION_AAI = "AAI";
+ public static final String UEB_PUB_AAI_VCE_INTERFACE_DATA_TOPIC = "ueb.pub.aai.vce.interface.data.topic";
+
+
+ /** Service description for Hosted Communications */
+ public static final String AAI_SERVICEDESCRIPTION_HOSTEDCOMM = "aai.servicedescription.hostedcomm";
+
+ /** Service description for Mobility */
+ public static final String AAI_SERVICEDESCRIPTION_MOBILITY = "aai.servicedescription.mobility";
+
+ /** Service description for Mobility */
+ public static final String AAI_SERVICEDESCRIPTION_VUSP = "aai.servicedescription.vusp";
+
+ /** Service description for Vvig */
+ public static final String AAI_SERVICEDESCRIPTION_VVIG = "aai.servicedescription.vvig";
+
+ /** Service description for LRSI */
+ public static final String AAI_SERVICEDESCRIPTION_LRSI = "aai.servicedescription.lrsi";
+
+ /**
+ * Instantiates a new AAI constants.
+ */
+ private AAIConstants() {
+ // prevent instantiation
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIMechIdConfig.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIMechIdConfig.java
new file mode 100644
index 00000000..1d0cd74a
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIMechIdConfig.java
@@ -0,0 +1,129 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Set;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+
+import org.openecomp.aai.logging.ErrorLogHelper;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+public class AAIMechIdConfig {
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIMechIdConfig.class);
+ private static final String mechIdConfigFileName = AAIConstants.AAI_HOME_ETC_APP_PROPERTIES + "mechid-config.json";
+
+ public static final String SYSTEM_GFP_IP = "GFP";
+ public static final String SYSTEM_GCP = "GCP";
+ public static final String SYSTEM_DCAE = "DCAE";
+ public static final String SYSTEM_RUBY = "RUBY";
+ public static final String SYSTEM_ACTION = "ACTION";
+ public static final String SYSTEM_INSTAR = "INSTAR-LPP-AMS";
+ public static final String FILE_CLASS_GFP_IP = "GFP-IP";
+ public static final String FILE_CLASS_INSTAR = "INSTAR-LPP-AMS";
+
+ public static HashMap<String, String> mechIdtoSystem = new HashMap<String, String>();
+ public static HashMap<String, ArrayList<String>> fileClassToMechId = new HashMap<String, ArrayList<String>>();
+
+ /**
+ * Inits the.
+ *
+ * @param tId the t id
+ * @param appId the app id
+ * @param logger the logger
+ */
+ public static void init() {
+ LOGGER.debug("Initializing AAIMechIdConfig");
+ Boolean enable;
+ String systemMechId = "";
+ JSONParser parser = new JSONParser();
+
+ try {
+ Object obj = parser.parse(new FileReader(mechIdConfigFileName));
+ JSONObject jsonObject = (JSONObject) obj;
+ JSONObject mechIds = (JSONObject) jsonObject.get("mech-ids");
+
+ @SuppressWarnings("unchecked")
+ Set<String> systemSet = mechIds.keySet();
+ for (String system : systemSet) {
+ JSONObject systemJsonObj = (JSONObject) mechIds.get(system);
+ systemMechId = (String) systemJsonObj.get("mechid");
+ enable = (Boolean) systemJsonObj.get("enable");
+ if (systemMechId != null && !systemMechId.isEmpty() && enable != null && enable == true) {
+ mechIdtoSystem.put(systemMechId, system);
+ JSONArray fileClasses = (JSONArray) systemJsonObj.get("file-classes");
+ if (fileClasses != null ) {
+ String fileClass = "";
+ for (Object fileClassObj : fileClasses) {
+ fileClass = (String) fileClassObj;
+
+ if (!fileClassToMechId.containsKey(fileClass)) {
+ fileClassToMechId.put(fileClass, new ArrayList<String>());
+ fileClassToMechId.get(fileClass).add(systemMechId);
+ } else {
+ if(!fileClassToMechId.get(fileClass).contains(systemMechId)){
+ fileClassToMechId.get(fileClass).add(systemMechId);
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+ } catch (FileNotFoundException fnfe) {
+ ErrorLogHelper.logError("AAI_4001",
+ " " + mechIdConfigFileName + ". Exception: " + fnfe.getMessage());
+ } catch (Exception e) {
+ ErrorLogHelper.logError("AAI_4004",
+ " " + mechIdConfigFileName + ". Exception: " + e.getMessage());
+ }
+ }
+
+
+ /**
+ * Transform mech id to pickup dir.
+ *
+ * @param systemMechId the system mech id
+ * @return the string
+ */
+ public static String transformMechIdToPickupDir(String systemMechId) {
+ String pickupDir = "";
+ if (systemMechId != null && !systemMechId.isEmpty()) {
+ pickupDir = "/opt/aaihome/" + systemMechId + "/pickup";
+
+ if (pickupDir != null && !pickupDir.isEmpty() && new File(pickupDir).isDirectory()) {
+ return pickupDir;
+ }
+
+ }
+ return null;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIRSyncUtility.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIRSyncUtility.java
new file mode 100644
index 00000000..b32e8882
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIRSyncUtility.java
@@ -0,0 +1,197 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ *
+ */
+package org.openecomp.aai.util;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.openecomp.aai.exceptions.AAIException;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+
+public class AAIRSyncUtility {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIRSyncUtility.class);
+ private final String DEFAULT_CHECK = new String("aai.primary.filetransfer.");
+
+ /**
+ * Instantiates a new AAIR sync utility.
+ */
+ public AAIRSyncUtility() {
+
+ }
+
+ /**
+ * Do command.
+ *
+ * @param command the command
+ * @return the int
+ * @throws Exception the exception
+ */
+ public int doCommand(List<String> command)
+ throws Exception
+ {
+ String s = null;
+
+ ProcessBuilder pb = new ProcessBuilder(command);
+ Process process = pb.start();
+
+ BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
+ BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+
+ LOGGER.debug("Here is the standard output of the command:\n");
+ while ((s = stdInput.readLine()) != null)
+ {
+ LOGGER.debug(s);
+ }
+
+ LOGGER.debug("Here is the standard error of the command (if any):\n");
+ while ((s = stdError.readLine()) != null)
+ {
+ LOGGER.debug(s);
+ }
+ return process.waitFor();
+ }
+
+
+ /**
+ * Method sendRsyncCommand.
+ *
+ * @param transId the trans id
+ * @param fileName the file name
+ */
+ public void sendRsyncCommand(String transId, String fileName)
+ {
+ String aaiServerList = null;
+ String rsyncOptionsList = null;
+
+ try {
+ aaiServerList = AAIConfig.get(DEFAULT_CHECK + "serverlist");
+ rsyncOptionsList = AAIConfig.get("aai.rsync.options.list");
+ String enableRsync = AAIConfig.get("aai.rsync.enabled");
+
+ if (!AAIConfig.isEmpty(enableRsync) && "n".equalsIgnoreCase(enableRsync)){
+ LOGGER.info("rsync not invoked for " + fileName + ": rsync is not enabled in aaiconfig.properties");
+ return;
+ }
+ } catch ( Exception e ) {
+ LOGGER.warn( "rsync not invoked: missing aaiconfig.properties entries for rsync" );
+ }
+
+ LOGGER.info("rsync to copy files started....");
+
+ ArrayList<String> remoteHostList = new ArrayList<String>();
+ StringTokenizer serverList = new StringTokenizer( aaiServerList, "|" );
+ String host = null;
+ try {
+ host = getHost();
+ String remoteConnString = null;
+
+ remoteHostList = getRemoteHostList(serverList, host);
+ LOGGER.debug("This host:" + host);
+ String pickUpDirectory = AAIConfig.get("instar.pickup.dir");
+ String user = AAIConfig.get("aai.rsync.remote.user");
+ String rsyncCmd = AAIConfig.get("aai.rsync.command");
+
+ //Push: rsync [OPTION...] SRC... [USER@]HOST:DEST
+
+ java.util.Iterator<String> remoteHostItr = remoteHostList.iterator();
+ while (!remoteHostList.isEmpty() && remoteHostItr.hasNext()) {
+ String remoteHost = remoteHostItr.next();
+ remoteConnString =user+"@"+remoteHost+":"+pickUpDirectory;
+
+ List<String> commands = new ArrayList<String>();
+ commands.add(rsyncCmd);
+ StringTokenizer optionTks = new StringTokenizer( rsyncOptionsList, "|" );
+ while (optionTks.hasMoreTokens()){
+ commands.add(optionTks.nextToken());
+ }
+ commands.add(fileName); // src directory/fileName
+ commands.add(remoteConnString); // target username/host/path
+ LOGGER.debug("Commands: " + commands.toString());
+ int rsyncResult = doCommand(commands);
+ if ( rsyncResult == 0 ) {
+ LOGGER.info("rsync completed for "+remoteHost);
+ }else {
+ LOGGER.error("rsync failed for "+ remoteHost+ " with response code "+rsyncResult );
+ }
+ }
+ } catch ( Exception e) {
+ LOGGER.error("no server found processing serverList for host " + host + ": " + e.getMessage() + " (AAI_4000)");
+ }
+ }
+
+ /**
+ * Gets the remote host list.
+ *
+ * @param serverList the server list
+ * @param host the host
+ * @return the remote host list
+ */
+ private ArrayList<String> getRemoteHostList(StringTokenizer serverList, String host) {
+ ArrayList<String> remoteHostList = new ArrayList<String>();
+ String remoteHost = null;
+ while ( serverList.hasMoreTokens() ) {
+ remoteHost = serverList.nextToken();
+ if (!host.equalsIgnoreCase(remoteHost)){
+ remoteHostList.add(remoteHost);
+ }
+ }
+ return remoteHostList;
+ }
+
+ /**
+ * Gets the host.
+ *
+ * @return the host
+ * @throws AAIException the AAI exception
+ */
+ private String getHost() throws AAIException {
+ String aaiServerList = AAIConfig.get(DEFAULT_CHECK + "serverlist");
+ String hostname = null;
+ try {
+ InetAddress ip = InetAddress.getLocalHost();
+ if ( ip != null ) {
+ hostname = ip.getHostName();
+ if ( hostname != null ) {
+ if ( !( aaiServerList.contains(hostname) ) )
+ LOGGER.warn("Host name not found in server list " + hostname);
+ } else
+ LOGGER.warn("InetAddress returned null hostname");
+ }
+
+ } catch (UnknownHostException e) {
+ LOGGER.warn("InetAddress getLocalHost exception " + e.getMessage());
+ }
+
+ return hostname;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAITxnLog.java b/aai-core/src/main/java/org/openecomp/aai/util/AAITxnLog.java
new file mode 100644
index 00000000..98a78478
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/AAITxnLog.java
@@ -0,0 +1,501 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.apache.hadoop.hbase.HBaseConfiguration;
+import org.apache.hadoop.hbase.client.*;
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
+import org.apache.hadoop.hbase.filter.Filter;
+import org.apache.hadoop.hbase.filter.FilterList;
+import org.apache.hadoop.hbase.filter.RegexStringComparator;
+import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.openecomp.aai.domain.notificationEvent.NotificationEvent;
+import org.openecomp.aai.domain.translog.TransactionLogEntries;
+import org.openecomp.aai.domain.translog.TransactionLogEntry;
+import org.openecomp.aai.exceptions.AAIException;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+public class AAITxnLog {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAITxnLog.class);
+
+ private final org.apache.hadoop.conf.Configuration config;
+ private HTable table = null;
+ private String tm = null;
+
+ /**
+ * Instantiates a new AAI txn log.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ */
+ public AAITxnLog(String transId, String fromAppId) {
+ /* When you create a HBaseConfiguration, it reads in whatever you've set
+ into your hbase-site.xml and in hbase-default.xml, as long as these can
+ be found on the CLASSPATH */
+
+ config = HBaseConfiguration.create();
+
+ try {
+ config.set(AAIConstants.ZOOKEEPER_ZNODE_PARENT, AAIConfig.get(AAIConstants.HBASE_ZOOKEEPER_ZNODE_PARENT));
+ config.set(AAIConstants.HBASE_CONFIGURATION_ZOOKEEPER_QUORUM, AAIConfig.get(AAIConstants.HBASE_CONFIGURATION_ZOOKEEPER_QUORUM));
+ config.set(AAIConstants.HBASE_CONFIGURATION_ZOOKEEPER_CLIENTPORT, AAIConfig.get(AAIConstants.HBASE_CONFIGURATION_ZOOKEEPER_CLIENTPORT));
+
+ Date date = new Date();
+ DateFormat formatter = new SimpleDateFormat(AAIConfig.get(AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT));
+ tm = formatter.format(date);
+ } catch (AAIException e) {
+ LOGGER.warn("Missing configuration in AAIConfig: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Put.
+ *
+ * @param status the status
+ * @param srcId the src id
+ * @param rsrcId the rsrc id
+ * @param rsrcType the rsrc type
+ * @param rqstBuf the rqst buf
+ * @param respBuf the resp buf
+ * @return the string
+ */
+ public String put(
+ String status,
+ String srcId,
+ String rsrcId,
+ String rsrcType,
+ String rqstBuf,
+ String respBuf
+ ) {
+ return put ("",status,"","",srcId,rsrcId,rsrcType,rqstBuf,respBuf,false,new NotificationEvent());
+
+ }
+
+ /**
+ * Put.
+ *
+ * @param tid the tid
+ * @param status the status
+ * @param srcId the src id
+ * @param rsrcId the rsrc id
+ * @param rsrcType the rsrc type
+ * @param rqstBuf the rqst buf
+ * @param respBuf the resp buf
+ * @return the string
+ */
+ public String put(
+ String tid,
+ String status,
+ String srcId,
+ String rsrcId,
+ String rsrcType,
+ String rqstBuf,
+ String respBuf
+ ) {
+ return put (tid,status,"","",srcId,rsrcId,rsrcType,rqstBuf,respBuf,false,new NotificationEvent());
+ }
+
+ /**
+ * Put.
+ *
+ * @param tid the tid
+ * @param status the status
+ * @param rqstTm the rqst tm
+ * @param respTm the resp tm
+ * @param srcId the src id
+ * @param rsrcId the rsrc id
+ * @param rsrcType the rsrc type
+ * @param rqstBuf the rqst buf
+ * @param respBuf the resp buf
+ * @return the string
+ */
+ public String put(
+ String tid,
+ String status,
+ String rqstTm,
+ String respTm,
+ String srcId,
+ String rsrcId,
+ String rsrcType,
+ String rqstBuf,
+ String respBuf
+ ) {
+ return put (tid,status,"","",srcId,rsrcId,rsrcType,rqstBuf,respBuf,false,new NotificationEvent());
+ }
+
+ /**
+ * Put.
+ *
+ * @param tid the tid
+ * @param status the status
+ * @param rqstTm the rqst tm
+ * @param respTm the resp tm
+ * @param srcId the src id
+ * @param rsrcId the rsrc id
+ * @param rsrcType the rsrc type
+ * @param rqstBuf the rqst buf
+ * @param respBuf the resp buf
+ * @param hasNotificationEvent the has notification event
+ * @param ne the ne
+ * @return the string
+ */
+ public String put(
+ String tid,
+ String status,
+ String rqstTm,
+ String respTm,
+ String srcId,
+ String rsrcId,
+ String rsrcType,
+ String rqstBuf,
+ String respBuf,
+ boolean hasNotificationEvent,
+ NotificationEvent ne
+ ) {
+
+ if (tid == null || "".equals(tid)) {
+ Date date = new Date();
+ DateFormat formatter = null;
+ try {
+ formatter = new SimpleDateFormat(AAIConfig.get(AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT));
+ } catch (Exception e) {
+ formatter = new SimpleDateFormat("YYYYMMdd-HH:mm:ss:SSS");
+ }
+ tm = formatter.format(date);
+ tid = tm + "-";
+ }
+ String htid = tid;
+
+ //need to add a prefix for better hbase logging server balancing
+ htid = HbaseSaltPrefixer.getInstance().prependSalt(htid);
+
+ if (rqstTm == null || "".equals(rqstTm)) {
+ rqstTm = tm;
+ }
+
+ if (respTm == null || "".equals(respTm)) {
+ respTm = tm;
+ }
+
+ try {
+ table = new HTable(config, AAIConfig.get(AAIConstants.HBASE_TABLE_NAME));
+
+ Put p = new Put(Bytes.toBytes(htid));
+
+ p.add(Bytes.toBytes("transaction"),Bytes.toBytes("tid"),Bytes.toBytes(tid));
+ p.add(Bytes.toBytes("transaction"),Bytes.toBytes("status"),Bytes.toBytes(status));
+ p.add(Bytes.toBytes("transaction"),Bytes.toBytes("rqstDate"),Bytes.toBytes(rqstTm));
+ p.add(Bytes.toBytes("transaction"),Bytes.toBytes("respDate"),Bytes.toBytes(respTm));
+ p.add(Bytes.toBytes("transaction"),Bytes.toBytes("sourceId"),Bytes.toBytes(srcId));
+
+ p.add(Bytes.toBytes("resource"),Bytes.toBytes("resourceId"),Bytes.toBytes(rsrcId));
+ p.add(Bytes.toBytes("resource"),Bytes.toBytes("resourceType"),Bytes.toBytes(rsrcType));
+
+ p.add(Bytes.toBytes("payload"),Bytes.toBytes("rqstBuf"),Bytes.toBytes(rqstBuf));
+ p.add(Bytes.toBytes("payload"),Bytes.toBytes("respBuf"),Bytes.toBytes(respBuf));
+
+ if (hasNotificationEvent == true) {
+ String eventType = ne.getEventHeader().getEventType();
+ String eventStatus = ne.getEventHeader().getStatus();
+
+ if (eventStatus == null) {
+ eventStatus = AAIConfig.get("aai.notificationEvent.default.status", "UNPROCESSED");
+ }
+ if (eventType == null) {
+ eventType = AAIConfig.get("aai.notificationEvent.default.eventType", "AAI-EVENT");
+ }
+
+ if (ne.getEntity() != null) {
+ PojoUtils pu = new PojoUtils();
+ p.add(Bytes.toBytes("notification"),Bytes.toBytes("notificationPayload"),Bytes.toBytes(pu.getJsonFromObject(ne)));
+ }
+ if (ne.getEventHeader().getId() != null) {
+ p.add(Bytes.toBytes("notification"),Bytes.toBytes("notificationId"),Bytes.toBytes(ne.getEventHeader().getId()));
+ }
+
+ p.add(Bytes.toBytes("notification"),Bytes.toBytes("notificationStatus"),Bytes.toBytes(eventStatus));
+ p.add(Bytes.toBytes("notification"),Bytes.toBytes("notificationTopic"),Bytes.toBytes(eventType));
+
+ if (ne.getEventHeader().getEntityLink() != null) {
+ p.add(Bytes.toBytes("notification"),Bytes.toBytes("notificationEntityLink"),Bytes.toBytes(ne.getEventHeader().getEntityLink()));
+ }
+ if (ne.getEventHeader().getAction() != null) {
+ p.add(Bytes.toBytes("notification"),Bytes.toBytes("notificationAction"),Bytes.toBytes(ne.getEventHeader().getAction()) );
+ }
+ }
+ /* Once you've adorned your Put instance with all the updates you want to
+ make, to commit it do the following */
+ table.put(p);
+ table.flushCommits();
+ table.close();
+ return htid;
+ } catch (Exception e) {
+ LOGGER.warn("AAITxnLog: put: Exception", e);
+ return htid;
+ }
+ }
+
+ /**
+ * Gets the.
+ *
+ * @param htid the htid
+ * @return the transaction log entry
+ * @throws AAIException the AAI exception
+ */
+ public TransactionLogEntry get(String htid) throws AAIException {
+
+ LOGGER.debug("In get: searching hbase config file...");
+ String tidStr = "";
+ TransactionLogEntry txObj = new TransactionLogEntry();
+
+ try {
+ table = new HTable(config, AAIConfig.get(AAIConstants.HBASE_TABLE_NAME));
+
+ Get g = new Get(Bytes.toBytes(htid));
+
+ Result r = table.get(g);
+ byte [] tid = r.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("tid"));
+ byte [] status = r.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("status"));
+ byte [] rqstDate = r.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("rqstDate"));
+ byte [] respDate = r.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("respDate"));
+ byte [] sourceId = r.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("sourceId"));
+
+ byte [] resourceId = r.getValue(Bytes.toBytes("resource"),Bytes.toBytes("resourceId"));
+ byte [] resourceType = r.getValue(Bytes.toBytes("resource"),Bytes.toBytes("resourceType"));
+
+ byte [] rqstBuf = r.getValue(Bytes.toBytes("payload"),Bytes.toBytes("rqstBuf"));
+ byte [] respBuf = r.getValue(Bytes.toBytes("payload"),Bytes.toBytes("respBuf"));
+
+ byte [] notificationPayload = r.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationPayload"));
+ byte [] notificationStatus = r.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationStatus"));
+ byte [] notificationId = r.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationId"));
+ byte [] notificationTopic = r.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationTopic"));
+ byte [] notificationEntityLink = r.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationEntityLink"));
+ byte [] notificationAction = r.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationAction"));
+
+ table.close();
+
+ tidStr = Bytes.toString(tid);
+ txObj.setTransactionLogEntryId(tidStr);
+ txObj.setStatus(Bytes.toString(status));
+ txObj.setRqstDate(Bytes.toString(rqstDate));
+ txObj.setRespDate(Bytes.toString(respDate));
+ txObj.setSourceId(Bytes.toString(sourceId));
+ txObj.setResourceId(Bytes.toString(resourceId));
+ txObj.setResourceType(Bytes.toString(resourceType));
+ txObj.setRqstBuf(Bytes.toString(rqstBuf));
+ txObj.setrespBuf(Bytes.toString(respBuf));
+ txObj.setNotificationPayload(Bytes.toString(notificationPayload));
+ txObj.setNotificationStatus(Bytes.toString(notificationStatus));
+ txObj.setNotificationId(Bytes.toString(notificationId));
+ txObj.setNotificationTopic(Bytes.toString(notificationTopic));
+ txObj.setNotificationEntityLink(Bytes.toString(notificationEntityLink));
+ txObj.setNotificationAction(Bytes.toString(notificationAction));
+ } catch (IOException e) {
+ LOGGER.error("IOException on hbase call", e);
+ throw new AAIException("AAI_4000");
+ }
+
+ return txObj;
+ }
+
+
+ /**
+ * Scan filtered.
+ *
+ * @param startMillis the start millis
+ * @param endMillis the end millis
+ * @param methodList the method list
+ * @param putFilter the put filter
+ * @param getFilter the get filter
+ * @param resourceFilter the resource filter
+ * @param fromAppIdFilter the from app id filter
+ * @return the transaction log entries
+ */
+ public TransactionLogEntries scanFiltered(long startMillis, long endMillis, List<String> methodList,
+ String putFilter, String getFilter, String resourceFilter, String fromAppIdFilter) {
+
+ LOGGER.debug("Starting scanFiltered()");
+
+ // we should have the config ready from the constructor
+
+ TransactionLogEntries txs = new TransactionLogEntries();
+
+ if (config == null) {
+ LOGGER.debug("in scan: can't create HBase configuration");
+ return txs;
+ }
+
+ try {
+ table = new HTable(config, AAIConfig.get(AAIConstants.HBASE_TABLE_NAME));
+ Scan s = new Scan();
+ FilterList flMaster = new FilterList(FilterList.Operator.MUST_PASS_ALL);
+ FilterList methodflMaster = new FilterList(FilterList.Operator.MUST_PASS_ONE);
+ if (methodList != null) {
+ for (String method : methodList) {
+ Filter filt = new SingleColumnValueFilter(Bytes.toBytes("resource"),
+ Bytes.toBytes("resourceType"), CompareOp.EQUAL, Bytes.toBytes(method));
+ methodflMaster.addFilter(filt);
+ }
+ flMaster.addFilter(methodflMaster);
+ }
+
+ if (getFilter != null) {
+ Filter filt = new SingleColumnValueFilter(Bytes.toBytes("payload"),
+ Bytes.toBytes("respBuf"), CompareOp.EQUAL, new RegexStringComparator(getFilter));
+ flMaster.addFilter(filt);
+ }
+ if (putFilter != null) {
+ Filter filt = new SingleColumnValueFilter(Bytes.toBytes("payload"),
+ Bytes.toBytes("rqstBuf"), CompareOp.EQUAL, new RegexStringComparator(putFilter));
+ flMaster.addFilter(filt);
+ }
+ if (resourceFilter != null) {
+ Filter filt = new SingleColumnValueFilter(Bytes.toBytes("resource"),
+ Bytes.toBytes("resourceId"), CompareOp.EQUAL, new RegexStringComparator(resourceFilter));
+ flMaster.addFilter(filt);
+ }
+ if (fromAppIdFilter != null) {
+ Filter filt = new SingleColumnValueFilter(Bytes.toBytes("transaction"),
+ Bytes.toBytes("sourceId"), CompareOp.EQUAL, new RegexStringComparator("^" + fromAppIdFilter));
+ flMaster.addFilter(filt);
+ }
+
+ if (flMaster.hasFilterRow()) {
+ s.setFilter(flMaster);
+ }
+
+ s.setTimeRange(startMillis, endMillis);
+ ResultScanner scanner = table.getScanner(s);
+
+ try {
+ for (Result rr = scanner.next(); rr != null; rr = scanner.next()) {
+
+ byte [] tid = rr.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("tid"));
+ byte [] status = rr.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("status"));
+ byte [] rqstDate = rr.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("rqstDate"));
+ byte [] respDate = rr.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("respDate"));
+ byte [] sourceId = rr.getValue(Bytes.toBytes("transaction"),Bytes.toBytes("sourceId"));
+
+ byte [] resourceId = rr.getValue(Bytes.toBytes("resource"),Bytes.toBytes("resourceId"));
+ byte [] resourceType = rr.getValue(Bytes.toBytes("resource"),Bytes.toBytes("resourceType"));
+
+ byte [] rqstBuf = rr.getValue(Bytes.toBytes("payload"),Bytes.toBytes("rqstBuf"));
+ byte [] respBuf = rr.getValue(Bytes.toBytes("payload"),Bytes.toBytes("respBuf"));
+
+ byte [] notificationPayload = rr.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationPayload"));
+ byte [] notificationStatus = rr.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationStatus"));
+ byte [] notificationId = rr.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationId"));
+ byte [] notificationTopic = rr.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationTopic"));
+ byte [] notificationEntityLink = rr.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationEntityLink"));
+ byte [] notificationAction = rr.getValue(Bytes.toBytes("notification"),Bytes.toBytes("notificationAction"));
+ TransactionLogEntry txObj = new TransactionLogEntry();
+ String tidStr = Bytes.toString(tid);
+ txObj.setTransactionLogEntryId(tidStr);
+ txObj.setStatus(Bytes.toString(status));
+ txObj.setRqstDate(Bytes.toString(rqstDate));
+ txObj.setRespDate(Bytes.toString(respDate));
+ txObj.setSourceId(Bytes.toString(sourceId));
+ txObj.setResourceId(Bytes.toString(resourceId));
+ txObj.setResourceType(Bytes.toString(resourceType));
+ txObj.setRqstBuf(Bytes.toString(rqstBuf));
+ txObj.setrespBuf(Bytes.toString(respBuf));
+ txObj.setNotificationPayload(Bytes.toString(notificationPayload));
+ txObj.setNotificationStatus(Bytes.toString(notificationStatus));
+ txObj.setNotificationId(Bytes.toString(notificationId));
+ txObj.setNotificationTopic(Bytes.toString(notificationTopic));
+ txObj.setNotificationEntityLink(Bytes.toString(notificationEntityLink));
+ txObj.setNotificationAction(Bytes.toString(notificationAction));
+ txs.getTransactionLogEntries().add(txObj);
+ }
+ } finally {
+ // Make sure you close your scanners when you are done!
+ scanner.close();
+ }
+ table.close();
+ } catch (Exception e) {
+ LOGGER.warn("AAITxnLog: scan: Exception=" + e.toString());
+ }
+
+ return txs;
+ }
+
+ /**
+ * Scan.
+ *
+ * @param htid the htid
+ * @return the list
+ */
+ public List<String> scan(String htid) {
+
+ List<String> list = new ArrayList<String>();
+ LOGGER.debug("In scan: searching hbase config file...");
+ // we should have the config ready from the constructor
+ if (config == null) {
+ LOGGER.debug("in scan: can't create HBase configuration");
+ return list;
+ }
+
+ try {
+ table = new HTable(config, AAIConfig.get(AAIConstants.HBASE_TABLE_NAME));
+ Scan s = new Scan(Bytes.toBytes(htid));
+ ResultScanner scanner = table.getScanner(s);
+
+ try {
+ for (Result rr = scanner.next(); rr != null; rr = scanner.next()) {
+ list.add(rr.toString());
+ LOGGER.debug("in scan: Found row : " + rr);
+
+ }
+ } finally {
+ // Make sure you close your scanners when you are done!
+ scanner.close();
+ }
+ table.close();
+ } catch (Exception e) {
+
+ LOGGER.debug("AAITxnLog: scan: Exception=" + e.toString());
+ }
+ return list;
+ }
+
+}
+
+/*
+Need to implement HBase Connection Pooling in the future.
+This is to reduce the 1 second delay during the first open of HConnection, and HTable instantiation.
+Hbase provides the Hconnection class and the HConnectionManager class.
+Both provifde the functionaltity similar to jdbc connection pooling
+to share pre-existing opened connections.
+Here we should be able to use the getTable() method to get a
+reference to an HTable instance.
+
+ */
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/AAIUtils.java b/aai-core/src/main/java/org/openecomp/aai/util/AAIUtils.java
new file mode 100644
index 00000000..1ea39b0b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/AAIUtils.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Date;
+import java.util.TimeZone;
+
+public class AAIUtils {
+
+ /**
+ * Null check.
+ *
+ * @param <T> the generic type
+ * @param iterable the iterable
+ * @return the iterable
+ */
+ public static <T> Iterable<T> nullCheck(Iterable<T> iterable) {
+ return iterable == null ? Collections.<T>emptyList() : iterable;
+ }
+
+ /**
+ * Gen date.
+ *
+ * @return the string
+ */
+ public static String genDate() {
+ Date date = new Date();
+ DateFormat formatter = new SimpleDateFormat("YYMMdd-HH:mm:ss:SSS");
+ formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
+ return formatter.format(date);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/Entity.java b/aai-core/src/main/java/org/openecomp/aai/util/Entity.java
new file mode 100644
index 00000000..865fe8b6
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/Entity.java
@@ -0,0 +1,196 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Generated;
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Generated("org.jsonschema2pojo")
+@JsonPropertyOrder({
+ "equipment-role",
+ "action",
+ "key-value-list",
+ "self-link"
+})
+public class Entity {
+
+ @JsonProperty("equipment-role")
+ private String equipmentRole;
+ @JsonProperty("action")
+ private String action;
+ @JsonProperty("key-value-list")
+ private List<KeyValueList> keyValueList = new ArrayList<KeyValueList>();
+ @JsonProperty("self-link")
+ private String selfLink;
+ @JsonIgnore
+ private Map<String, Object> additionalProperties = new HashMap<String, Object>();
+
+ /**
+ *
+ * @return
+ * The equipmentRole
+ */
+ @JsonProperty("equipment-role")
+ public String getEquipmentRole() {
+ return equipmentRole;
+ }
+
+ /**
+ *
+ * @param equipmentRole
+ * The equipment-role
+ */
+ @JsonProperty("equipment-role")
+ public void setEquipmentRole(String equipmentRole) {
+ this.equipmentRole = equipmentRole;
+ }
+
+ public Entity withEquipmentRole(String equipmentRole) {
+ this.equipmentRole = equipmentRole;
+ return this;
+ }
+
+ /**
+ *
+ * @return
+ * The action
+ */
+ @JsonProperty("action")
+ public String getAction() {
+ return action;
+ }
+
+ /**
+ *
+ * @param action
+ * The action
+ */
+ @JsonProperty("action")
+ public void setAction(String action) {
+ this.action = action;
+ }
+
+ public Entity withAction(String action) {
+ this.action = action;
+ return this;
+ }
+
+ /**
+ *
+ * @return
+ * The keyValueList
+ */
+ @JsonProperty("key-value-list")
+ public List<KeyValueList> getKeyValueList() {
+ return keyValueList;
+ }
+
+ /**
+ *
+ * @param keyValueList
+ * The key-value-list
+ */
+ @JsonProperty("key-value-list")
+ public void setKeyValueList(List<KeyValueList> keyValueList) {
+ this.keyValueList = keyValueList;
+ }
+
+ public Entity withKeyValueList(List<KeyValueList> keyValueList) {
+ this.keyValueList = keyValueList;
+ return this;
+ }
+
+ /**
+ *
+ * @return
+ * The selfLink
+ */
+ @JsonProperty("self-link")
+ public String getSelfLink() {
+ return selfLink;
+ }
+
+ /**
+ *
+ * @param selfLink
+ * The self-link
+ */
+ @JsonProperty("self-link")
+ public void setSelfLink(String selfLink) {
+ this.selfLink = selfLink;
+ }
+
+ public Entity withSelfLink(String selfLink) {
+ this.selfLink = selfLink;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this);
+ }
+
+ @JsonAnyGetter
+ public Map<String, Object> getAdditionalProperties() {
+ return this.additionalProperties;
+ }
+
+ @JsonAnySetter
+ public void setAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ }
+
+ public Entity withAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder().append(equipmentRole).append(action).append(keyValueList).append(selfLink).append(additionalProperties).toHashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if ((other instanceof Entity) == false) {
+ return false;
+ }
+ Entity rhs = ((Entity) other);
+ return new EqualsBuilder().append(equipmentRole, rhs.equipmentRole).append(action, rhs.action).append(keyValueList, rhs.keyValueList).append(selfLink, rhs.selfLink).append(additionalProperties, rhs.additionalProperties).isEquals();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/EntityList.java b/aai-core/src/main/java/org/openecomp/aai/util/EntityList.java
new file mode 100644
index 00000000..db685dbc
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/EntityList.java
@@ -0,0 +1,112 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Generated;
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Generated("org.jsonschema2pojo")
+@JsonPropertyOrder({
+ "entity"
+})
+public class EntityList {
+
+ @JsonProperty("entity")
+ private List<Entity> entity = new ArrayList<Entity>();
+ @JsonIgnore
+ private Map<String, Object> additionalProperties = new HashMap<String, Object>();
+
+ /**
+ *
+ * @return
+ * The entity
+ */
+ @JsonProperty("entity")
+ public List<Entity> getEntity() {
+ return entity;
+ }
+
+ /**
+ *
+ * @param entity
+ * The entity
+ */
+ @JsonProperty("entity")
+ public void setEntity(List<Entity> entity) {
+ this.entity = entity;
+ }
+
+ public EntityList withEntity(List<Entity> entity) {
+ this.entity = entity;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this);
+ }
+
+ @JsonAnyGetter
+ public Map<String, Object> getAdditionalProperties() {
+ return this.additionalProperties;
+ }
+
+ @JsonAnySetter
+ public void setAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ }
+
+ public EntityList withAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder().append(entity).append(additionalProperties).toHashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if ((other instanceof EntityList) == false) {
+ return false;
+ }
+ EntityList rhs = ((EntityList) other);
+ return new EqualsBuilder().append(entity, rhs.entity).append(additionalProperties, rhs.additionalProperties).isEquals();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/FileWatcher.java b/aai-core/src/main/java/org/openecomp/aai/util/FileWatcher.java
new file mode 100644
index 00000000..6db89ebe
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/FileWatcher.java
@@ -0,0 +1,59 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import java.util.*;
+import java.io.*;
+
+public abstract class FileWatcher extends TimerTask {
+ private long timeStamp;
+ private File file;
+
+ /**
+ * Instantiates a new file watcher.
+ *
+ * @param file the file
+ */
+ public FileWatcher( File file ) {
+ this.file = file;
+ this.timeStamp = file.lastModified();
+ }
+
+ /**
+ * runs a timer task
+ * @see java.util.TimerTask.run
+ */
+ public final void run() {
+ long timeStamp = file.lastModified();
+
+ if( (timeStamp - this.timeStamp) > 500 ) {
+ this.timeStamp = timeStamp;
+ onChange(file);
+ }
+ }
+
+ /**
+ * On change.
+ *
+ * @param file the file
+ */
+ protected abstract void onChange( File file );
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/GenerateXsd.java b/aai-core/src/main/java/org/openecomp/aai/util/GenerateXsd.java
new file mode 100644
index 00000000..a1668886
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/GenerateXsd.java
@@ -0,0 +1,1672 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.SchemaOutputResolver;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Result;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+
+import org.openecomp.aai.dbmodel.DbEdgeRules;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Multimap;
+
+
+public class GenerateXsd {
+ static String apiVersion = null;
+ static String apiVersionFmt = null;
+ static String responsesUrl = null;
+ static String responsesLabel = null;
+ static Map<String, String> generatedJavaType = new HashMap<String, String>();
+ static Map<String, String> appliedPaths = new HashMap<String, String>();
+ static NodeList javaTypeNodes;
+ static Class<?> versionedClass;
+
+
+ public static final int VALUE_NONE = 0;
+ public static final int VALUE_DESCRIPTION = 1;
+ public static final int VALUE_INDEXED_PROPS = 2;
+
+ private static XPath xpath = XPathFactory.newInstance().newXPath();
+
+
+ private enum LineageType {
+ PARENT, CHILD, UNRELATED;
+ }
+ private class EdgeDescription {
+
+ private String ruleKey;
+ private LineageType type = LineageType.UNRELATED;
+ private String direction;
+ private String multiplicity;
+ private boolean hasDelTarget = false;
+
+ public String getRuleKey() {
+ return ruleKey;
+ }
+ public String getMultiplicity() {
+ return multiplicity;
+ }
+ public String getDirection() {
+ return direction;
+ }
+ public void setRuleKey(String val) {
+ this.ruleKey=val;
+ }
+ public void setType(LineageType val) {
+ this.type=val;
+ }
+ public void setDirection(String val) {
+ this.direction = val;
+ }
+ public void setMultiplicity(String val) {
+ this.multiplicity=val;
+ }
+ public void setHasDelTarget(String val) {
+ hasDelTarget = Boolean.parseBoolean(val);
+ }
+
+ public String getRelationshipDescription(String fromTo, String otherNodeName) {
+
+ String result = "";
+
+ if ("FROM".equals(fromTo)) {
+ if ("OUT".equals(direction)) {
+ if (LineageType.PARENT == type) {
+ result = " (is composed of "+otherNodeName;
+ }
+ }
+ else {
+ if (LineageType.CHILD == type) {
+ result = " (comprises "+otherNodeName;
+ }
+ else if (LineageType.PARENT == type) {
+ result = " (comprises "+otherNodeName;
+ }
+ }
+ } else {
+ if ("OUT".equals(direction)) {
+ if (LineageType.PARENT == type) {
+ result = " (comprises "+otherNodeName;
+ }
+ } else {
+ if (LineageType.PARENT == type) {
+ result = " (is composed of "+otherNodeName;
+ }
+ }
+ }
+
+// if (type != null) {
+// if (LineageType.PARENT.equals(type) && "FROM".equals(fromTo)) {
+// if ("OUT".equals(direction)) {
+// result = " (is composed of "+otherNodeName;
+// } else {
+// result = " (comprises "+otherNodeName;
+// }
+// } else {
+// result = " (comprises " + otherNodeName;
+// // if (!(multiplicity.startsWith("One"))) {
+// // System.err.println("Surprised to find multiplicity "+multiplicity+" with comprises for "+ruleKey);
+// // }
+// }
+// }
+ if ("TO".equals(fromTo)) {
+ if (result.length() == 0) result = result + " (";
+ else result = result + ", ";
+
+ result = result + mapMultiplicity(fromTo);
+ if (hasDelTarget) result = result + ", will delete target node";
+ }
+
+ if (result.length() > 0) result = result + ")";
+
+ return result;
+ }
+
+ private String mapMultiplicity(String fromTo) {
+ String result = multiplicity;
+// Below logic works if an IN switches multiplicity, which it doesn't today.
+// if ("TO".equals(fromTo)) {
+// if (direction.equals("OUT")) {
+// result = multiplicity;
+// } else {
+// result = switchMultiplicity(multiplicity);
+// }
+// } else {
+// if (direction.equals("OUT")) {
+// result = multiplicity;
+// } else {
+// result = switchMultiplicity(multiplicity);
+// }
+// }
+ return result;
+ }
+
+// private String switchMultiplicity(String val) throws IllegalArgumentException
+// {
+// String result = null;
+// switch (val) {
+// case "Many2Many":
+// case "One2One":
+// result = val;
+// break;
+// case "Many2One":
+// result = "One2Many";
+// break;
+// case "One2Many":
+// result = "Many2One";
+// break;
+// default:
+// throw new IllegalArgumentException("Multiplicity cannot be "+val);
+// }
+// System.out.println("Switched Multiplicity from "+val+" to "+result);
+// return result;
+// }
+ }
+
+ public static void main(String[] args) throws IOException {
+
+ if (args.length > 0) {
+ if (args[0] != null) {
+ apiVersion = args[0];
+ }
+ }
+ boolean genDoc = false;
+ if ( args.length > 1 ) {
+ genDoc = true;
+ int index = args[1].indexOf("|");
+ if ( index > 0 ) {
+ responsesUrl = args[1].substring(0, index);
+ responsesLabel = args[1].substring(index+1);
+ //System.out.println( "response URL " + responsesUrl);
+ //System.out.println( "response label " + responsesLabel);
+ responsesUrl = "description: "+ responsesLabel + "(" +
+ responsesUrl + ").\n";
+ //System.out.println( "operation described with " + responsesUrl);
+ } else { // default
+ responsesUrl = "";
+ }
+ }
+ String oxmPath = null;
+ if ( apiVersion == null ) {
+ // to run from eclipse, set these env, e.g. v7, \sources\aai\aaimastergit\bundleconfig-local\etc\oxm\
+ String envRev= System.getenv("OXM_REV");
+ if ( envRev != null )
+ apiVersion = envRev;
+
+ }
+ oxmPath = System.getenv("OXM_PATH");
+ String outfileName;
+ if ( genDoc ) {
+ outfileName = "c:\\temp\\aai.yaml";
+ } else
+ outfileName = "c:\\temp\\aai_schema.xsd";
+ if ( apiVersion != null ) { // generate from oxm
+ apiVersionFmt = "." + apiVersion + ".";
+ if ( oxmPath == null ) {
+ oxmPath = AAIConstants.AAI_HOME_ETC_OXM + AAIConstants.AAI_FILESEP;
+ //oxmPath = "\\sources\\aai\\aaimastergit\\bundleconfig-local\\etc\\oxm\\";
+ }
+
+ File oxm_file = new File(oxmPath + "aai_oxm_" + apiVersion + ".xml");
+ String xsd;
+ File outfile;
+ if ( genDoc ) {
+ xsd = generateSwaggerFromOxmFile( oxm_file);
+ outfile =new File(outfileName);
+ } else {
+ xsd = processOxmFile( oxm_file);
+ outfile =new File(outfileName);
+ }
+
+
+ try {
+ outfile.createNewFile();
+ } catch (IOException e) {
+ System.out.println( "Exception creating output file " + outfileName);
+ e.printStackTrace();
+ }
+ try {
+ FileWriter fw = new FileWriter(outfile.getAbsoluteFile());
+ BufferedWriter bw = new BufferedWriter(fw);
+ bw.write(xsd);
+ bw.close();
+
+ } catch ( IOException e) {
+ System.out.println( "Exception writing output file " + outfileName);
+ e.printStackTrace();
+ }
+ System.out.println( "GeneratedXSD successful, saved in " + outfileName);
+ return;
+ }
+
+ JAXBContext jaxbContext = null;
+ try {
+ jaxbContext = JAXBContext.newInstance(org.openecomp.aai.domain.yang.Vce.class);
+ } catch (JAXBException e) {
+
+ e.printStackTrace();
+ }
+ SchemaOutputResolver sor = new MySchemaOutputResolver();
+ jaxbContext.generateSchema(sor);
+
+ }
+
+ public static class MySchemaOutputResolver extends SchemaOutputResolver {
+
+ public Result createOutput(String namespaceURI, String suggestedFileName) throws IOException {
+ File file = new File("c:\\temp\\aai_schema.xsd");
+ StreamResult result = new StreamResult(file);
+ result.setSystemId(file.toURI().toURL().toString());
+ return result;
+ }
+
+ }
+
+ public static String processJavaTypeElement( String javaTypeName, Element javaTypeElement) {
+
+ String xmlRootElementName = null;
+
+ NodeList parentNodes = javaTypeElement.getElementsByTagName("java-attributes");
+ StringBuffer sb = new StringBuffer();
+ if ( parentNodes.getLength() == 0 ) {
+ System.out.println( "no java-attributes for java-type " + javaTypeName);
+ return "";
+
+ }
+
+ NamedNodeMap attributes;
+
+ NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
+ Element valElement = (Element) valNodes.item(0);
+ attributes = valElement.getAttributes();
+ for ( int i = 0; i < attributes.getLength(); ++i ) {
+ Attr attr = (Attr) attributes.item(i);
+ String attrName = attr.getNodeName();
+
+ String attrValue = attr.getNodeValue();
+ //System.out.println("Found xml-root-element attribute: " + attrName + " with value: " + attrValue);
+ if ( attrName.equals("name"))
+ xmlRootElementName = attrValue;
+ }
+ /*
+ if ( javaTypeName.equals("RelationshipList")) {
+ System.out.println( "Skipping " + javaTypeName);
+ generatedJavaType.put(javaTypeName, null);
+ return "";
+ }
+ */
+
+ Element parentElement = (Element)parentNodes.item(0);
+ NodeList xmlElementNodes = parentElement.getElementsByTagName("xml-element");
+ NodeList childNodes;
+ Element childElement;
+ String xmlElementWrapper;
+
+ Element xmlElementElement;
+ String addType;
+ String elementName, elementType, elementIsKey, elementIsRequired, elementContainerType;
+ StringBuffer sb1 = new StringBuffer();
+ if ( xmlElementNodes.getLength() > 0 ) {
+ sb1.append(" <xs:element name=\"" + xmlRootElementName + "\">\n");
+ sb1.append(" <xs:complexType>\n");
+ NodeList properties = GenerateXsd.locateXmlProperties(javaTypeElement);
+ if (properties != null) {
+ System.out.println("properties found for: " + xmlRootElementName);
+ sb1.append(" <xs:annotation>\r\n");
+ insertAnnotation(properties, false, "class", sb1, " ");
+
+ sb1.append(" </xs:annotation>\r\n");
+ } else {
+ System.out.println("no properties found for: " + xmlRootElementName);
+ }
+ sb1.append(" <xs:sequence>\n");
+ for ( int i = 0; i < xmlElementNodes.getLength(); ++i ) {
+
+ xmlElementElement = (Element)xmlElementNodes.item(i);
+ childNodes = xmlElementElement.getElementsByTagName("xml-element-wrapper");
+
+ xmlElementWrapper = null;
+ if ( childNodes.getLength() > 0 ) {
+ childElement = (Element)childNodes.item(0);
+ // get name
+ attributes = childElement.getAttributes();
+ for ( int k = 0; k < attributes.getLength(); ++k ) {
+ Attr attr = (Attr) attributes.item(k);
+ String attrName = attr.getNodeName();
+ String attrValue = attr.getNodeValue();
+ if ( attrName.equals("name")) {
+ xmlElementWrapper = attrValue;
+ //System.out.println("found xml-element-wrapper " + xmlElementWrapper);
+ }
+ }
+
+ }
+ attributes = xmlElementElement.getAttributes();
+ addType = null;
+
+
+ elementName = elementType = elementIsKey = elementIsRequired = elementContainerType = null;
+ for ( int j = 0; j < attributes.getLength(); ++j ) {
+ Attr attr = (Attr) attributes.item(j);
+ String attrName = attr.getNodeName();
+
+ String attrValue = attr.getNodeValue();
+ //System.out.println("For " + xmlRootElementName + " Found xml-element attribute: " + attrName + " with value: " + attrValue);
+ if ( attrName.equals("name")) {
+ elementName = attrValue;
+ }
+ if ( attrName.equals("type")) {
+ elementType = attrValue;
+ if ( attrValue.contains(apiVersionFmt) ) {
+ addType = attrValue.substring(attrValue.lastIndexOf('.')+1);
+ if ( !generatedJavaType.containsKey(addType) ) {
+ generatedJavaType.put(addType, attrValue);
+ sb.append(processJavaTypeElement( addType, getJavaTypeElement(addType) ));
+ }
+ }
+
+ }
+
+ if ( attrName.equals("xml-key")) {
+ elementIsKey = attrValue;
+ }
+ if ( attrName.equals("required")) {
+ elementIsRequired = attrValue;
+ }
+ if ( attrName.equals("container-type")) {
+ elementContainerType = attrValue;
+ }
+ }
+
+ if ( xmlElementWrapper != null ) {
+ sb1.append(" <xs:element name=\"" + xmlElementWrapper +"\"");
+ if ( elementIsRequired == null || !elementIsRequired.equals("true")||addType != null) {
+ sb1.append(" minOccurs=\"0\"");
+ }
+ sb1.append(">\n");
+ sb1.append(" <xs:complexType>\n");
+ properties = GenerateXsd.locateXmlProperties(javaTypeElement);
+ if (properties != null) {
+ sb1.append(" <xs:annotation>\r\n");
+ insertAnnotation(properties, false, "class", sb1, " ");
+ sb1.append(" </xs:annotation>\r\n");
+ } else {
+ System.out.println("no properties found for: " + xmlElementWrapper);
+ }
+ sb1.append(" <xs:sequence>\n");
+ sb1.append(" ");
+ }
+ if ("Nodes".equals(addType)) {
+ System.out.println ("Skipping nodes, temporary testing");
+ continue;
+ }
+ if ( addType != null ) {
+ //sb1.append(" <xs:element ref=\"tns:" + elementName +"\"");
+ sb1.append(" <xs:element ref=\"tns:" + getXmlRootElementName(addType) +"\"");
+ } else {
+ sb1.append(" <xs:element name=\"" + elementName +"\"");
+ }
+ if ( elementType.equals("java.lang.String"))
+ sb1.append(" type=\"xs:string\"");
+ //if ( elementType.equals("java.lang.String"))
+ //sb1.append(" type=\"xs:string\"");
+ if ( elementType.equals("java.lang.Long"))
+ sb1.append(" type=\"xs:unsignedInt\"");
+ if ( elementType.equals("java.lang.Integer"))
+ sb1.append(" type=\"xs:int\"");
+ if ( elementType.equals("java.lang.Boolean"))
+ sb1.append(" type=\"xs:boolean\"");
+ //if ( elementIsRequired != null && elementIsRequired.equals("true")||addType != null) {
+ if ( elementIsRequired == null || !elementIsRequired.equals("true")||addType != null) {
+ sb1.append(" minOccurs=\"0\"");
+ }
+ if ( elementContainerType != null && elementContainerType.equals("java.util.ArrayList")) {
+ sb1.append(" maxOccurs=\"unbounded\"");
+ }
+ properties = GenerateXsd.locateXmlProperties(xmlElementElement);
+ if (properties != null || elementIsKey != null) {
+ sb1.append(">\n");
+ sb1.append(" <xs:annotation>\r\n");
+ insertAnnotation(properties, elementIsKey != null, "field", sb1, " ");
+ sb1.append(" </xs:annotation>\r\n");
+
+ if (xmlElementWrapper== null) {
+ sb1.append(" </xs:element>\n");
+ }
+ } else {
+ sb1.append("/>\n");
+ }
+ if ( xmlElementWrapper != null ) {
+ sb1.append(" </xs:sequence>\n");
+ sb1.append(" </xs:complexType>\n");
+ sb1.append(" </xs:element>\n");
+ }
+ }
+ /*
+ if ( xmlRootElementName.equals("notify") ||
+ xmlRootElementName.equals("relationship") ||
+ xmlRootElementName.equals("relationship-data") ||
+ xmlRootElementName.equals("related-to-property") )
+
+ sb1.append(" <xs:any namespace=\"##other\" processContents=\"lax\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n");
+ */
+ sb1.append(" </xs:sequence>\n");
+ sb1.append(" </xs:complexType>\n");
+ sb1.append(" </xs:element>\n");
+ }
+ /*
+ NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
+ Element valElement = (Element) valNodes.item(0);
+ attributes = valElement.getAttributes();
+ for ( int i = 0; i < attributes.getLength(); ++i ) {
+ Attr attr = (Attr) attributes.item(i);
+ String attrName = attr.getNodeName();
+
+ String attrValue = attr.getNodeValue();
+ System.out.println("Found xml-root-element attribute: " + attrName + " with value: " + attrValue);
+ if ( attrValue.equals("name"))
+ xmlRootElementName = attrValue;
+ }
+ */
+
+ if ( xmlElementNodes.getLength() < 1 ) {
+ sb.append(" <xs:element name=\"" + xmlRootElementName + "\">\n");
+ sb.append(" <xs:complexType>\n");
+ sb.append(" <xs:sequence/>\n");
+ sb.append(" </xs:complexType>\n");
+ sb.append(" </xs:element>\n");
+ generatedJavaType.put(javaTypeName, null);
+ return sb.toString();
+ }
+
+ sb.append( sb1 );
+
+ return sb.toString();
+ }
+
+ private static void insertAnnotation(NodeList items, boolean isKey, String target, StringBuffer sb1, String indentation) {
+ if (items != null || isKey) {
+ List<String> metadata = new ArrayList<>();
+
+ String name = "";
+ String value = "";
+ Element item = null;
+ if (isKey) {
+ metadata.add("isKey=true");
+ }
+ if (items != null) {
+ for (int i = 0; i < items.getLength(); i++) {
+ item = (Element)items.item(i);
+ name = item.getAttribute("name");
+ value = item.getAttribute("value");
+ if (name.equals("abstract")) {
+ name = "isAbstract";
+ } else if (name.equals("extends")) {
+ name = "extendsFrom";
+ }
+ metadata.add(name + "=\"" + value.replaceAll("&", "&amp;") + "\"");
+ System.out.println("property name: " + name);
+
+ }
+ }
+ sb1.append(
+ indentation + " <xs:appinfo>\r\n" +
+ indentation + " <annox:annotate target=\""+target+"\">@org.openecomp.aai.annotations.Metadata(" + Joiner.on(",").join(metadata) + ")</annox:annotate>\r\n" +
+ indentation + " </xs:appinfo>\r\n");
+ }
+
+ }
+
+ private static Element getJavaTypeElement( String javaTypeName )
+ {
+
+ String attrName, attrValue;
+ Attr attr;
+ Element javaTypeElement;
+ for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) {
+ javaTypeElement = (Element) javaTypeNodes.item(i);
+ NamedNodeMap attributes = javaTypeElement.getAttributes();
+ for ( int j = 0; j < attributes.getLength(); ++j ) {
+ attr = (Attr) attributes.item(j);
+ attrName = attr.getNodeName();
+ attrValue = attr.getNodeValue();
+ if ( attrName.equals("name") && attrValue.equals(javaTypeName))
+ return javaTypeElement;
+ }
+ }
+ System.out.println( "oxm file format error, missing java-type " + javaTypeName);
+ return (Element) null;
+ }
+
+ private static Element getJavaTypeElementSwagger( String javaTypeName )
+ {
+
+ String attrName, attrValue;
+ Attr attr;
+ Element javaTypeElement;
+ for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) {
+ javaTypeElement = (Element) javaTypeNodes.item(i);
+ NamedNodeMap attributes = javaTypeElement.getAttributes();
+ for ( int j = 0; j < attributes.getLength(); ++j ) {
+ attr = (Attr) attributes.item(j);
+ attrName = attr.getNodeName();
+ attrValue = attr.getNodeValue();
+ if ( attrName.equals("name") && attrValue.equals(javaTypeName))
+ return javaTypeElement;
+ }
+ }
+ System.out.println( "oxm file format error, missing java-type " + javaTypeName);
+ return (Element) null;
+ }
+ private static String getXmlRootElementName( String javaTypeName )
+ {
+
+ String attrName, attrValue;
+ Attr attr;
+ Element javaTypeElement;
+ for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) {
+ javaTypeElement = (Element) javaTypeNodes.item(i);
+ NamedNodeMap attributes = javaTypeElement.getAttributes();
+ for ( int j = 0; j < attributes.getLength(); ++j ) {
+ attr = (Attr) attributes.item(j);
+ attrName = attr.getNodeName();
+ attrValue = attr.getNodeValue();
+ if ( attrName.equals("name") && attrValue.equals(javaTypeName)) {
+ NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
+ Element valElement = (Element) valNodes.item(0);
+ attributes = valElement.getAttributes();
+ for ( int k = 0; k < attributes.getLength(); ++k ) {
+ attr = (Attr) attributes.item(k);
+ attrName = attr.getNodeName();
+
+ attrValue = attr.getNodeValue();
+ //System.out.println("Found xml-root-element attribute: " + attrName + " with value: " + attrValue);
+ if ( attrName.equals("name"))
+ return (attrValue);
+ }
+ }
+ }
+ }
+ System.out.println( "oxm file format error, missing java-type " + javaTypeName);
+ return null;
+ }
+
+
+ public static String processOxmFile( File oxmFile )
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n");
+ String namespace = "org.openecomp";
+ sb.append("<xs:schema elementFormDefault=\"qualified\" version=\"1.0\" targetNamespace=\"http://" + namespace + ".aai.inventory/"
+ + apiVersion + "\" xmlns:tns=\"http://" + namespace + ".aai.inventory/" + apiVersion + "\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
+ + "\n"
+ + "xmlns:jaxb=\"http://java.sun.com/xml/ns/jaxb\"\r\n" +
+ " jaxb:version=\"2.1\" \r\n" +
+ " xmlns:annox=\"http://annox.dev.java.net\" \r\n" +
+ " jaxb:extensionBindingPrefixes=\"annox\">\n\n");
+
+ try {
+
+ DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+ dbFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+ Document doc = dBuilder.parse(oxmFile);
+
+ NodeList bindingsNodes = doc.getElementsByTagName("xml-bindings");
+ Element bindingElement;
+ NodeList javaTypesNodes;
+ Element javaTypesElement;
+
+ Element javaTypeElement;
+
+
+ if ( bindingsNodes == null || bindingsNodes.getLength() == 0 ) {
+ System.out.println( "missing <binding-nodes> in " + oxmFile );
+ return null;
+ }
+
+ bindingElement = (Element) bindingsNodes.item(0);
+ javaTypesNodes = bindingElement.getElementsByTagName("java-types");
+ if ( javaTypesNodes.getLength() < 1 ) {
+ System.out.println( "missing <binding-nodes><java-types> in " + oxmFile );
+ return null;
+ }
+ javaTypesElement = (Element) javaTypesNodes.item(0);
+ javaTypeNodes = javaTypesElement.getElementsByTagName("java-type");
+ if ( javaTypeNodes.getLength() < 1 ) {
+ System.out.println( "missing <binding-nodes><java-types><java-type> in " + oxmFile );
+ return null;
+ }
+
+ String javaTypeName;
+ String attrName, attrValue;
+ Attr attr;
+ for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) {
+ javaTypeElement = (Element) javaTypeNodes.item(i);
+ NamedNodeMap attributes = javaTypeElement.getAttributes();
+ javaTypeName = null;
+ for ( int j = 0; j < attributes.getLength(); ++j ) {
+ attr = (Attr) attributes.item(j);
+ attrName = attr.getNodeName();
+ attrValue = attr.getNodeValue();
+ if ( attrName.equals("name"))
+ javaTypeName = attrValue;
+ }
+ if ( javaTypeName == null ) {
+ System.out.println( "<java-type> has no name attribute in " + oxmFile );
+ return null;
+ }
+ if ("Nodes".equals(javaTypeName)) {
+ System.out.println("skipping Nodes entry (temporary feature)");
+ continue;
+ }
+ if ( !generatedJavaType.containsKey(javaTypeName) ) {
+ generatedJavaType.put(javaTypeName, null);
+ sb.append(processJavaTypeElement( javaTypeName, javaTypeElement ));
+ }
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ sb.append("</xs:schema>\n");
+ return sb.toString();
+ }
+
+ private static boolean isStandardType( String elementType )
+ {
+ switch ( elementType ) {
+ case "java.lang.String":
+ case "java.lang.Long":
+ case "java.lang.Integer":
+ case"java.lang.Boolean":
+ return true;
+ }
+ return false;
+ }
+
+ private static Vector<String> getIndexedProps( String attrValue )
+ {
+ if ( attrValue == null )
+ return null;
+ StringTokenizer st = new StringTokenizer( attrValue, ",");
+ if ( st.countTokens() == 0 )
+ return null;
+ Vector<String> result = new Vector<String>();
+ while ( st.hasMoreTokens()) {
+ result.add(st.nextToken());
+ }
+ return result;
+ }
+
+ private static Class<?> getEdgeRulesClass() throws ClassNotFoundException {
+ Class<?> result = null;
+
+ // If a class matching the apiVersion exists, we are generating documentation for a prior release
+ // Otherwise, we're generated documentation for the current release.
+ try {
+ result = Class.forName("org.openecomp.aai.dbmodel." + apiVersion +".gen.DbEdgeRules");
+ } catch (ClassNotFoundException ex) {
+ result = Class.forName("org.openecomp.aai.dbmodel.DbEdgeRules");
+ }
+ return result;
+ }
+
+ /**
+ * Guaranteed to at least return non null but empty collection of edge descriptions
+ * @param nodeName name of the vertex whose edge relationships to return
+ * @return collection of node neighbors based on DbEdgeRules
+ */
+ private static Collection<EdgeDescription> getEdgeRules( String nodeName )
+ {
+
+ ArrayList<EdgeDescription> result = new ArrayList<>();
+ Iterator<String> edgeRulesIterator;
+
+ try {
+
+ Field mapfield = versionedClass.getField("EdgeRules");
+ Object map = mapfield.get(null);
+ if (map instanceof Multimap<?,?>) {
+ edgeRulesIterator = ((Multimap<String,String>) map).keySet().iterator();
+ } else {
+ throw new NoSuchFieldException ("Didn't get back the multimap field expected");
+ }
+ GenerateXsd x = new GenerateXsd();
+
+ while( edgeRulesIterator.hasNext() ){
+ String ruleKey = edgeRulesIterator.next();
+ if ( ruleKey.startsWith(nodeName + "|" ) ||
+ ruleKey.endsWith("|" + nodeName)) {
+ Collection <String> edRuleColl = DbEdgeRules.EdgeRules.get(ruleKey);
+ Iterator <String> ruleItr = edRuleColl.iterator();
+ while( ruleItr.hasNext() ){
+ EdgeDescription edgeDes = x.new EdgeDescription();
+ edgeDes.setRuleKey(ruleKey);
+ String fullRuleString = ruleItr.next();
+ String[] toks = fullRuleString.split(",");
+ if (toks != null) {
+ if (toks.length > 1) {
+ edgeDes.setDirection(toks[1]);
+ }
+ if (toks.length > 2) {
+ edgeDes.setMultiplicity(toks[2]);
+ }
+ if (toks.length > 3) {
+ if (toks[3].equals("true"))
+ edgeDes.setType(LineageType.PARENT);
+ else if (toks[3].equals("parent"))
+ edgeDes.setType(LineageType.PARENT);
+ else if (toks[3].equals("child"))
+ edgeDes.setType(LineageType.CHILD);
+ else
+ edgeDes.setType(LineageType.UNRELATED);
+ }
+ if (toks.length > 5) {
+ edgeDes.setHasDelTarget(toks[5]);;
+ }
+ }
+
+ //System.out.println( "nodeName " + nodeName + " ruleKey " + ruleKey + " ruleString " + fullRuleString);
+ //result.add(ruleKey + "-" + fullRuleString);
+ result.add(edgeDes);
+ }
+ }
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ return result;
+ }
+
+ /**
+ * Finds the default delete scope from DBEdgeRules
+ * @param nodeName name of vertex whose delete scope to return
+ * @return default delete scope of the input nodeName, null if none.
+ */
+ private static String getDeleteRules( String nodeName )
+ {
+ String result = null;
+ Iterator<String> delRulesIterator;
+
+ try {
+
+ Field mapfield = versionedClass.getField("DefaultDeleteScope");
+ Object map = mapfield.get(null);
+ if (map instanceof Multimap<?,?>) {
+ delRulesIterator = ((Multimap<String,String>) map).keySet().iterator();
+ } else {
+ throw new NoSuchFieldException ("Didn't get back the multimap field expected");
+ }
+
+ while( delRulesIterator.hasNext() ){
+ String ruleKey = delRulesIterator.next();
+ if ( ruleKey.equals(nodeName)) {
+ Collection <String> deRuleColl = DbEdgeRules.DefaultDeleteScope.get(ruleKey);
+ Iterator <String> ruleItr = deRuleColl.iterator();
+ if( ruleItr.hasNext() ){
+ result = ruleItr.next();
+ }
+ }
+ }
+
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ return result;
+ }
+
+ public static String processJavaTypeElementSwagger( String javaTypeName, Element javaTypeElement,
+ StringBuffer pathSb, StringBuffer definitionsSb, String path, String tag, String opId,
+ String getItemName, StringBuffer pathParams, String queryParams, String validEdges) {
+
+ String xmlRootElementName = null;
+
+ //Map<String, String> addJavaType = new HashMap<String, String>();
+ String useTag = null;
+ String useOpId = null;
+
+ if ( tag != null ) {
+ switch ( tag ) {
+ case "Network":
+ case "ServiceDesignAndCreation":
+ case "Business":
+ case "CloudInfrastructure":
+ break;
+ default:
+ return null;
+ }
+ }
+
+ if ( !javaTypeName.equals("Inventory") ) {
+ if ( javaTypeName.equals("AaiInternal"))
+ return null;
+ if ( opId == null )
+ useOpId = javaTypeName;
+ else
+ useOpId = opId + javaTypeName;
+ if ( tag == null )
+ useTag = javaTypeName;
+ }
+
+ NodeList parentNodes = javaTypeElement.getElementsByTagName("java-attributes");
+
+ if ( parentNodes.getLength() == 0 ) {
+ System.out.println( "no java-attributes for java-type " + javaTypeName);
+ return "";
+
+ }
+
+ NamedNodeMap attributes;
+
+ NodeList valNodes = javaTypeElement.getElementsByTagName("xml-root-element");
+ Element valElement = (Element) valNodes.item(0);
+ attributes = valElement.getAttributes();
+ for ( int i = 0; i < attributes.getLength(); ++i ) {
+ Attr attr = (Attr) attributes.item(i);
+ String attrName = attr.getNodeName();
+
+ String attrValue = attr.getNodeValue();
+ //System.out.println("Found xml-root-element attribute: " + attrName + " with value: " + attrValue);
+ if ( attrName.equals("name"))
+ xmlRootElementName = attrValue;
+ }
+ /*
+ if ( xmlRootElementName.equals("oam-networks"))
+ System.out.println( "xmlRootElement oam-networks with getItemData [" + getItemName + "]");
+ */
+ //already processed
+ /*
+ if ( generatedJavaType.containsKey(xmlRootElementName) ) {
+ return null;
+ }
+ */
+ NodeList childNodes;
+ Element childElement;
+ NodeList xmlPropNodes = javaTypeElement.getElementsByTagName("xml-properties");
+ Element xmlPropElement;
+ String pathDescriptionProperty = null;
+
+
+ Vector<String> indexedProps = null;
+
+ /*System.out.println( "javaTypeName " + javaTypeName + " has xml-properties length " + xmlPropNodes.getLength());
+ if ( path != null && path.equals("/network/generic-vnfs"))
+ System.out.println("path is " + "/network/generic-vnfs with getItemName " + getItemName);
+ */
+ if ( xmlPropNodes.getLength() > 0 ) {
+
+ for ( int i = 0; i < xmlPropNodes.getLength(); ++i ) {
+ xmlPropElement = (Element)xmlPropNodes.item(i);
+ if ( !xmlPropElement.getParentNode().isSameNode(javaTypeElement))
+ continue;
+ childNodes = xmlPropElement.getElementsByTagName("xml-property");
+
+ if ( childNodes.getLength() > 0 ) {
+ for ( int j = 0; j < childNodes.getLength(); ++j ) {
+ childElement = (Element)childNodes.item(j);
+ // get name
+ int useValue = VALUE_NONE;
+ attributes = childElement.getAttributes();
+ for ( int k = 0; k < attributes.getLength(); ++k ) {
+ Attr attr = (Attr) attributes.item(k);
+ String attrName = attr.getNodeName();
+ String attrValue = attr.getNodeValue();
+ if ( attrName == null || attrValue == null )
+ continue;
+ if ( attrName.equals("name") && attrValue.equals("description")) {
+ useValue = VALUE_DESCRIPTION;
+ }
+ if ( useValue == VALUE_DESCRIPTION && attrName.equals("value")) {
+ pathDescriptionProperty = attrValue;
+ //break;
+ //System.out.println("found xml-element-wrapper " + xmlElementWrapper);
+ }
+ if ( attrValue.equals("indexedProps")) {
+ useValue = VALUE_INDEXED_PROPS;
+ }
+ if ( useValue == VALUE_INDEXED_PROPS && attrName.equals("value")) {
+ indexedProps = getIndexedProps( attrValue );
+ }
+ }
+ }
+ }
+ }
+ }
+ //System.out.println("javaTypeName " + javaTypeName + " description " + pathDescriptionProperty);
+
+ /*
+ if ( javaTypeName.equals("RelationshipList")) {
+ System.out.println( "Skipping " + javaTypeName);
+ generatedJavaType.put(javaTypeName, null);
+ return "";
+ }
+ */
+
+ Element parentElement = (Element)parentNodes.item(0);
+ NodeList xmlElementNodes = parentElement.getElementsByTagName("xml-element");
+
+
+ String attrDescription = null;
+
+ Element xmlElementElement;
+ String addType = null;
+ String elementType = null, elementIsKey = null, elementIsRequired, elementContainerType = null;
+ String elementName = null;
+ StringBuffer sbParameters = new StringBuffer();
+
+ StringBuffer sbRequired = new StringBuffer();
+ int requiredCnt = 0;
+ int propertyCnt = 0;
+ StringBuffer sbProperties = new StringBuffer();
+ StringBuffer sbIndexedParams = new StringBuffer();
+
+
+ StringTokenizer st;
+ if ( xmlRootElementName.equals("inventory"))
+ path = "";
+ else if ( path == null )
+ //path = "/aai/" + apiVersion;
+ path = "/" + xmlRootElementName;
+ else
+ path += "/" + xmlRootElementName;
+ st = new StringTokenizer(path, "/");
+ /*
+ if ( path.equals("/business/customers/customer/{global-customer-id}/service-subscriptions/service-subscription"))
+ System.out.println("processing path /business/customers/customer/{global-customer-id}/service-subscriptions with tag " + tag);
+ */
+ boolean genPath = false;
+ /*
+ if ( path != null && path.equals("/network/generic-vnfs/generic-vnf"))
+ System.out.println("path is " + "/network/generic-vnfs/generic-vnf");
+ */
+ if ( st.countTokens() > 1 && getItemName == null ) {
+ if ( appliedPaths.containsKey(path))
+ return null;
+ appliedPaths.put(path, null);
+ genPath = true;
+ if ( path.contains("/relationship/") ) { // filter paths with relationship-list
+ genPath = false;
+ }
+ if ( path.endsWith("/relationship-list")) {
+ genPath = false;
+ }
+
+ }
+
+ Vector<String> addTypeV = null;
+ if ( xmlElementNodes.getLength() > 0 ) {
+
+ for ( int i = 0; i < xmlElementNodes.getLength(); ++i ) {
+ xmlElementElement = (Element)xmlElementNodes.item(i);
+ if ( !xmlElementElement.getParentNode().isSameNode(parentElement))
+ continue;
+ /*childNodes = xmlElementElement.getElementsByTagName("xml-element-wrapper");
+ if ( childNodes.getLength() > 0 ) {
+ childElement = (Element)childNodes.item(0);
+ // get name
+ attributes = childElement.getAttributes();
+ for ( int k = 0; k < attributes.getLength(); ++k ) {
+ Attr attr = (Attr) attributes.item(k);
+ String attrName = attr.getNodeName();
+ String attrValue = attr.getNodeValue();
+ if ( attrName.equals("name")) {
+ xmlElementWrapper = attrValue;
+ //System.out.println("found xml-element-wrapper " + xmlElementWrapper);
+ }
+ }
+
+ }
+ */
+ valNodes = xmlElementElement.getElementsByTagName("xml-properties");
+ attrDescription = null;
+ if ( valNodes.getLength() > 0 ) {
+ for ( int j = 0; j < valNodes.getLength(); ++j ) {
+ valElement = (Element)valNodes.item(j);
+ if ( !valElement.getParentNode().isSameNode(xmlElementElement))
+ continue;
+ childNodes = valElement.getElementsByTagName("xml-property");
+ if ( childNodes.getLength() > 0 ) {
+ childElement = (Element)childNodes.item(0);
+ // get name
+ attributes = childElement.getAttributes();
+ attrDescription = null;
+ boolean useValue = false;
+ for ( int k = 0; k < attributes.getLength(); ++k ) {
+ Attr attr = (Attr) attributes.item(k);
+ String attrName = attr.getNodeName();
+ String attrValue = attr.getNodeValue();
+ if ( attrName.equals("name") && attrValue.equals("description")) {
+ useValue = true;
+ }
+ if ( useValue && attrName.equals("value")) {
+ attrDescription = attrValue;
+ //System.out.println("found xml-element-wrapper " + xmlElementWrapper);
+ }
+ }
+
+ }
+ }
+ }
+
+ attributes = xmlElementElement.getAttributes();
+ addTypeV = null; // vector of 1
+ addType = null;
+
+ elementName = elementType = elementIsKey = elementIsRequired = elementContainerType = null;
+ for ( int j = 0; j < attributes.getLength(); ++j ) {
+ Attr attr = (Attr) attributes.item(j);
+ String attrName = attr.getNodeName();
+
+ String attrValue = attr.getNodeValue();
+ //System.out.println("For " + xmlRootElementName + " Found xml-element attribute: " + attrName + " with value: " + attrValue);
+ if ( attrName.equals("name")) {
+ elementName = attrValue;
+
+ }
+ if ( attrName.equals("type") && getItemName == null ) {
+ elementType = attrValue;
+ if ( attrValue.contains(apiVersionFmt) ) {
+ addType = attrValue.substring(attrValue.lastIndexOf('.')+1);
+ if ( addTypeV == null )
+ addTypeV = new Vector<String>();
+ addTypeV.add(addType);
+ }
+
+ }
+ if ( attrName.equals("xml-key")) {
+ elementIsKey = attrValue;
+ path += "/{" + elementName + "}";
+ }
+ if ( attrName.equals("required")) {
+ elementIsRequired = attrValue;
+ }
+ if ( attrName.equals("container-type")) {
+ elementContainerType = attrValue;
+ }
+ }
+ if ( getItemName != null ) {
+ if ( getItemName.equals("array") ) {
+ if ( elementContainerType != null && elementContainerType.equals("java.util.ArrayList")) {
+ //System.out.println( " returning array " + elementName );
+ return elementName;
+ }
+
+ } else { // not an array check
+ if ( elementContainerType == null || !elementContainerType.equals("java.util.ArrayList")) {
+ //System.out.println( " returning object " + elementName );
+ return elementName;
+ }
+
+ }
+ //System.out.println( " returning null" );
+ return null;
+ }
+ if ( elementIsRequired != null ) {
+ if ( requiredCnt == 0 )
+ sbRequired.append(" required:\n");
+ ++requiredCnt;
+ if ( addTypeV != null ) {
+ for ( int k = 0; k < addTypeV.size(); ++i ) {
+ sbRequired.append(" - " + getXmlRootElementName(addTypeV.elementAt(k)) + ":\n");
+ }
+ } else
+ sbRequired.append(" - " + elementName + "\n");
+
+ }
+
+ if ( elementIsKey != null ) {
+ sbParameters.append((" - name: " + elementName + "\n"));
+ sbParameters.append((" in: path\n"));
+ if ( attrDescription != null && attrDescription.length() > 0 )
+ sbParameters.append((" description: " + attrDescription + "\n"));
+ sbParameters.append((" required: true\n"));
+ if ( elementType.equals("java.lang.String"))
+ sbParameters.append(" type: string\n");
+ if ( elementType.equals("java.lang.Long")) {
+ sbParameters.append(" type: integer\n");
+ sbParameters.append(" format: int64\n");
+ }
+ if ( elementType.equals("java.lang.Integer")) {
+ sbParameters.append(" type: integer\n");
+ sbParameters.append(" format: int32\n");
+ }
+ if ( elementType.equals("java.lang.Boolean"))
+ sbParameters.append(" type: boolean\n");
+
+
+ } else if ( indexedProps != null
+ && indexedProps.contains(elementName ) ) {
+ sbIndexedParams.append((" - name: " + elementName + "\n"));
+ sbIndexedParams.append((" in: query\n"));
+ if ( attrDescription != null && attrDescription.length() > 0 )
+ sbIndexedParams.append((" description: " + attrDescription + "\n"));
+ sbIndexedParams.append((" required: false\n"));
+ if ( elementType.equals("java.lang.String"))
+ sbIndexedParams.append(" type: string\n");
+ if ( elementType.equals("java.lang.Long")) {
+ sbIndexedParams.append(" type: integer\n");
+ sbIndexedParams.append(" format: int64\n");
+ }
+ if ( elementType.equals("java.lang.Integer")) {
+ sbIndexedParams.append(" type: integer\n");
+ sbIndexedParams.append(" format: int32\n");
+ }
+ if ( elementType.equals("java.lang.Boolean"))
+ sbIndexedParams.append(" type: boolean\n");
+ }
+
+ /*
+ if ( elementName != null && elementName.equals("inventory-item"))
+ System.out.println( "processing inventory-item elementName");
+ */
+
+ if ( isStandardType(elementType)) {
+ sbProperties.append(" " + elementName + ":\n");
+ ++propertyCnt;
+ sbProperties.append(" type: ");
+
+ if ( elementType.equals("java.lang.String"))
+ sbProperties.append("string\n");
+ else if ( elementType.equals("java.lang.Long")) {
+ sbProperties.append("integer\n");
+ sbProperties.append(" format: int64\n");
+ }
+ else if ( elementType.equals("java.lang.Integer")){
+ sbProperties.append("integer\n");
+ sbProperties.append(" format: int32\n");
+ }
+ else if ( elementType.equals("java.lang.Boolean"))
+ sbProperties.append("boolean\n");
+ if ( attrDescription != null && attrDescription.length() > 0 )
+ sbProperties.append(" description: " + attrDescription + "\n");
+ }
+
+ //if ( addType != null && elementContainerType != null && elementContainerType.equals("java.util.ArrayList") ) {
+
+ if ( addTypeV != null ) {
+ StringBuffer newPathParams = null;
+ if ( pathParams != null ) {
+ newPathParams = new StringBuffer();
+ newPathParams.append(pathParams);
+ }
+ if ( sbParameters.toString().length() > 0 ) {
+ if ( newPathParams == null )
+ newPathParams = new StringBuffer();
+ newPathParams.append(sbParameters);
+ }
+ String newQueryParams = null;
+ if ( sbIndexedParams.toString().length() > 0 ) {
+ if ( queryParams == null )
+ newQueryParams = sbIndexedParams.toString();
+ else
+ newQueryParams = queryParams + sbIndexedParams.toString();
+ } else {
+ newQueryParams = queryParams;
+ }
+ for ( int k = 0; k < addTypeV.size(); ++k ) {
+ addType = addTypeV.elementAt(k);
+
+ if ( opId == null || !opId.contains(addType)) {
+ processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType),
+ pathSb, definitionsSb, path, tag == null ? useTag : tag, useOpId, null,
+ newPathParams, newQueryParams, validEdges);
+ }
+ // need item name of array
+ String itemName = processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType),
+ pathSb, definitionsSb, path, tag == null ? useTag : tag, useOpId,
+ "array", null, null, null );
+
+ if ( itemName != null ) {
+ if ( addType.equals("AaiInternal") ) {
+ //System.out.println( "addType AaiInternal, skip properties");
+
+ } else if ( getItemName == null) {
+ ++propertyCnt;
+ sbProperties.append(" " + getXmlRootElementName(addType) + ":\n");
+ sbProperties.append(" type: array\n items:\n");
+ sbProperties.append(" $ref: \"#/definitions/" + itemName + "\"\n");
+ if ( attrDescription != null && attrDescription.length() > 0 )
+ sbProperties.append(" description: " + attrDescription + "\n");
+ }
+ } else {
+ /*itemName = processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType),
+ pathSb, definitionsSb, path, tag == null ? useTag : tag, useOpId, "other" );
+ if ( itemName != null ) {
+ */
+ if ( elementContainerType != null && elementContainerType.equals("java.util.ArrayList")) {
+ // need properties for getXmlRootElementName(addType)
+ newPathParams = null;
+ if ( pathParams != null ) {
+ newPathParams = new StringBuffer();
+ newPathParams.append(pathParams);
+ }
+ if ( sbParameters.toString().length() > 0 ) {
+ if ( newPathParams == null )
+ newPathParams = new StringBuffer();
+ newPathParams.append(sbParameters);
+ }
+ newQueryParams = null;
+ if ( sbIndexedParams.toString().length() > 0 ) {
+ if ( queryParams == null )
+ newQueryParams = sbIndexedParams.toString();
+ else
+ newQueryParams = queryParams + sbIndexedParams.toString();
+ } else {
+ newQueryParams = queryParams;
+ }
+ processJavaTypeElementSwagger( addType, getJavaTypeElementSwagger(addType),
+ pathSb, definitionsSb, path, tag == null ? useTag : tag, useOpId,
+ null, newPathParams, newQueryParams, validEdges );
+ sbProperties.append(" " + getXmlRootElementName(addType) + ":\n");
+ sbProperties.append(" type: array\n items: \n");
+ sbProperties.append(" $ref: \"#/definitions/" + getXmlRootElementName(addType) + "\"\n");
+ } else {
+ sbProperties.append(" " + getXmlRootElementName(addType) + ":\n");
+ sbProperties.append(" type: object\n");
+ sbProperties.append(" $ref: \"#/definitions/" + getXmlRootElementName(addType) + "\"\n");
+ }
+ if ( attrDescription != null && attrDescription.length() > 0 )
+ sbProperties.append(" description: " + attrDescription + "\n");
+ ++propertyCnt;
+ /*}
+ else {
+ System.out.println(" unable to define swagger object for " + addType);
+ }
+ */
+ }
+ //if ( getItemName == null) looking for missing properties
+ //generatedJavaType.put(addType, null);
+ }
+ }
+ }
+ }
+ if ( genPath ) {
+ /*
+ if ( useOpId.equals("CloudInfrastructureComplexesComplexCtagPools"))
+ System.out.println( "adding path CloudInfrastructureComplexesComplexCtagPools");
+ */
+
+ if ( !path.endsWith("/relationship") ) {
+ pathSb.append(" " + path + ":\n" );
+ pathSb.append(" get:\n");
+ pathSb.append(" tags:\n");
+ pathSb.append(" - " + tag + "\n");
+ pathSb.append(" summary: returns " + xmlRootElementName + "\n");
+
+ pathSb.append(" description: returns " + xmlRootElementName + "\n");
+ pathSb.append(" operationId: get" + useOpId + "\n");
+ pathSb.append(" produces:\n");
+ pathSb.append(" - application/json\n");
+ pathSb.append(" - application/xml\n");
+
+ pathSb.append(" responses:\n");
+ pathSb.append(" \"200\":\n");
+ pathSb.append(" description: successful operation\n");
+ pathSb.append(" schema:\n");
+ pathSb.append(" $ref: \"#/definitions/" + xmlRootElementName + "\"\n");
+ pathSb.append(" \"default\":\n");
+ pathSb.append(" " + responsesUrl);
+ /*
+ pathSb.append(" \"200\":\n");
+ pathSb.append(" description: successful operation\n");
+ pathSb.append(" schema:\n");
+ pathSb.append(" $ref: \"#/definitions/" + xmlRootElementName + "\"\n");
+ pathSb.append(" \"404\":\n");
+ pathSb.append(" description: resource was not found\n");
+ pathSb.append(" \"400\":\n");
+ pathSb.append(" description: bad request\n");
+ */
+ if ( path.indexOf('{') > 0 ) {
+
+ if ( sbParameters.toString().length() > 0 ) {
+ if ( pathParams == null )
+ pathParams = new StringBuffer();
+ pathParams.append(sbParameters);
+ }
+ if ( pathParams != null) {
+ pathSb.append(" parameters:\n");
+ pathSb.append(pathParams);
+ } else
+ System.out.println( "null pathParams for " + useOpId);
+ if ( sbIndexedParams.toString().length() > 0 ) {
+ if ( queryParams == null )
+ queryParams = sbIndexedParams.toString();
+ else
+ queryParams = queryParams + sbIndexedParams.toString();
+ }
+ if ( queryParams != null ) {
+ if ( pathParams == null ) {
+ pathSb.append(" parameters:\n");
+ }
+ pathSb.append(queryParams);
+ }
+ }
+ }
+ boolean skipPutDelete = false; // no put or delete for "all"
+ if ( !path.endsWith("/relationship") ) {
+ if ( !path.endsWith("}") ){
+ skipPutDelete = true;
+ }
+
+ }
+ if ( path.indexOf('{') > 0 && !opId.startsWith("Search") &&!skipPutDelete) {
+ // add PUT
+ if ( path.endsWith("/relationship") ) {
+ pathSb.append(" " + path + ":\n" );
+ }
+ pathSb.append(" put:\n");
+ pathSb.append(" tags:\n");
+ pathSb.append(" - " + tag + "\n");
+
+ if ( path.endsWith("/relationship") ) {
+ pathSb.append(" summary: see node definition for valid relationships\n");
+ } else {
+ pathSb.append(" summary: create or update an existing " + xmlRootElementName + "\n");
+ pathSb.append(" description: create or update an existing " + xmlRootElementName + "\n");
+ }
+ pathSb.append(" operationId: createOrUpdate" + useOpId + "\n");
+ pathSb.append(" consumes:\n");
+ pathSb.append(" - application/json\n");
+ pathSb.append(" - application/xml\n");
+ pathSb.append(" produces:\n");
+ pathSb.append(" - application/json\n");
+ pathSb.append(" - application/xml\n");
+ pathSb.append(" responses:\n");
+ pathSb.append(" \"default\":\n");
+ pathSb.append(" " + responsesUrl);
+ /*
+ pathSb.append(" responses:\n");
+ pathSb.append(" \"200\":\n");
+ pathSb.append(" description: existing resource has been modified and there is a response buffer\n");
+ pathSb.append(" \"201\":\n");
+ pathSb.append(" description: new resource is created\n");
+ pathSb.append(" \"202\":\n");
+ pathSb.append(" description: action requested but may have taken other actions as well, which are returned in the response payload\n");
+ pathSb.append(" \"204\":\n");
+ pathSb.append(" description: existing resource has been modified and there is no response buffer\n");
+ pathSb.append(" \"400\":\n");
+ pathSb.append(" description: Bad Request will be returned if headers are missing\n");
+ pathSb.append(" \"404\":\n");
+ pathSb.append(" description: Not Found will be returned if an unknown URL is used\n");
+ */
+ pathSb.append(" parameters:\n");
+ //pathSb.append(" - in: path\n");
+ pathSb.append(pathParams); // for nesting
+ pathSb.append(" - name: body\n");
+ pathSb.append(" in: body\n");
+ pathSb.append(" description: " + xmlRootElementName + " object that needs to be created or updated\n");
+ pathSb.append(" required: true\n");
+ pathSb.append(" schema:\n");
+ pathSb.append(" $ref: \"#/definitions/" + xmlRootElementName + "\"\n");
+ /*
+ if ( queryParams != null ) {
+ pathSb.append(queryParams);
+ }
+ */
+ // add DELETE
+ pathSb.append(" delete:\n");
+ pathSb.append(" tags:\n");
+ pathSb.append(" - " + tag + "\n");
+ pathSb.append(" summary: delete an existing " + xmlRootElementName + "\n");
+
+ pathSb.append(" description: delete an existing " + xmlRootElementName + "\n");
+
+ pathSb.append(" operationId: delete" + useOpId + "\n");
+ pathSb.append(" consumes:\n");
+ pathSb.append(" - application/json\n");
+ pathSb.append(" - application/xml\n");
+ pathSb.append(" produces:\n");
+ pathSb.append(" - application/json\n");
+ pathSb.append(" - application/xml\n");
+ pathSb.append(" responses:\n");
+ pathSb.append(" \"default\":\n");
+ pathSb.append(" " + responsesUrl);
+ /*
+ pathSb.append(" responses:\n");
+ pathSb.append(" \"200\":\n");
+ pathSb.append(" description: successful, the response includes an entity describing the status\n");
+ pathSb.append(" \"204\":\n");
+ pathSb.append(" description: successful, action has been enacted but the response does not include an entity\n");
+ pathSb.append(" \"400\":\n");
+ pathSb.append(" description: Bad Request will be returned if headers are missing\n");
+ pathSb.append(" \"404\":\n");
+ pathSb.append(" description: Not Found will be returned if an unknown URL is used\n");
+ */
+ pathSb.append(" parameters:\n");
+ //pathSb.append(" - in: path\n");
+ pathSb.append(pathParams); // for nesting
+ if ( !path.endsWith("/relationship") ) {
+ pathSb.append(" - name: resource-version\n");
+
+ pathSb.append(" in: query\n");
+ pathSb.append(" description: resource-version for concurrency\n");
+ pathSb.append(" required: true\n");
+ pathSb.append(" type: string\n");
+ }
+ /*
+ if ( queryParams != null ) {
+ pathSb.append(queryParams);
+ }
+ */
+ }
+
+ }
+ if ( generatedJavaType.containsKey(xmlRootElementName) ) {
+ return null;
+ }
+
+ definitionsSb.append(" " + xmlRootElementName + ":\n");
+ Collection<EdgeDescription> edges = getEdgeRules(xmlRootElementName );
+ if ( edges.size() > 0 ) {
+ StringBuffer sbEdge = new StringBuffer();
+ sbEdge.append(" ###### Related Nodes\n");
+ for (EdgeDescription ed : edges) {
+ if ( ed.getRuleKey().startsWith(xmlRootElementName)) {
+ sbEdge.append(" - TO ").append(ed.getRuleKey().substring(ed.getRuleKey().indexOf("|")+1));
+ sbEdge.append(ed.getRelationshipDescription("TO", xmlRootElementName));
+ sbEdge.append("\n");
+ }
+ }
+ for (EdgeDescription ed : edges) {
+ if ( ed.getRuleKey().endsWith(xmlRootElementName)) {
+ sbEdge.append(" - FROM ").append(ed.getRuleKey().substring(0, ed.getRuleKey().indexOf("|")));
+ sbEdge.append(ed.getRelationshipDescription("FROM", xmlRootElementName));
+ sbEdge.append("\n");
+ }
+ }
+ validEdges = sbEdge.toString();
+ }
+
+ String deleteRule = getDeleteRules(xmlRootElementName);
+ // Handle description property. Might have a description OR valid edges OR both OR neither.
+ // Only put a description: tag if there is at least one.
+ if (pathDescriptionProperty != null || deleteRule != null || validEdges != null) {
+ definitionsSb.append(" description: |\n");
+
+ if ( pathDescriptionProperty != null )
+ definitionsSb.append(" " + pathDescriptionProperty + "\n" );
+ if (deleteRule != null)
+ definitionsSb.append(" ###### Default Delete Scope\n ").append(deleteRule).append("\n");
+ if (validEdges != null)
+ definitionsSb.append(validEdges);
+ }
+
+ if ( requiredCnt > 0 )
+ definitionsSb.append(sbRequired);
+ if ( propertyCnt > 0 ) {
+ definitionsSb.append(" properties:\n");
+ definitionsSb.append(sbProperties);
+ }
+ generatedJavaType.put(xmlRootElementName, null);
+ return null;
+ }
+
+ public static String generateSwaggerFromOxmFile( File oxmFile )
+ {
+
+ StringBuffer sb = new StringBuffer();
+ sb.append("swagger: \"2.0\"\ninfo:\n description:\n A&AI REST API\n version: \"" + apiVersion +"\"\n");
+ sb.append(" title: Active and Available Inventory REST API\n");
+ sb.append(" license:\n name: Apache 2.0\n url: http://www.apache.org/licenses/LICENSE-2.0.html\n");
+ sb.append("schemes:\n - https\npaths:\n");
+ /*
+ sb.append("responses:\n");
+ sb.append(" \"200\":\n");
+ sb.append(" description: successful operation\n");
+ sb.append(" \"404\":\n");
+ sb.append(" description: resource was not found\n");
+ sb.append(" \"400\":\n");
+ sb.append(" description: bad request\n");
+ */
+ try {
+
+ versionedClass = getEdgeRulesClass();
+
+ DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+ dbFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+ Document doc = dBuilder.parse(oxmFile);
+
+ NodeList bindingsNodes = doc.getElementsByTagName("xml-bindings");
+ Element bindingElement;
+ NodeList javaTypesNodes;
+ Element javaTypesElement;
+
+ Element javaTypeElement;
+
+
+ if ( bindingsNodes == null || bindingsNodes.getLength() == 0 ) {
+ System.out.println( "missing <binding-nodes> in " + oxmFile );
+ return null;
+ }
+
+ bindingElement = (Element) bindingsNodes.item(0);
+ javaTypesNodes = bindingElement.getElementsByTagName("java-types");
+ if ( javaTypesNodes.getLength() < 1 ) {
+ System.out.println( "missing <binding-nodes><java-types> in " + oxmFile );
+ return null;
+ }
+ javaTypesElement = (Element) javaTypesNodes.item(0);
+
+ javaTypeNodes = javaTypesElement.getElementsByTagName("java-type");
+ if ( javaTypeNodes.getLength() < 1 ) {
+ System.out.println( "missing <binding-nodes><java-types><java-type> in " + oxmFile );
+ return null;
+ }
+
+ String javaTypeName;
+ String attrName, attrValue;
+ Attr attr;
+ StringBuffer pathSb = new StringBuffer();
+
+ StringBuffer definitionsSb = new StringBuffer("definitions:\n");
+
+ for ( int i = 0; i < javaTypeNodes.getLength(); ++ i ) {
+ javaTypeElement = (Element) javaTypeNodes.item(i);
+ NamedNodeMap attributes = javaTypeElement.getAttributes();
+ javaTypeName = null;
+ for ( int j = 0; j < attributes.getLength(); ++j ) {
+ attr = (Attr) attributes.item(j);
+ attrName = attr.getNodeName();
+ attrValue = attr.getNodeValue();
+ if ( attrName.equals("name"))
+ javaTypeName = attrValue;
+ }
+ if ( javaTypeName == null ) {
+ System.out.println( "<java-type> has no name attribute in " + oxmFile );
+ return null;
+ }
+ if ( !generatedJavaType.containsKey(getXmlRootElementName(javaTypeName)) ) {
+
+ //generatedJavaType.put(javaTypeName, null);
+ //if ( javaTypeName.equals("search")||javaTypeName.equals("actions"))
+
+ processJavaTypeElementSwagger( javaTypeName, javaTypeElement, pathSb,
+ definitionsSb, null, null, null, null, null, null, null);
+ }
+ }
+ sb.append(pathSb);
+ //System.out.println( "definitions block\n" + definitionsSb.toString());
+ sb.append(definitionsSb.toString());
+ //sb.append(definitionsSb);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ //System.out.println("generated " + sb.toString());
+ return sb.toString();
+ }
+
+ private static NodeList locateXmlProperties(Element element) {
+ XPathExpression expr;
+ NodeList result = null;
+ try {
+ expr = xpath.compile("xml-properties");
+ if (expr != null) {
+ Object nodeset = expr.evaluate(element, XPathConstants.NODESET);
+ if (nodeset != null) {
+ NodeList nodes = (NodeList) nodeset;
+ if (nodes != null && nodes.getLength() > 0) {
+ Element xmlProperty = (Element)nodes.item(0);
+ result = xmlProperty.getElementsByTagName("xml-property");
+ }
+ }
+ }
+ } catch (XPathExpressionException e) {
+ e.printStackTrace();
+ }
+ return result;
+
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/HbaseSaltPrefixer.java b/aai-core/src/main/java/org/openecomp/aai/util/HbaseSaltPrefixer.java
new file mode 100644
index 00000000..29373858
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/HbaseSaltPrefixer.java
@@ -0,0 +1,60 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+/*
+ * logging to hbase encountered hotspotting issues, so per
+ * http://archive.cloudera.com/cdh5/cdh/5/hbase-0.98.6-cdh5.3.8/book/rowkey.design.html
+ * we decided to salt the rowkeys
+ * as these keys are generated in a couple places, I made a class to contain that logic
+ */
+public class HbaseSaltPrefixer {
+ private int NUM_REGION_BUCKETS = 3; //the number of hbase region servers per cluster
+
+ private static class SingletonHolder{
+ private static final HbaseSaltPrefixer INSTANCE = new HbaseSaltPrefixer();
+ }
+
+ /**
+ * Instantiates a new hbase salt prefixer.
+ */
+ private HbaseSaltPrefixer(){}
+
+ /**
+ * Gets the single instance of HbaseSaltPrefixer.
+ *
+ * @return single instance of HbaseSaltPrefixer
+ */
+ public static HbaseSaltPrefixer getInstance() {
+ return SingletonHolder.INSTANCE;
+ }
+
+ /**
+ * Prepend salt.
+ *
+ * @param key the key
+ * @return the string
+ */
+ public String prependSalt(String key) {
+ int salt = Math.abs(key.hashCode()) % NUM_REGION_BUCKETS;
+ return salt + "-" + key;
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/KeyValueList.java b/aai-core/src/main/java/org/openecomp/aai/util/KeyValueList.java
new file mode 100644
index 00000000..95f09d58
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/KeyValueList.java
@@ -0,0 +1,138 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Generated;
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Generated("org.jsonschema2pojo")
+@JsonPropertyOrder({
+ "key",
+ "value"
+})
+public class KeyValueList {
+
+ @JsonProperty("key")
+ private String key;
+ @JsonProperty("value")
+ private String value;
+ @JsonIgnore
+ private Map<String, Object> additionalProperties = new HashMap<String, Object>();
+
+ /**
+ *
+ * @return
+ * The key
+ */
+ @JsonProperty("key")
+ public String getKey() {
+ return key;
+ }
+
+ /**
+ *
+ * @param key
+ * The key
+ */
+ @JsonProperty("key")
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public KeyValueList withKey(String key) {
+ this.key = key;
+ return this;
+ }
+
+ /**
+ *
+ * @return
+ * The value
+ */
+ @JsonProperty("value")
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ *
+ * @param value
+ * The value
+ */
+ @JsonProperty("value")
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public KeyValueList withValue(String value) {
+ this.value = value;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this);
+ }
+
+ @JsonAnyGetter
+ public Map<String, Object> getAdditionalProperties() {
+ return this.additionalProperties;
+ }
+
+ @JsonAnySetter
+ public void setAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ }
+
+ public KeyValueList withAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder().append(key).append(value).append(additionalProperties).toHashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if ((other instanceof KeyValueList) == false) {
+ return false;
+ }
+ KeyValueList rhs = ((KeyValueList) other);
+ return new EqualsBuilder().append(key, rhs.key).append(value, rhs.value).append(additionalProperties, rhs.additionalProperties).isEquals();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/MapperUtil.java b/aai-core/src/main/java/org/openecomp/aai/util/MapperUtil.java
new file mode 100644
index 00000000..54f239b6
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/MapperUtil.java
@@ -0,0 +1,115 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import org.openecomp.aai.exceptions.AAIException;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
+
+public class MapperUtil {
+
+
+ /**
+ * Read as object of.
+ *
+ * @param <T> the generic type
+ * @param clazz the clazz
+ * @param value the value
+ * @return the t
+ * @throws AAIException the AAI exception
+ */
+ public static <T> T readAsObjectOf(Class<T> clazz, String value) throws AAIException {
+ com.fasterxml.jackson.databind.ObjectMapper MAPPER = new ObjectMapper();
+ try {
+ return MAPPER.readValue(value, clazz);
+ } catch (Exception e) {
+ throw new AAIException("AAI_4007", e);
+ }
+ }
+
+ /**
+ * Read with dashes as object of.
+ *
+ * @param <T> the generic type
+ * @param clazz the clazz
+ * @param value the value
+ * @return the t
+ * @throws AAIException the AAI exception
+ */
+ public static <T> T readWithDashesAsObjectOf(Class<T> clazz, String value) throws AAIException {
+ com.fasterxml.jackson.databind.ObjectMapper MAPPER = new ObjectMapper();
+ try {
+ MAPPER.registerModule(new JaxbAnnotationModule());
+ MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ MAPPER.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, false);
+
+ return MAPPER.readValue(value, clazz);
+ } catch (Exception e) {
+ throw new AAIException("AAI_4007", e);
+ }
+ }
+
+ /**
+ * Write as JSON string.
+ *
+ * @param obj the obj
+ * @return the string
+ * @throws AAIException the AAI exception
+ */
+ public static String writeAsJSONString(Object obj) throws AAIException {
+ com.fasterxml.jackson.databind.ObjectMapper MAPPER = new ObjectMapper();
+ try {
+ String s = MAPPER.writeValueAsString(obj);
+ return s;
+ //readValue(value, clazz);
+ } catch (Exception e) {
+ throw new AAIException("AAI_4008", e);
+ }
+ }
+
+ /**
+ * Write as JSON string with dashes.
+ *
+ * @param obj the obj
+ * @return the string
+ * @throws AAIException the AAI exception
+ */
+ public static String writeAsJSONStringWithDashes(Object obj) throws AAIException {
+ com.fasterxml.jackson.databind.ObjectMapper MAPPER = new ObjectMapper();
+ try {
+ MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+
+ MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ MAPPER.configure(SerializationFeature.INDENT_OUTPUT, false);
+ MAPPER.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
+
+ MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ MAPPER.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, false);
+
+ MAPPER.registerModule(new JaxbAnnotationModule());
+ String s = MAPPER.writeValueAsString(obj);
+ return s;
+ } catch (Exception e) {
+ throw new AAIException("AAI_4008", e);
+ }
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/PojoUtils.java b/aai-core/src/main/java/org/openecomp/aai/util/PojoUtils.java
new file mode 100644
index 00000000..cd4d771f
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/PojoUtils.java
@@ -0,0 +1,738 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
+import com.google.common.base.CaseFormat;
+import com.google.common.collect.Multimap;
+import com.thinkaurelius.titan.core.TitanVertex;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.eclipse.persistence.dynamic.DynamicEntity;
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.eclipse.persistence.jaxb.MarshallerProperties;
+import org.openecomp.aai.domain.model.AAIResource;
+import org.openecomp.aai.exceptions.AAIException;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.Map.Entry;
+
+public class PojoUtils {
+
+ /**
+ * Gets the key value list.
+ *
+ * @param <T> the generic type
+ * @param e the e
+ * @param clazz the clazz
+ * @return the key value list
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ */
+ public <T> List<KeyValueList> getKeyValueList(Entity e, T clazz) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+ List<KeyValueList> kvList = e.getKeyValueList();
+ Object value = null;
+ Method[] methods = clazz.getClass().getDeclaredMethods();
+ String propertyName = "";
+
+ for (Method method : methods) {
+ if (method.getName().startsWith("get")) {
+ propertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(3));
+ if (!(method.getReturnType().getName().contains("aai")) || method.getReturnType().getName().contains("java.util.List")) {
+ value = method.invoke(clazz);
+ KeyValueList kv = new KeyValueList();
+ kv.setKey(propertyName);
+ if (value != null) {
+ kv.setValue(value.toString());
+ } else {
+ kv.setValue("");
+ }
+ kvList.add(kv);
+ }
+ }
+ }
+ return kvList;
+ }
+
+ /**
+ * Gets the json from object.
+ *
+ * @param <T> the generic type
+ * @param clazz the clazz
+ * @return the json from object
+ * @throws JsonGenerationException the json generation exception
+ * @throws JsonMappingException the json mapping exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public <T> String getJsonFromObject(T clazz) throws JsonGenerationException, JsonMappingException, IOException {
+ return getJsonFromObject(clazz, false, true);
+ }
+
+ /**
+ * Gets the json from object.
+ *
+ * @param <T> the generic type
+ * @param clazz the clazz
+ * @param wrapRoot the wrap root
+ * @param indent the indent
+ * @return the json from object
+ * @throws JsonGenerationException the json generation exception
+ * @throws JsonMappingException the json mapping exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public <T> String getJsonFromObject(T clazz, boolean wrapRoot, boolean indent) throws JsonGenerationException, JsonMappingException, IOException {
+ ObjectMapper mapper = new ObjectMapper();
+
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+
+ mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ mapper.configure(SerializationFeature.INDENT_OUTPUT, indent);
+ mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, wrapRoot);
+
+ mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, wrapRoot);
+
+ mapper.registerModule(new JaxbAnnotationModule());
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ mapper.writeValue(baos, clazz);
+
+ return baos.toString();
+ }
+
+ /**
+ * Gets the json from dynamic object.
+ *
+ * @param ent the ent
+ * @param jaxbContext the jaxb context
+ * @param includeRoot the include root
+ * @return the json from dynamic object
+ * @throws JsonGenerationException the json generation exception
+ * @throws JsonMappingException the json mapping exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ * @throws JAXBException the JAXB exception
+ */
+ public String getJsonFromDynamicObject(DynamicEntity ent, org.eclipse.persistence.jaxb.JAXBContext jaxbContext, boolean includeRoot) throws JsonGenerationException, JsonMappingException, IOException, JAXBException {
+ org.eclipse.persistence.jaxb.JAXBMarshaller marshaller = jaxbContext.createMarshaller();
+
+ marshaller.setProperty(org.eclipse.persistence.jaxb.JAXBMarshaller.JAXB_FORMATTED_OUTPUT, false);
+ marshaller.setProperty(MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, Boolean.FALSE) ;
+ marshaller.setProperty("eclipselink.json.include-root", includeRoot);
+ marshaller.setProperty("eclipselink.media-type", "application/json");
+ StringWriter writer = new StringWriter();
+ marshaller.marshal(ent, writer);
+
+ return writer.toString();
+ }
+
+ /**
+ * Gets the xml from object.
+ *
+ * @param <T> the generic type
+ * @param clazz the clazz
+ * @return the xml from object
+ * @throws JAXBException the JAXB exception
+ */
+ public <T> String getXmlFromObject(T clazz) throws JAXBException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ JAXBContext jc = JAXBContext.newInstance(clazz.getClass().getPackage().getName());
+
+ Marshaller marshaller = jc.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+ marshaller.marshal(clazz, baos);
+
+ return baos.toString();
+ }
+
+ /**
+ * Gets the lookup key.
+ *
+ * @param baseKey the base key
+ * @param lookupHash the lookup hash
+ * @param keyProps the key props
+ * @return the lookup key
+ */
+ public String getLookupKey (String baseKey, HashMap<String,Object> lookupHash, Collection<String> keyProps) {
+ int baseKeyLen = baseKey.length();
+ StringBuffer newKey = new StringBuffer();
+ if (baseKeyLen > 0) {
+ newKey.append(baseKey);
+ }
+
+ Iterator <String> keyPropI = keyProps.iterator();
+ while( keyPropI.hasNext() ){
+ String keyProp = keyPropI.next();
+ if (baseKeyLen > 0) {
+ newKey.append("&");
+ }
+ newKey.append(keyProp + "=" + lookupHash.get(keyProp));
+ }
+ return newKey.toString();
+ }
+
+ /**
+ * Gets the lookup keys.
+ *
+ * @param lookupHashes the lookup hashes
+ * @param _dbRulesNodeKeyProps the db rules node key props
+ * @return the lookup keys
+ */
+ public String getLookupKeys (LinkedHashMap<String,HashMap<String,Object>> lookupHashes, Multimap<String, String> _dbRulesNodeKeyProps) {
+ Iterator<String> it = lookupHashes.keySet().iterator();
+ String lookupKeys = "";
+ while (it.hasNext()) {
+ String objectType = (String)it.next();
+ HashMap<String,Object> lookupHash = lookupHashes.get(objectType);
+
+ Collection<String> keyProps = _dbRulesNodeKeyProps.get(objectType);
+ Iterator <String> keyPropI = keyProps.iterator();
+ while( keyPropI.hasNext() ){
+ lookupKeys += lookupHash.get(keyPropI.next());
+ }
+ }
+ return lookupKeys;
+ }
+
+ /**
+ * Gets the example object.
+ *
+ * @param <T> the generic type
+ * @param clazz the clazz
+ * @param singleton the singleton
+ * @return the example object
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws AAIException the AAI exception
+ */
+ public <T> void getExampleObject(T clazz, boolean singleton) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, AAIException {
+ Method[] methods = clazz.getClass().getDeclaredMethods();
+ String dnHypPropertyName = "";
+ String upCamPropertyName = "";
+ Random rand = new Random();
+ int randInt = rand.nextInt(10000000);
+
+ for (Method method : methods) {
+ boolean go = false;
+ if (method.getName().startsWith("get")) {
+ dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(3));
+ upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(3));
+ go = true;
+ } else if (method.getName().startsWith("is")) {
+ dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(2));
+ upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(2));
+ go = true;
+ }
+ // don't return resource-version on a singleton
+ if (singleton && dnHypPropertyName.equals("resource-version")) {
+ go = false;
+ }
+ if (go) {
+ String retType = method.getReturnType().getName();
+ if (!retType.contains("aai") && !retType.contains("java.util.List")) {
+ // get the setter
+ Method meth = clazz.getClass().getMethod("set" + upCamPropertyName, method.getReturnType());
+
+ if (retType.contains("String")) {
+ String val = "example-" + dnHypPropertyName + "-val-" + randInt;
+ if (val != null) {
+ meth.invoke(clazz, val);
+ }
+ } else if (retType.toLowerCase().contains("long")) {
+ Integer foo = rand.nextInt(100000);
+ meth.invoke(clazz, foo.longValue());
+ } else if (retType.toLowerCase().contains("int")) {
+ meth.invoke(clazz, rand.nextInt(100000));
+ } else if (retType.toLowerCase().contains("short")) {
+ Integer randShort = rand.nextInt(10000);
+ meth.invoke(clazz, randShort.shortValue());
+ } else if (retType.toLowerCase().contains("boolean")) {
+ meth.invoke(clazz, true);
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Gets the aai object from vertex.
+ *
+ * @param <T> the generic type
+ * @param clazz the clazz
+ * @param vert the vert
+ * @param _propertyDataTypeMap the property data type map
+ * @return the aai object from vertex
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws AAIException the AAI exception
+ */
+ public <T> void getAaiObjectFromVertex(T clazz, TitanVertex vert, Map<String, String> _propertyDataTypeMap) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, AAIException {
+ Method[] methods = clazz.getClass().getDeclaredMethods();
+ String dnHypPropertyName = "";
+ String upCamPropertyName = "";
+ for (Method method : methods) {
+ boolean go = false;
+ if (method.getName().startsWith("get")) {
+ dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(3));
+ upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(3));
+ go = true;
+ } else if (method.getName().startsWith("is")) {
+ dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(2));
+ upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(2));
+ go = true;
+ }
+ if (go) {
+ String retType = method.getReturnType().getName();
+ if (!retType.contains("aai") && !retType.contains("java.util.List")) {
+ // get the setter
+ Method meth = clazz.getClass().getMethod("set" + upCamPropertyName, method.getReturnType());
+
+ if (retType.contains("String")) {
+ String val = (String)vert.<String>property(dnHypPropertyName).orElse(null);
+ if (val != null) {
+ meth.invoke(clazz, val);
+ }
+ } else if (retType.toLowerCase().contains("long")) {
+ String titanType = _propertyDataTypeMap.get(dnHypPropertyName);
+
+ Long val = null;
+ // we have a case where the type in titan is "Integer" but in the POJO it's Long or long
+ if (titanType.toLowerCase().contains("int")) {
+ Integer intVal = (Integer)vert.<Integer>property(dnHypPropertyName).orElse(null);
+ if (intVal != null) {
+ val = intVal.longValue();
+ }
+ } else {
+ val = (Long)vert.<Long>property(dnHypPropertyName).orElse(null);
+ }
+ if (val != null) {
+ meth.invoke(clazz, val);
+ }
+ } else if (retType.toLowerCase().contains("int")) {
+ Integer val = (Integer)vert.<Integer>property(dnHypPropertyName).orElse(null);
+ if (val != null) {
+ meth.invoke(clazz, val);
+ }
+ } else if (retType.toLowerCase().contains("short")) {
+ Short val = (Short)vert.<Short>property(dnHypPropertyName).orElse(null);
+ if (val != null) {
+ meth.invoke(clazz, val);
+ }
+ } else if (retType.toLowerCase().contains("boolean")) {
+ Boolean val = (Boolean)vert.<Boolean>property(dnHypPropertyName).orElse(null);
+ if (val != null) {
+ meth.invoke(clazz, val);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the topology object.
+ *
+ * @param <T> the generic type
+ * @param clazz the clazz
+ * @param _dbRulesNodeNameProps the db rules node name props
+ * @param _dbRulesNodeKeyProps the db rules node key props
+ * @param vert the vert
+ * @return the topology object
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws AAIException the AAI exception
+ */
+ public <T> void getTopologyObject(T clazz, Multimap<String, String> _dbRulesNodeNameProps, Multimap<String, String> _dbRulesNodeKeyProps, TitanVertex vert) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, AAIException {
+ Method[] methods = clazz.getClass().getDeclaredMethods();
+ String dnHypPropertyName = "";
+// Object value = null;
+ List<String> includeProps = new ArrayList<String>();
+
+ if ("false".equals(AAIConfig.get("aai.notification.topology.allAttrs", "false"))) {
+ for (Method method : methods) {
+ if (method.getName().startsWith("is")) {
+ dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(2));
+ String upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(2));
+ String retType = method.getReturnType().getName();
+ if (retType.equals("java.lang.Boolean")) {
+ // get the setter
+ Method setterMeth = clazz.getClass().getMethod("set" + upCamPropertyName, method.getReturnType());
+ setterMeth.invoke(clazz, (Boolean)null);
+ }
+ }
+ }
+ String dnHypClassName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,clazz.getClass().getSimpleName());
+ Collection<String> keepProps = _dbRulesNodeNameProps.get(dnHypClassName);
+ Iterator <String> keepPropI = keepProps.iterator();
+ while( keepPropI.hasNext() ){
+ includeProps.add(keepPropI.next());
+ }
+ Collection<String> keepProps2 = _dbRulesNodeKeyProps.get(dnHypClassName);
+ Iterator <String> keepPropI2 = keepProps2.iterator();
+ while( keepPropI2.hasNext() ){
+ includeProps.add(keepPropI2.next());
+ }
+ }
+
+ for (Method method : methods) {
+ if (method.getName().startsWith("get")) {
+ dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(3));
+ if (includeProps.size() > 0) {
+ if (!includeProps.contains(dnHypPropertyName)) {
+ continue;
+ }
+ }
+ String upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(3));
+ String retType = method.getReturnType().getName();
+ if (!retType.contains("aai") && !retType.contains("java.util.List")) {
+ // get the setter
+ Method meth = clazz.getClass().getMethod("set" + upCamPropertyName, method.getReturnType());
+
+ if (retType.contains("String")) {
+ String val = (String)vert.<String>property(dnHypPropertyName).orElse(null);
+ if (val != null) {
+ meth.invoke(clazz, val);
+ }
+ } else if (retType.toLowerCase().contains("long")) {
+ Long val = (Long)vert.<Long>property(dnHypPropertyName).orElse(null);
+ if (val != null) {
+ meth.invoke(clazz, val);
+ }
+ } else if (retType.toLowerCase().contains("int")) {
+ Integer val = (Integer)vert.<Integer>property(dnHypPropertyName).orElse(null);
+ if (val != null) {
+ meth.invoke(clazz, val);
+ }
+ } else if (retType.toLowerCase().contains("short")) {
+ Short val = (Short)vert.<Short>property(dnHypPropertyName).orElse(null);
+ if (val != null) {
+ meth.invoke(clazz, val);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the dynamic topology object.
+ *
+ * @param aaiRes the aai res
+ * @param meObjectType the me object type
+ * @param _dbRulesNodeNameProps the db rules node name props
+ * @param _dbRulesNodeKeyProps the db rules node key props
+ * @param _propertyDataTypeMap the property data type map
+ * @param vert the vert
+ * @return the dynamic topology object
+ * @throws AAIException the AAI exception
+ */
+ public DynamicEntity getDynamicTopologyObject(AAIResource aaiRes, DynamicType meObjectType, Multimap<String, String> _dbRulesNodeNameProps,
+ Multimap<String, String> _dbRulesNodeKeyProps, Map<String, String> _propertyDataTypeMap, TitanVertex vert) throws AAIException {
+
+ DynamicEntity meObject = meObjectType.newDynamicEntity();
+
+ List<String> includeProps = new ArrayList<String>();
+
+ if ("false".equals(AAIConfig.get("aai.notification.topology.allAttrs", "false"))) {
+ String dnHypClassName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,meObjectType.getJavaClass().getSimpleName());
+ Collection<String> keepProps = _dbRulesNodeNameProps.get(dnHypClassName);
+ Iterator <String> keepPropI = keepProps.iterator();
+ while( keepPropI.hasNext() ){
+ includeProps.add(keepPropI.next());
+ }
+ Collection<String> keepProps2 = _dbRulesNodeKeyProps.get(dnHypClassName);
+ Iterator <String> keepPropI2 = keepProps2.iterator();
+ while( keepPropI2.hasNext() ) {
+ includeProps.add(keepPropI2.next());
+ }
+ }
+
+
+
+ for (String attrName : aaiRes.getStringFields()) {
+ if (includeProps.contains(attrName)) {
+ meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), vert.<String>property(attrName).orElse(null));
+ }
+ }
+ // the attrName might need to be converted to camel case!!!
+ for (String attrName : aaiRes.getLongFields()) {
+ if (includeProps.contains(attrName)) {
+ String titanType = _propertyDataTypeMap.get(attrName);
+
+ Long val = null;
+ // we have a case where the type in titan is "Integer" but in the POJO it's Long or long
+ if (titanType.toLowerCase().contains("int")) {
+ Integer intVal = (Integer)vert.<Integer>property(attrName).orElse(null);
+ if (intVal != null) {
+ val = intVal.longValue();
+ }
+ } else {
+ val = (Long)vert.<Long>property(attrName).orElse(null);
+ }
+ meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val);
+ }
+ }
+
+ for (String attrName : aaiRes.getIntFields()) {
+ if (includeProps.contains(attrName)) {
+ Integer val = (Integer)vert.<Integer>property(attrName).orElse(null);
+ meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val);
+ }
+ }
+
+ for (String attrName : aaiRes.getShortFields()) {
+ if (includeProps.contains(attrName)) {
+ String titanType = _propertyDataTypeMap.get(attrName);
+
+ Short val = null;
+ // we have a case where the type in titan is "Integer" but in the POJO it's Long or long
+ if (titanType.toLowerCase().contains("int")) {
+ Integer intVal = (Integer)vert.<Integer>property(attrName).orElse(null);
+ if (intVal != null) {
+ val = intVal.shortValue();
+ }
+ } else {
+ val = (Short)vert.<Short>property(attrName).orElse(null);
+ }
+ meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val);
+ }
+ }
+
+ for (String attrName : aaiRes.getBooleanFields()) {
+ if (includeProps.contains(attrName)) {
+ Boolean val = (Boolean)vert.<Boolean>property(attrName).orElse(null);
+ meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val);
+ }
+ }
+ return meObject;
+ }
+
+ /**
+ * Gets the aai dynamic object from vertex.
+ *
+ * @param aaiRes the aai res
+ * @param meObject the me object
+ * @param vert the vert
+ * @param _propertyDataTypeMap the property data type map
+ * @return the aai dynamic object from vertex
+ */
+ public void getAaiDynamicObjectFromVertex(AAIResource aaiRes, DynamicEntity meObject, TitanVertex vert,
+ Map<String, String> _propertyDataTypeMap) {
+ getAaiDynamicObjectFromVertex(aaiRes, meObject, vert, _propertyDataTypeMap, null);
+ }
+
+ /**
+ * Gets the aai dynamic object from vertex.
+ *
+ * @param aaiRes the aai res
+ * @param meObject the me object
+ * @param vert the vert
+ * @param _propertyDataTypeMap the property data type map
+ * @param propertyOverRideHash the property over ride hash
+ * @return the aai dynamic object from vertex
+ */
+ @SuppressWarnings("unchecked")
+ public void getAaiDynamicObjectFromVertex(AAIResource aaiRes, DynamicEntity meObject, TitanVertex vert,
+ Map<String, String> _propertyDataTypeMap, HashMap<String, Object> propertyOverRideHash) {
+
+ for (String attrName : aaiRes.getStringFields()) {
+ if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) {
+ meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), vert.<String>property(dbAliasWorkaround(attrName)).orElse(null));
+ }
+ }
+
+ for (String attrName : aaiRes.getStringListFields()) {
+ if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) {
+ meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), vert.<ArrayList<String>>property(attrName).orElse(null));
+ }
+ }
+
+ // the attrName might need to be converted to camel case!!!
+ for (String attrName : aaiRes.getLongFields()) {
+ String titanType = _propertyDataTypeMap.get(attrName);
+ Long val = null;
+ // we have a case where the type in titan is "Integer" but in the POJO it's Long or long
+ if (titanType.toLowerCase().contains("int")) {
+ Object vertexVal = vert.property(attrName).orElse(null);
+ if (vertexVal != null) {
+ if (vertexVal instanceof Integer) {
+ val = ((Integer)vertexVal).longValue();
+
+ } else {
+ val = (Long)vert.<Long>property(attrName).orElse(null);
+ }
+ }
+ } else {
+ val = (Long)vert.<Long>property(attrName).orElse(null);
+ }
+ if (val != null) {
+ if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) {
+ meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val);
+ }
+ }
+ }
+
+ for (String attrName : aaiRes.getIntFields()) {
+ Integer val = (Integer)vert.<Integer>property(attrName).orElse(null);
+ if (val != null) {
+ if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) {
+ meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val);
+ }
+ }
+ }
+
+ for (String attrName : aaiRes.getShortFields()) {
+ String titanType = _propertyDataTypeMap.get(attrName);
+ Short val = null;
+ // we have a case where the type in titan is "Integer" but in the POJO it's Long or long
+ if (titanType.toLowerCase().contains("int")) {
+ Integer intVal = (Integer)vert.<Integer>property(attrName).orElse(null);
+ if (intVal != null) {
+ val = intVal.shortValue();
+ }
+ } else {
+ val = (Short)vert.<Short>property(attrName).orElse(null);
+ }
+ if (val != null) {
+ if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) {
+ meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val);
+ }
+ }
+ }
+
+ for (String attrName : aaiRes.getBooleanFields()) {
+ Boolean val = (Boolean)vert.<Boolean>property(attrName).orElse(null);
+ // This is not ideal, but moxy isn't marshalling these attributes.
+ // TODO: Figure out how to see the default-value from the OXM at startup (or at runtime).
+ String dnHypClassName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,aaiRes.getSimpleName());
+ if (val == null && AAIConfig.getDefaultBools().containsKey(dnHypClassName)) {
+ if (AAIConfig.getDefaultBools().get(dnHypClassName).contains(attrName)) {
+ val = false;
+ }
+ }
+ if (val != null) {
+ if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) {
+ meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val);
+ }
+ }
+ }
+
+ }
+
+ private String dbAliasWorkaround(String propName) {
+ final String modelInvariantIdLocal = "model-invariant-id-local";
+ final String modelVersionIdLocal = "model-version-id-local";
+ final String modelInvariantId = "model-invariant-id";
+ final String modelVersionId = "model-version-id";
+
+ if (propName.equals(modelInvariantId)) {
+ return modelInvariantIdLocal;
+ }
+ if (propName.equals(modelVersionId)) {
+ return modelVersionIdLocal;
+ }
+
+ return propName;
+
+ }
+
+ /**
+ * Gets the dynamic example object.
+ *
+ * @param childObject the child object
+ * @param aaiRes the aai res
+ * @param singleton the singleton
+ * @return the dynamic example object
+ */
+ public void getDynamicExampleObject(DynamicEntity childObject, AAIResource aaiRes, boolean singleton) {
+ // TODO Auto-generated method stub
+
+ Random rand = new Random();
+ Integer randInt = rand.nextInt(100000);
+ long range = 100000000L;
+ long randLong = (long)(rand.nextDouble()*range);
+ Integer randShrt = rand.nextInt(20000);
+ short randShort = randShrt.shortValue();
+
+ for (String dnHypAttrName : aaiRes.getStringFields()) {
+
+ if (singleton && ("resource-version").equals(dnHypAttrName)) {
+ continue;
+ }
+
+ String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName);
+ childObject.set(dnCamAttrName, "example-" + dnHypAttrName + "-val-" + randInt);
+
+ }
+
+ for (String dnHypAttrName : aaiRes.getStringListFields()) {
+ ArrayList<String> exampleList = new ArrayList<String>();
+ exampleList.add("example-" + dnHypAttrName + "-val-" + randInt + "-" + 1);
+ exampleList.add("example-" + dnHypAttrName + "-val-" + randInt + "-" + 2);
+ String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName);
+ childObject.set(dnCamAttrName, exampleList);
+ }
+
+ // the attrName might need to be converted to camel case!!!
+ for (String dnHypAttrName : aaiRes.getLongFields()) {
+ String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName);
+ childObject.set(dnCamAttrName, randLong);
+ }
+
+ for (String dnHypAttrName : aaiRes.getIntFields()) {
+ String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName);
+ childObject.set(dnCamAttrName, randInt);
+ }
+
+ for (String dnHypAttrName : aaiRes.getShortFields()) {
+ String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName);
+ childObject.set(dnCamAttrName, randShort);
+ }
+
+ for (String dnHypAttrName : aaiRes.getBooleanFields()) {
+ String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName);
+ childObject.set(dnCamAttrName, Boolean.TRUE);
+ }
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/Request.java b/aai-core/src/main/java/org/openecomp/aai/util/Request.java
new file mode 100644
index 00000000..cc812f0d
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/Request.java
@@ -0,0 +1,160 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
+import javax.ws.rs.core.UriBuilder;
+
+import org.openecomp.aai.exceptions.AAIException;
+
+public class Request<T> {
+
+ public static final String V2 = "v2";
+ public static final String V3 = "v3";
+ public static final String V4 = "v4";
+ public static final String V5 = "v5";
+ public final String fromAppId;
+ public final String transactionId;
+ public final String path;
+ public final RestObject<T> restObj;
+ public final boolean oldServer;
+ public final String apiVersion;
+
+
+ /**
+ * Instantiates a new request.
+ *
+ * @param builder the builder
+ */
+ public Request(RequestBuilder<T> builder) {
+
+ fromAppId = builder.fromAppId;
+ transactionId = builder.transactionId;
+ restObj = builder.restObj;
+ oldServer = builder.oldServer;
+ apiVersion = builder.apiVersion;
+
+ if (!oldServer) {
+ path = apiVersion + "/" + builder.path;
+ } else {
+ path = builder.path;
+ }
+
+
+ }
+
+ public static class RequestBuilder<T> {
+ private String fromAppId;
+ private String transactionId;
+ private String path;
+ private RestObject<T> restObj;
+ private boolean oldServer;
+ private String apiVersion = Request.V4;
+
+
+ /**
+ * Sets the from app id.
+ *
+ * @param fromAppId the from app id
+ * @return the request builder
+ */
+ public RequestBuilder<T> setFromAppId(String fromAppId) {
+ this.fromAppId = fromAppId;
+ return this;
+ }
+
+ /**
+ * Sets the transaction id.
+ *
+ * @param transactionId the transaction id
+ * @return the request builder
+ */
+ public RequestBuilder<T> setTransactionId(String transactionId) {
+ this.transactionId = transactionId;
+ return this;
+
+ }
+
+ /**
+ * Sets the path.
+ *
+ * @param path the path
+ * @return the request builder
+ */
+ public RequestBuilder<T> setPath(String path) {
+
+ this.path = path;
+ return this;
+
+ }
+
+ /**
+ * Sets the restcore obj.
+ *
+ * @param restObj the restcore obj
+ * @return the request builder
+ */
+ public RequestBuilder<T> setRestObj(RestObject<T> restObj) {
+ this.restObj = restObj;
+ return this;
+
+ }
+
+ /**
+ * Sets the old server.
+ *
+ * @param oldServer the old server
+ * @return the request builder
+ */
+ public RequestBuilder<T> setOldServer(boolean oldServer) {
+ this.oldServer = oldServer;
+ return this;
+
+ }
+
+ /**
+ * Sets the api version.
+ *
+ * @param apiVersion the api version
+ * @return the request builder
+ */
+ public RequestBuilder<T> setApiVersion(String apiVersion) {
+ this.apiVersion = apiVersion;
+ return this;
+ }
+
+ /**
+ * Builds the.
+ *
+ * @return the request
+ */
+ public Request<T> build() {
+ return new Request<T>(this);
+ }
+
+ }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/RestObject.java b/aai-core/src/main/java/org/openecomp/aai/util/RestObject.java
new file mode 100644
index 00000000..c8b78d41
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/RestObject.java
@@ -0,0 +1,46 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+public class RestObject<T> {
+
+ /**
+ * Generic version of the RestObject class.
+ * @param <T> the type of the value being called for the Rest object interface
+ */
+ // T stands for "Type"
+ private T t;
+
+ /**
+ * Sets the.
+ *
+ * @param t the t
+ */
+ public void set(T t) { this.t = t; }
+
+ /**
+ * Gets the.
+ *
+ * @return the t
+ */
+ public T get() { return t; }
+
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/RestURLEncoder.java b/aai-core/src/main/java/org/openecomp/aai/util/RestURLEncoder.java
new file mode 100644
index 00000000..d75fe27b
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/RestURLEncoder.java
@@ -0,0 +1,41 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import java.io.UnsupportedEncodingException;
+import org.springframework.web.util.UriUtils;
+
+
+public class RestURLEncoder {
+
+
+ /**
+ * Encode URL.
+ *
+ * @param nodeKey the node key
+ * @return the string
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public static final String encodeURL (String nodeKey) throws UnsupportedEncodingException {
+ return UriUtils.encode(nodeKey, "UTF-8").replaceAll("\\+", "%20");
+ }
+}
+
diff --git a/aai-core/src/main/java/org/openecomp/aai/util/UniquePropertyCheck.java b/aai-core/src/main/java/org/openecomp/aai/util/UniquePropertyCheck.java
new file mode 100644
index 00000000..58eb41a4
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/util/UniquePropertyCheck.java
@@ -0,0 +1,264 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.util;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.UUID;
+
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.slf4j.MDC;
+
+import org.openecomp.aai.exceptions.AAIException;
+import com.att.eelf.configuration.Configuration;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.thinkaurelius.titan.core.TitanEdge;
+import com.thinkaurelius.titan.core.TitanFactory;
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.thinkaurelius.titan.core.TitanTransaction;
+import com.thinkaurelius.titan.core.TitanVertex;
+
+
+
+public class UniquePropertyCheck {
+
+
+ private static final String FROMAPPID = "AAI-UTILS";
+ private static final String TRANSID = UUID.randomUUID().toString();
+ private static final String COMPONENT = "UniquePropertyCheck";
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+
+
+ Properties props = System.getProperties();
+ props.setProperty(Configuration.PROPERTY_LOGGING_FILE_NAME, "uniquePropertyCheck-logback.xml");
+ props.setProperty(Configuration.PROPERTY_LOGGING_FILE_PATH, AAIConstants.AAI_HOME_ETC_APP_PROPERTIES);
+ EELFLogger logger = EELFManager.getInstance().getLogger(UniquePropertyCheck.class.getSimpleName());
+ MDC.put("logFilenameAppender", UniquePropertyCheck.class.getSimpleName());
+
+ if( args == null || args.length != 1 ){
+ String msg = "usage: UniquePropertyCheck propertyName \n";
+ System.out.println(msg);
+ logAndPrint(logger, msg );
+ System.exit(1);
+ }
+ String propertyName = args[0];
+ TitanTransaction graph = null;
+
+ try {
+ AAIConfig.init();
+ System.out.println(" ---- NOTE --- about to open graph (takes a little while)--------\n");
+ TitanGraph tGraph = TitanFactory.open(AAIConstants.REALTIME_DB_CONFIG);
+
+ if( tGraph == null ) {
+ logAndPrint(logger, " Error: Could not get TitanGraph ");
+ System.exit(1);
+ }
+
+ graph = tGraph.newTransaction();
+ if( graph == null ){
+ logAndPrint(logger, "could not get graph object in UniquePropertyCheck() \n");
+ System.exit(0);
+ }
+ }
+ catch (AAIException e1) {
+ String msg = "Threw Exception: [" + e1.toString() + "]";
+ logAndPrint(logger, msg);
+ System.exit(0);
+ }
+ catch (Exception e2) {
+ String msg = "Threw Exception: [" + e2.toString() + "]";
+ logAndPrint(logger, msg);
+ System.exit(0);
+ }
+
+ runTheCheckForUniqueness( TRANSID, FROMAPPID, graph, propertyName, logger );
+ System.exit(0);
+
+ }// End main()
+
+
+ /**
+ * Run the check for uniqueness.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param propertyName the property name
+ * @param logger the logger
+ * @return the boolean
+ */
+ public static Boolean runTheCheckForUniqueness( String transId, String fromAppId, TitanTransaction graph,
+ String propertyName, EELFLogger logger ){
+
+ // Note - property can be found in more than one nodetype
+ // our uniqueness constraints are always across the entire db - so this
+ // tool looks across all nodeTypes that the property is found in.
+ Boolean foundDupesFlag = false;
+
+ HashMap <String,String> valuesAndVidHash = new HashMap <String, String> ();
+ HashMap <String,String> dupeHash = new HashMap <String, String> ();
+
+ int propCount = 0;
+ int dupeCount = 0;
+ Iterable <?> vertItr = graph.query().has(propertyName).vertices();
+ Iterator <?> vertItor = vertItr.iterator();
+ while( vertItor.hasNext() ){
+ propCount++;
+ TitanVertex v = (TitanVertex)vertItor.next();
+ String thisVid = v.id().toString();
+ Object val = (v.<Object>property(propertyName)).orElse(null);
+ if( valuesAndVidHash.containsKey(val) ){
+ // We've seen this one before- track it in our dupe hash
+ dupeCount++;
+ if( dupeHash.containsKey(val) ){
+ // This is not the first one being added to the dupe hash for this value
+ String updatedDupeList = dupeHash.get(val) + "|" + thisVid;
+ dupeHash.put(val.toString(), updatedDupeList);
+ }
+ else {
+ // This is the first time we see this value repeating
+ String firstTwoVids = valuesAndVidHash.get(val) + "|" + thisVid;
+ dupeHash.put(val.toString(), firstTwoVids);
+ }
+ }
+ else {
+ valuesAndVidHash.put(val.toString(), thisVid);
+ }
+ }
+
+
+ String info = "\n Found this property [" + propertyName + "] " + propCount + " times in our db.";
+ logAndPrint(logger, info);
+ info = " Found " + dupeCount + " cases of duplicate values for this property.\n\n";
+ logAndPrint(logger, info);
+
+ try {
+ if( ! dupeHash.isEmpty() ){
+ Iterator <?> dupeItr = dupeHash.entrySet().iterator();
+ while( dupeItr.hasNext() ){
+ Map.Entry pair = (Map.Entry) dupeItr.next();
+ String dupeValue = pair.getKey().toString();;
+ String vidsStr = pair.getValue().toString();
+ String[] vidArr = vidsStr.split("\\|");
+ logAndPrint(logger, "\n\n -------------- Found " + vidArr.length
+ + " nodes with " + propertyName + " of this value: [" + dupeValue + "]. Node details: ");
+
+ for( int i = 0; i < vidArr.length; i++ ){
+ String vidString = vidArr[i];
+ Long idLong = Long.valueOf(vidString);
+ TitanVertex tvx = (TitanVertex)graph.getVertex(idLong);
+ showPropertiesAndEdges( TRANSID, FROMAPPID, tvx, logger );
+ }
+ }
+ }
+ }
+ catch( Exception e2 ){
+ logAndPrint(logger, "Threw Exception: [" + e2.toString() + "]");
+ }
+ finally {
+ if( graph != null ){
+ graph.rollback();
+ }
+ }
+
+ return foundDupesFlag;
+
+ }// end of runTheCheckForUniqueness()
+
+
+ /**
+ * Show properties and edges.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param tVert the t vert
+ * @param logger the logger
+ */
+ private static void showPropertiesAndEdges( String transId, String fromAppId, TitanVertex tVert,
+ EELFLogger logger ){
+
+ if( tVert == null ){
+ logAndPrint(logger, "Null node passed to showPropertiesAndEdges.");
+ }
+ else {
+ String nodeType = "";
+ Object ob = tVert.<String>property("aai-node-type").orElse(null);
+ if( ob == null ){
+ nodeType = "null";
+ }
+ else{
+ nodeType = ob.toString();
+ }
+
+ logAndPrint(logger, " AAINodeType/VtxID for this Node = [" + nodeType + "/" + tVert.id() + "]");
+ logAndPrint(logger, " Property Detail: ");
+ Iterator<VertexProperty<Object>> pI = tVert.properties();
+ while( pI.hasNext() ){
+ VertexProperty<Object> tp = pI.next();
+ Object val = tp.value();
+ logAndPrint(logger, "Prop: [" + tp.key() + "], val = [" + val + "] ");
+ }
+
+ Iterator <Edge> eI = tVert.edges(Direction.BOTH);
+ if( ! eI.hasNext() ){
+ logAndPrint(logger, "No edges were found for this vertex. ");
+ }
+ while( eI.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI.next();
+ String lab = ed.label();
+ TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert);
+ if( vtx == null ){
+ logAndPrint(logger, " >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< ");
+ }
+ else {
+ String nType = vtx.<String>property("aai-node-type").orElse(null);
+ String vid = vtx.id().toString();
+ logAndPrint(logger, "Found an edge (" + lab + ") from this vertex to a [" + nType + "] node with VtxId = " + vid);
+ }
+ }
+ }
+ } // End of showPropertiesAndEdges()
+
+
+ /**
+ * Log and print.
+ *
+ * @param logger the logger
+ * @param msg the msg
+ */
+ protected static void logAndPrint(EELFLogger logger, String msg) {
+ System.out.println(msg);
+ logger.info(msg);
+ }
+
+}
+
+
diff --git a/aai-core/src/main/java/org/openecomp/aai/workarounds/LegacyURITransformer.java b/aai-core/src/main/java/org/openecomp/aai/workarounds/LegacyURITransformer.java
new file mode 100644
index 00000000..896243cc
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/workarounds/LegacyURITransformer.java
@@ -0,0 +1,93 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.workarounds;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class LegacyURITransformer {
+
+ private final Pattern legacyUriPattern = Pattern.compile("/aai/servers/(?<version>v[23])/(?<tenantKey>.*?)/vservers/(?<vserverKey>[^/]*?$)");
+ private final Pattern currentUriPattern = Pattern.compile("/aai/(?<version>v\\d+)/cloud-infrastructure/tenants/tenant/(?<tenantKey>.*?)/vservers/vserver/(?<vserverKey>[^/]*?$)");
+ /**
+ * Instantiates a new legacy URL transformer.
+ */
+ private LegacyURITransformer() {
+
+ }
+
+ private static class Helper {
+ private static final LegacyURITransformer INSTANCE = new LegacyURITransformer();
+ }
+
+ /**
+ * Gets the single instance of LegacyURLTransformer.
+ *
+ * @return single instance of LegacyURLTransformer
+ */
+ public static LegacyURITransformer getInstance() {
+ return Helper.INSTANCE;
+ }
+
+ /**
+ * Gets the legacy URL.
+ *
+ * @param url the url
+ * @return the legacy URL
+ * @throws URISyntaxException
+ * @throws MalformedURLException the malformed URL exception
+ */
+ public URI getLegacyURI(URI url) throws URISyntaxException {
+ String replacement = "/aai/servers/${version}/${tenantKey}/vservers/${vserverKey}";
+ String result = url.toString();
+ Matcher m = currentUriPattern.matcher(result);
+ if (m.find()) {
+ result = m.replaceFirst(replacement);
+
+ }
+
+ return new URI(result);
+
+ }
+
+ /**
+ * Gets the current URL.
+ *
+ * @param url the url
+ * @return the current URL
+ * @throws URISyntaxException
+ * @throws MalformedURLException the malformed URL exception
+ */
+ public URI getCurrentURI(URI url) throws URISyntaxException {
+ String replacement = "/aai/${version}/cloud-infrastructure/tenants/tenant/${tenantKey}/vservers/vserver/${vserverKey}";
+ String result = url.toString();
+ Matcher m = legacyUriPattern.matcher(result);
+ if (m.find()) {
+ result = m.replaceFirst(replacement);
+
+ }
+
+ return new URI(result);
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/workarounds/NamingExceptions.java b/aai-core/src/main/java/org/openecomp/aai/workarounds/NamingExceptions.java
new file mode 100644
index 00000000..ac1d2cc7
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/workarounds/NamingExceptions.java
@@ -0,0 +1,79 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.workarounds;
+
+public class NamingExceptions {
+
+ /**
+ * Instantiates a new naming exceptions.
+ */
+ private NamingExceptions() {
+
+ }
+
+ private static class Helper {
+ private static final NamingExceptions INSTANCE = new NamingExceptions();
+ }
+
+ /**
+ * Gets the single instance of NamingExceptions.
+ *
+ * @return single instance of NamingExceptions
+ */
+ public static NamingExceptions getInstance() {
+ return Helper.INSTANCE;
+ }
+
+ /**
+ * Gets the object name.
+ *
+ * @param name the name
+ * @return the object name
+ */
+ public String getObjectName(String name) {
+
+ String result = name;
+
+ if (name.equals("cvlan-tag")) {
+ result = "cvlan-tag-entry";
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets the DB name.
+ *
+ * @param name the name
+ * @return the DB name
+ */
+ public String getDBName(String name) {
+
+ String result = name;
+
+ if (name.equals("cvlan-tag-entry")) {
+ result = "cvlan-tag";
+ }
+
+ return result;
+
+ }
+}
diff --git a/aai-core/src/main/java/org/openecomp/aai/workarounds/RemoveDME2QueryParams.java b/aai-core/src/main/java/org/openecomp/aai/workarounds/RemoveDME2QueryParams.java
new file mode 100644
index 00000000..8713de63
--- /dev/null
+++ b/aai-core/src/main/java/org/openecomp/aai/workarounds/RemoveDME2QueryParams.java
@@ -0,0 +1,65 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.aai.workarounds;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+public class RemoveDME2QueryParams {
+
+ private final String[] blacklist = {"version", "envContext", "routeOffer"};
+
+
+ /**
+ * Should remove query params.
+ *
+ * @param params the params
+ * @return true, if successful
+ */
+ public boolean shouldRemoveQueryParams(MultivaluedMap<String, String> params) {
+ boolean remove = true;
+
+ for (String param : blacklist) {
+ if (!params.containsKey(param)) {
+ remove = false;
+ break;
+ }
+ }
+
+ return remove;
+
+ }
+
+ /**
+ * Removes the query params.
+ *
+ * @param params the params
+ */
+ public void removeQueryParams(MultivaluedMap<String, String> params) {
+
+
+ for (String param : blacklist) {
+ params.remove(param);
+ }
+
+
+ }
+
+}