blob: 823027f23d749912e18e6d36d9df9543a092aafb [file] [log] [blame]
Piotr Marcinkiewicz73aec242020-08-18 16:14:33 +02001.. This work is licensed under a Creative Commons Attribution 4.0 International License.
2.. http://creativecommons.org/licenses/by/4.0
3
4Available APIs
5==============
6
Michal Bankad628e672020-08-21 13:36:37 +02007
Piotr Marcinkiewicz73aec242020-08-18 16:14:33 +02008.. toctree::
9 :depth: 3
10
11
12cbs-client - a Config Binding Service client
13--------------------------------------------
14CbsClientFactory can be used to lookup for CBS in your application. Returned CbsClient can then be used to get a configuration, poll for configuration or poll for configuration changes.
15
16The following CBS endpoints are supported by means of different CbsRequests:
17 - get-configuration created by CbsRequests.getConfiguration method - returns the service configuration
18 - get-by-key created by CbsRequests.getByKey method - returns componentName:key entry from Consul
19 - get-all created by CbsRequests.getAll method - returns everything which relates to the service (configuration, policies, etc.)
20
21Sample usage:
22
23.. code-block:: java
24
25 // Generate RequestID and InvocationID which will be used when logging and in HTTP requests
26 final RequestDiagnosticContext diagnosticContext = RequestDiagnosticContext.create();
27 final CbsRequest request = CbsRequests.getConfiguration(diagnosticContext);
28
29 // Read necessary properties from the environment
30 final CbsClientConfiguration config = CbsClientConfiguration.fromEnvironment();
31
32 // Create the client and use it to get the configuration
33 CbsClientFactory.createCbsClient(config)
34 .flatMap(cbsClient -> cbsClient.get(request))
35 .subscribe(
36 jsonObject -> {
37 // do a stuff with your JSON configuration using GSON API
38 final int port = Integer.parseInt(jsonObject.get("collector.listen_port").getAsString());
39 // ...
40 },
41 throwable -> {
42 logger.warn("Ooops", throwable);
43 });
44
45
46Note that a subscribe handler can/will be called in separate thread asynchronously after CBS address lookup succeeds and CBS service call returns a result.
47
48If you are interested in calling CBS periodically and react only when the configuration changed you can use updates method:
49
50.. code-block:: java
51
52 // Generate RequestID and InvocationID which will be used when logging and in HTTP requests
53 final RequestDiagnosticContext diagnosticContext = RequestDiagnosticContext.create();
54 final CbsRequest request = CbsRequests.getConfiguration(diagnosticContext);
55
56 // Read necessary configuration from the environment
57 final CbsClientConfiguration config = CbsClientConfiguration.fromEnvironment();
58
59 // Polling properties
60 final Duration initialDelay = Duration.ofSeconds(5);
61 final Duration period = Duration.ofMinutes(1);
62
63 // Create the client and use it to get the configuration
64 CbsClientFactory.createCbsClient(config)
65 .flatMapMany(cbsClient -> cbsClient.updates(request, initialDelay, period))
66 .subscribe(
67 jsonObject -> {
68 // do a stuff with your JSON configuration using GSON API
69 final int port = Integer.parseInt(jsonObject.get("collector.listen_port").getAsString());
70 // ...
71 },
72 throwable -> {
73 logger.warn("Ooops", throwable);
74 });
75
76The most significant change is in line 14. We are using flatMapMany since we want to map one CbsClient to many JsonObject updates. After 5 seconds CbsClient will call CBS every minute. If the configuration has changed it will pass the JsonObject downstream - in our case consumer of JsonObject will be called.
77
78Parsing streams' definitions:
79
80- CBS configuration response contains various service-specific entries. It also contains a standardized DCAE streams definitions as streams_publishes and streams_subscribes JSON objects. CBS Client API provides a way of parsing this part of configuration so you can use Java objects instead of low-level GSON API.
81- Because streams definitions are a simple value objects we were not able to provide you a nice polymorphic API. Instead you have 2-level API at your disposal:
82 - You can extract raw streams by means of DataStreams.namedSinks (for streams_publishes) and DataStreams.namedSources (for streams_subscribes).
83 - Then you will be able to parse the specific entry from returned collection to a desired stream type by means of parsers built by StreamFromGsonParsers factory.
84
85- Sample usage:
86
87 .. code-block:: java
88
89 final CbsRequest request = CbsRequests.getConfiguration(RequestDiagnosticContext.create());
90 final StreamFromGsonParser<MessageRouterSink> mrSinkParser = StreamFromGsonParsers.messageRouterSinkParser();
91
92 CbsClientFactory.createCbsClient(CbsClientConfiguration.fromEnvironment())
93 .flatMapMany(cbsClient -> cbsClient.updates(request, Duration.ofSeconds(5), Duration.ofMinutes(1)))
94 .map(DataStreams::namedSinks)
95 .map(sinks -> sinks.filter(StreamPredicates.streamOfType(MESSAGE_ROUTER)).map(mrSinkParser::unsafeParse).toList())
96 .subscribe(
97 mrSinks -> mrSinks.forEach(mrSink -> {
98 logger.info(mrSink.name()); // name = the configuration key
99 logger.info(mrSink.aafCredentials().username()); // = aaf_username
100 logger.info(mrSink.topicUrl());
101 // ...
102 }),
103 throwable -> logger.warn("Ooops", throwable)
104 );
105
106 For details and sample usage please refer to JavaDoc and unit and integration tests. Especially `CbsClientImplIT <https://gerrit.onap.org/r/gitweb?p=dcaegen2/services/sdk.git;a=blob;f=rest-services/cbs-client/src/test/java/org/onap/dcaegen2/services/sdk/rest/services/cbs/client/impl/CbsClientImplIT.java;hb=HEAD>`_, `MessageRouterSinksIT <https://gerrit.onap.org/r/gitweb?p=dcaegen2/services/sdk.git;a=blob;f=rest-services/cbs-client/src/test/java/org/onap/dcaegen2/services/sdk/rest/services/cbs/client/api/streams/MessageRouterSinksIT.java;hb=HEAD>`_ and `MixedDmaapStreamsIT <https://gerrit.onap.org/r/gitweb?p=dcaegen2/services/sdk.git;a=blob;f=rest-services/cbs-client/src/test/java/org/onap/dcaegen2/services/sdk/rest/services/cbs/client/api/streams/MixedDmaapStreamsIT.java;hb=HEAD>`_ might be useful.
107
108- INFO
109 Results of these parsers (MessageRouterSink, MessageRouterSource) can be directly used to connect to DMaaP MR by means of dmaap-client API described below.
110
111crypt-password - an utility for BCrypt passwords
112------------------------------------------------
113Library to generate and match cryptography password using BCrypt algorithm
114
115.. code-block:: java
116
117 java -jar crypt-password-${sdk.version}.jar password_to_crypt
118
119 $2a$10$iDEKdKknakPqH5XZb6wEmeBP2SMRwwiWHy8RNioUTNycIomjIqCAO
120
121Can be used like maven dependency to match generated password.
122
123dmaap-client - a DMaaP MR client
124--------------------------------
125After parsing CBS sink definitions you will get a Source or Sink value object. It can be then directly used to communicate with DMaaP Message Router REST API.
126
127Writing message publisher
128
129.. code-block:: java
130
131 final MessageRouterPublisher publisher = DmaapClientFactory.createMessageRouterPublisher();
132 final MessageRouterSink sinkDefinition; //... Sink definition obtained by parsing CBS response
133 final MessageRouterPublishRequest request = ImmutableMessageRouterPublishRequest.builder()
134 .sinkDefinition(sinkDefinition)
135 .build();
136
137 Flux.just(1, 2, 3)
138 .map(JsonPrimitive::new)
139 .transform(input -> publisher.put(request, input))
140 .subscribe(resp -> {
141 if (resp.successful()) {
142 logger.debug("Sent a batch of messages to the MR");
143 } else {
144 logger.warn("Message sending has failed: {}", resp.failReason());
145 }
146 },
147 ex -> {
148 logger.warn("An unexpected error while sending messages to DMaaP", ex);
149 });
150
151Note that we are using Reactor transform operator. As an alternative you could assign Flux of JSON values to the variable and then invoke publisher.put on it. The important performance-related thing to remember is that you should feed the put method with a stream of messages instead of multiple calls with single messages. This way the client API will be able to send them in batches which should significantly improve performance (at least on transfer level).
152
153Writing message subscriber
154
155.. code-block:: java
156
157 final MessageRouterSource sourceDefinition; //... Source definition obtained by parsing CBS response
158 final MessageRouterSubscribeRequest request = ImmutableMessageRouterSubscribeRequest.builder()
159 .sourceDefinition(sourceDefinition)
160 .build();
161
162 cut.subscribeForElements(request, Duration.ofMinutes(1))
163 .map(JsonElement::getAsJsonObject)
164 .subscribe(json -> {
165 // application logic
166 },
167 ex -> {
168 logger.warn("An unexpected error while receiving messages from DMaaP", ex);
169 });
170
tkogut5ff189c2021-02-02 13:28:16 +0100171******************************************
172Configure timeout when talking to DMaaP-MR
173******************************************
174
175* publisher:
176
177.. code-block:: java
178
179 final MessageRouterPublishRequest request = ImmutableMessageRouterPublishRequest.builder()
180 .timeoutConfig(ImmutableDmaapTimeoutConfig.builder()
181 .timeout(Duration.ofSeconds(2))
182 .build())
183 .
184 .
185 .
186 .build();
187
188* subscriber:
189
190.. code-block:: java
191
192 final MessageRouterSubscribeRequest request = ImmutableMessageRouterSubscribeRequest.builder()
193 .timeoutConfig(ImmutableDmaapTimeoutConfig.builder()
194 .timeout(Duration.ofSeconds(2))
195 .build())
196 .
197 .
198 .
199 .build();
200
201The default timeout value (4 seconds) can be used:
202
203.. code-block:: java
204
205 ImmutableDmaapTimeoutConfig.builder().build()
206
207For timeout exception following message is return as failReason in DmaapResponse:
208
209.. code-block:: RST
210
211 408 Request Timeout
212 {"requestError":{"serviceException":{"messageId":"SVC0001","text":"Client timeout exception occurred, Error code is %1","variables":["408"]}}}
213
214*************************
215Configure retry mechanism
216*************************
217
218* publisher:
219
220.. code-block:: java
221
222 final MessageRouterPublisherConfig config = ImmutableMessageRouterPublisherConfig.builder()
223 .retryConfig(ImmutableDmaapRetryConfig.builder()
224 .retryIntervalInSeconds(2)
225 .retryCount(2)
226 .build())
227 .
228 .
229 .
230 .build();
231 final MessageRouterPublisher publisher = DmaapClientFactory.createMessageRouterPublisher(config);
232
233* subscriber:
234
235.. code-block:: java
236
237 final MessageRouterSubscriberConfig config = ImmutableMessageRouterSubscriberConfig.builder()
238 .retryConfig(ImmutableDmaapRetryConfig.builder()
239 .retryIntervalInSeconds(2)
240 .retryCount(2)
241 .build())
242 .
243 .
244 .
245 .build();
246 final MessageRouterSubscriber subscriber = DmaapClientFactory.createMessageRouterSubscriber(config);
247
248The default retry config (retryCount=3, retryIntervalInSeconds=1) can be used:
249
250.. code-block:: java
251
252 ImmutableDmaapRetryConfig.builder().build()
253
254Retry functionality works for:
255 - DMaaP MR HTTP response status codes: 404, 408, 413, 429, 500, 502, 503, 504
256 - Java Exception classes: ReadTimeoutException, ConnectException
257
Pawel97c255e2021-02-09 14:23:48 +0100258**************************************
259Configure custom persistent connection
260**************************************
261
262* publisher:
263
264.. code-block:: java
265
266 final MessageRouterPublisherConfig connectionPoolConfiguration = ImmutableMessageRouterPublisherConfig.builder()
267 .connectionPoolConfig(ImmutableDmaapConnectionPoolConfig.builder()
268 .connectionPool(16)
269 .maxIdleTime(10) //in seconds
270 .maxLifeTime(20) //in seconds
271 .build())
272 .build();
273 final MessageRouterPublisher publisher = DmaapClientFactory.createMessageRouterPublisher(connectionPoolConfiguration);
274
275* subscriber:
276
277.. code-block:: java
278
279 final MessageRouterSubscriberConfig connectionPoolConfiguration = ImmutableMessageRouterSubscriberConfig.builder()
280 .connectionPoolConfig(ImmutableDmaapConnectionPoolConfig.builder()
281 .connectionPool(16)
282 .maxIdleTime(10) //in seconds
283 .maxLifeTime(20) //in seconds
284 .build())
285 .build();
286 final MessageRouterSubscriber subscriber = DmaapClientFactory.createMessageRouterSubscriber(connectionPoolConfiguration);
287
288The default custom persistent connection configuration (connectionPool=16, maxLifeTime=2147483647, maxIdleTime=2147483647) can be used:
289
290.. code-block:: java
291
292 ImmutableDmaapConnectionPoolConfig.builder().build()
293
tkoguteb4cf542021-03-12 11:07:53 +0100294***************************************
295Configure request for authorized topics
296***************************************
297
298* publisher:
299
300.. code-block:: java
301
302 final MessageRouterSink sink = ImmutableMessageRouterSink.builder()
303 .aafCredentials(ImmutableAafCredentials.builder()
304 .username("username")
305 .password("password").build())
306 .
307 .
308 .
309 .build();
310
311 final MessageRouterPublishRequest request = ImmutableMessageRouterPublishRequest.builder()
312 .sinkDefinition(sink)
313 .
314 .
315 .
316 .build();
317
318* subscriber:
319
320.. code-block:: java
321
322 final MessageRouterSource sourceDefinition = ImmutableMessageRouterSource.builder()
323 .aafCredentials(ImmutableAafCredentials.builder()
324 .username("username")
325 .password("password")
326 .build())
327 .
328 .
329 .
330 .build();
331
332 final MessageRouterSubscribeRequest request = ImmutableMessageRouterSubscribeRequest.builder()
333 .sourceDefinition(sourceDefinition)
334 .
335 .
336 .
337 .build();
338
339AAF Credentials are optional for subscribe/publish requests.
340Username and password are used for basic authentication header during sending HTTP request to dmaap-mr.
341
Piotr Marcinkiewicz73aec242020-08-18 16:14:33 +0200342hvvesclient-producer - a reference Java implementation of High Volume VES Collector client
343------------------------------------------------------------------------------------------
344This library is used in xNF simulator which helps us test HV VES Collector in CSIT tests. You may use it as a reference when implementing your code in non-JVM language or directly when using Java/Kotlin/etc.
345
346Sample usage:
347
348.. code-block:: java
349
350 final ProducerOptions producerOptions = ImmutableProducerOptions.builder()
351 .collectorAddresses(HashSet.of(
352 InetSocketAddress.createUnresolved("dcae-hv-ves-collector", 30222)))
353 .build();
354 final HvVesProducer hvVesProducer = HvVesProducerFactory.create(producerOptions);
355
356 Flux<VesEvent> events; // ...
357 Mono.from(hvVesProducer.send(events))
358 .doOnSuccess(() -> logger.info("All events has been sent"))
359 .doOnError(ex -> logger.warn("Failed to send one or more events", ex))
360 .subscribe();
Michal Bankad628e672020-08-21 13:36:37 +0200361
362external-schema-manager - JSON Validator with schema mapping
363------------------------------------------------------------
364This library can be used to validate any JSON content incoming as JsonNode. What differs it from other validation
365libraries is mapping of externally located schemas to local schema files.
366
367Validated JSON must have one field that will refer to an external schema, which will be mapped to local file and then
368validation of any chosen part of JSON is executed using local schema.
369
370Mapping file is cached on validator creation, so it's not read every time validation is performed.
371Schemas' content couldn't be cached due to external library restrictions (OpenAPI4j).
372
373Example JSON:
374
375.. code-block:: json
376
377 {
378 "schemaReference": "https://forge.3gpp.org/rep/sa5/data-models/blob/REL-16/OpenAPI/faultMnS.yaml",
379 "data":
380 {
381 "exampleData: "SAMPLE_VALUE"
382 }
383 }
384
385Interface:
386
387There are two methods, that are interface of this sub-project.
388
389Validator builder:
390
391.. code-block:: java
392
393 new StndDefinedValidator.ValidatorBuilder()
394 .mappingFilePath(mappingFilePath)
395 .schemasPath(schemasPath)
396 .schemaRefPath(schemaRefPath)
397 .stndDefinedDataPath(stndDefinedDataPath)
398 .build();
399
400
401Validator usage:
402
403.. code-block:: java
404
405 stndDefinedValidator.validate(event);
406
407There are 4 string parameters of the builder:
408
409.. csv-table:: **String parameters of the builder**
410 :header: "Name", "Description", "Example", "Note"
411 :widths: 10, 20, 20, 20
412
413 "mappingFilePath", "This should be a local filesystem path to file with mappings of public URLs to local URLs. Format of the schema mapping file is a JSON file with list of mappings", "etc/externalRepo/schema-map.json", " "
414 "schemasPath", "Schemas path is a directory under which external-schema-manager will search for local schemas", "./etc/externalRepo/ and first mapping from example mappingFile is taken, validator will look for schema under the path: ./etc/externalRepo/3gpp/rep/sa5/data-models/blob/REL-16/OpenAPI/faultMnS.yaml", " "
415 "schemaRefPath", "This is an internal path from validated JSON. It should define which field will be taken as public schema reference, which is later mapped", "/event/stndDefinedFields/schemaReference", "In SDK version 1.4.2 this path doesn't use JSON path notation (with . signs). It might change in further versions"
416 "stndDefinedDataPath", "This is path to stndDefined data in JSON. This fields will be validated during stndDefined validation.", "/event/stndDefinedFields/data", "In SDK version 1.4.2 this path doesn't use JSON path notation (with . signs). It might change in further versions."
417
418
419Format of the schema mapping file is a JSON file with list of mappings, as shown in the example below.
420
421.. code-block:: json
422
423 [
424 {
425 "publicURL": "https://forge.3gpp.org/rep/sa5/data-models/blob/REL-16/OpenAPI/faultMnS.yaml",
426 "localURL": "3gpp/rep/sa5/data-models/blob/REL-16/OpenAPI/faultMnS.yaml"
427 },
428 {
429 "publicURL": "https://forge.3gpp.org/rep/sa5/data-models/blob/REL-16/OpenAPI/heartbeatNtf.yaml",
430 "localURL": "3gpp/rep/sa5/data-models/blob/REL-16/OpenAPI/heartbeatNtf.yaml"
431 },
432 {
433 "publicURL": "https://forge.3gpp.org/rep/sa5/data-models/blob/REL-16/OpenAPI/PerDataFileReportMnS.yaml",
434 "localURL": "3gpp/rep/sa5/data-models/blob/REL-16/OpenAPI/PerDataFileReportMnS.yaml"
435 },
436 {
437 "publicURL": "https://forge.3gpp.org/rep/sa5/data-models/blob/master/OpenAPI/provMnS.yaml",
438 "localURL": "3gpp/rep/sa5/data-models/blob/REL-16/OpenAPI/provMnS.yaml"
439 }
440 ]
441
442**Possible scenarios when using external-schema-manger:**
443
444When the schema-map file, the schema and the sent event are correct, then the validation is successful and the log
445shows "Validation of stndDefinedDomain has been successful".
446
447Errors in the schema-map - none of the mappings are cached:
448
449- When no schema-map file exists, "Unable to read mapping file. Mapping file path: {}" is logged.
450- When a schema-map file exists, but has an incorrect format, a warning is logged: "Schema mapping file has incorrect format. Mapping file path: {}"
451
452Errors in one of the mappings in schema-map - this mapping is not cached, a warning is logged "Mapping for publicURL ({}) will not be cached to validator.":
453
454- When the local url in the schema-map file references a file that does not exist, the warning "Local schema resource missing. Schema file with path {} has not been found."
455- When the schema file is empty, the information "Schema file is empty. Schema path: {}" is logged
456- When a schema file has an incorrect format (not a yaml), the following information is logged: Schema has incorrect YAML structure. Schema path: {} "
457
458Errors in schemaRefPath returns errors:
459
460- If in the schemaRef path in the event we provide an url that refers to an existing schema, but the part after # refers to a non-existent part of it, then an error is thrown: IncorrectInternalFileReferenceException ("Schema reference refer to existing file, but internal reference (after #) is incorrect.") "
tkogut5ff189c2021-02-02 13:28:16 +0100461- When in the schemaRef path in the event, we provide a url that refers to a non-existent mapping from public to localURL, a NoLocalReferenceException is thrown, which logs to the console: "Couldn't find mapping for public url. PublicURL: {}"