diff options
Diffstat (limited to 'common/src')
32 files changed, 1340 insertions, 160 deletions
diff --git a/common/src/main/java/org/onap/so/client/RestClient.java b/common/src/main/java/org/onap/so/client/RestClient.java index 631850a01f..1a453c6b2f 100644 --- a/common/src/main/java/org/onap/so/client/RestClient.java +++ b/common/src/main/java/org/onap/so/client/RestClient.java @@ -271,7 +271,7 @@ public abstract class RestClient { return format(method("DELETE", obj), resultClass).orElse(null); } - private Response method(String method, Object entity) { + public Response method(String method, Object entity) { RetryPolicy policy = new RetryPolicy(); List<Predicate<Throwable>> items = retryOn(); diff --git a/common/src/main/java/org/onap/so/client/RestClientSSL.java b/common/src/main/java/org/onap/so/client/RestClientSSL.java index cb2839ae1f..ac4a8d1a7c 100644 --- a/common/src/main/java/org/onap/so/client/RestClientSSL.java +++ b/common/src/main/java/org/onap/so/client/RestClientSSL.java @@ -56,7 +56,7 @@ public abstract class RestClientSSL extends RestClient { KeyStore ks = getKeyStore(); if(ks != null) { client = ClientBuilder.newBuilder().keyStore(ks, System.getProperty(RestClientSSL.SSL_KEY_STORE_PASSWORD_KEY)).build(); - logger.debug("RestClientSSL not using default SSL context - setting keystore here."); + logger.info("RestClientSSL not using default SSL context - setting keystore here."); return client; } } diff --git a/common/src/main/java/org/onap/so/client/RestTemplateConfig.java b/common/src/main/java/org/onap/so/client/RestTemplateConfig.java index ad833208dc..14556f1211 100644 --- a/common/src/main/java/org/onap/so/client/RestTemplateConfig.java +++ b/common/src/main/java/org/onap/so/client/RestTemplateConfig.java @@ -20,8 +20,10 @@ package org.onap.so.client; +import org.onap.so.logging.jaxrs.filter.SpringClientFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.BufferingClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; @@ -30,6 +32,9 @@ public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { - return new RestTemplate( new HttpComponentsClientHttpRequestFactory()); + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(new HttpComponentsClientHttpRequestFactory())); + restTemplate.getInterceptors().add(new SpringClientFilter()); + return restTemplate; } } diff --git a/common/src/main/java/org/onap/so/client/aai/AAIObjectPlurals.java b/common/src/main/java/org/onap/so/client/aai/AAIObjectPlurals.java index c50653a203..553c1e0db0 100644 --- a/common/src/main/java/org/onap/so/client/aai/AAIObjectPlurals.java +++ b/common/src/main/java/org/onap/so/client/aai/AAIObjectPlurals.java @@ -33,7 +33,8 @@ public enum AAIObjectPlurals implements GraphInventoryObjectPlurals { SERVICE_SUBSCRIPTION(AAIObjectType.CUSTOMER.uriTemplate(), "/service-subscriptions"), SERVICE_INSTANCE(AAIObjectType.SERVICE_SUBSCRIPTION.uriTemplate(), "/service-instances"), OWNING_ENTITIES(AAINamespaceConstants.BUSINESS, "/owning-entities"), - VOLUME_GROUP(AAIObjectType.CLOUD_REGION.uriTemplate(), "/volume-groups/"); + VOLUME_GROUP(AAIObjectType.CLOUD_REGION.uriTemplate(), "/volume-groups/"), + AVAILIBILITY_ZONE(AAIObjectType.CLOUD_REGION.uriTemplate(), "/availability-zones/"); private final String uriTemplate; diff --git a/common/src/main/java/org/onap/so/client/aai/AAIObjectType.java b/common/src/main/java/org/onap/so/client/aai/AAIObjectType.java index a5d8f12e83..4b646f9ed7 100644 --- a/common/src/main/java/org/onap/so/client/aai/AAIObjectType.java +++ b/common/src/main/java/org/onap/so/client/aai/AAIObjectType.java @@ -27,6 +27,7 @@ import org.onap.aai.annotations.Metadata; import org.onap.aai.domain.yang.AllottedResource; import org.onap.aai.domain.yang.CloudRegion; import org.onap.aai.domain.yang.Collection; +import org.onap.aai.domain.yang.Complex; import org.onap.aai.domain.yang.Configuration; import org.onap.aai.domain.yang.Customer; import org.onap.aai.domain.yang.GenericVnf; @@ -64,6 +65,7 @@ public enum AAIObjectType implements GraphInventoryObjectType { CUSTOMER(AAINamespaceConstants.BUSINESS, Customer.class), GENERIC_QUERY("/search", "/generic-query"), BULK_PROCESS("/bulkprocess", ""), + SINGLE_TRANSACTION("/bulk/single-transaction", ""), GENERIC_VNF(AAINamespaceConstants.NETWORK, GenericVnf.class), VF_MODULE(AAIObjectType.GENERIC_VNF.uriTemplate(), VfModule.class), L3_NETWORK(AAINamespaceConstants.NETWORK, L3Network.class), @@ -98,6 +100,7 @@ public enum AAIObjectType implements GraphInventoryObjectType { COLLECTION(AAINamespaceConstants.NETWORK, Collection.class), VNFC(AAINamespaceConstants.NETWORK, Vnfc.class), VLAN_TAG(AAINamespaceConstants.NETWORK, VlanTag.class), + COMPLEX(AAINamespaceConstants.CLOUD_INFRASTRUCTURE, Complex.class), UNKNOWN("", ""); private final String uriTemplate; diff --git a/common/src/main/java/org/onap/so/client/aai/AAIPatchConverter.java b/common/src/main/java/org/onap/so/client/aai/AAIPatchConverter.java new file mode 100644 index 0000000000..6ccb592409 --- /dev/null +++ b/common/src/main/java/org/onap/so/client/aai/AAIPatchConverter.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2018 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.onap.so.client.aai; + +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import org.onap.so.client.graphinventory.exceptions.GraphInventoryPatchDepthExceededException; +import org.onap.so.jsonpath.JsonPathUtil; + +import com.fasterxml.jackson.core.JsonProcessingException; + +public class AAIPatchConverter { + + private static final AAICommonObjectMapperProvider standardProvider = new AAICommonObjectMapperProvider(); + private static final AAICommonObjectMapperPatchProvider patchProvider = new AAICommonObjectMapperPatchProvider(); + private static final Pattern LOCATE_COMPLEX_OBJECT = Pattern.compile("^((?!relationship-list).)+?\\['[^\\[\\]]+?'\\]$"); + + + protected String convertPatchFormat(Object obj) { + return validatePatchObject(marshallObjectToPatchFormat(obj)); + } + + protected String validatePatchObject(String payload) { + if (hasComplexObject(payload)) { + throw new GraphInventoryPatchDepthExceededException(payload); + } + + return payload; + } + + /** validates client side that json does not include any complex objects + * relationship-list is omitted from this validation + */ + protected boolean hasComplexObject(String json) { + if (json.isEmpty()) { + return false; + } + String complex = "$.*.*"; + String array = "$.*.*.*"; + List<String> result = JsonPathUtil.getInstance().getPathList(json, complex); + List<String> result2 = JsonPathUtil.getInstance().getPathList(json, array); + + result.addAll(result2); + return result.stream().anyMatch(item -> LOCATE_COMPLEX_OBJECT.matcher(item).find()); + } + + protected String marshallObjectToPatchFormat(Object obj) { + Object value = obj; + try { + if (!(obj instanceof Map || obj instanceof String)) { + value = patchProvider.getMapper().writeValueAsString(obj); + } else if (obj instanceof Map) { + value = standardProvider.getMapper().writeValueAsString(obj); + } + } catch (JsonProcessingException e) { + value = "{}"; + } + + return (String)value; + } +} diff --git a/common/src/main/java/org/onap/so/client/aai/AAIResourcesClient.java b/common/src/main/java/org/onap/so/client/aai/AAIResourcesClient.java index 072534d6f6..7e4397ec29 100644 --- a/common/src/main/java/org/onap/so/client/aai/AAIResourcesClient.java +++ b/common/src/main/java/org/onap/so/client/aai/AAIResourcesClient.java @@ -309,6 +309,15 @@ public class AAIResourcesClient extends AAIClient { return new AAITransactionalClient(this.getVersion()); } + /** + * Starts a transaction groups multiple A&AI mutations + * + * @return + */ + public AAISingleTransactionClient beginSingleTransaction() { + return new AAISingleTransactionClient(this.getVersion()); + } + private AAIUri addParams(Optional<Depth> depth, boolean nodesOnly, AAIUri uri) { AAIUri clone = uri.clone(); if (depth.isPresent()) { diff --git a/common/src/main/java/org/onap/so/client/aai/AAIRestClient.java b/common/src/main/java/org/onap/so/client/aai/AAIRestClient.java index 2bd5f118c0..ac6e939e9e 100644 --- a/common/src/main/java/org/onap/so/client/aai/AAIRestClient.java +++ b/common/src/main/java/org/onap/so/client/aai/AAIRestClient.java @@ -20,6 +20,8 @@ package org.onap.so.client.aai; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; + import java.net.URI; import java.util.List; import java.util.Map; @@ -41,9 +43,9 @@ public class AAIRestClient extends RestClientSSL { private final AAIProperties aaiProperties; private static final AAICommonObjectMapperProvider standardProvider = new AAICommonObjectMapperProvider(); - private static final AAICommonObjectMapperPatchProvider patchProvider = new AAICommonObjectMapperPatchProvider(); - private static final Pattern LOCATE_COMPLEX_OBJECT = Pattern.compile("^((?!relationship-list).)+?\\['[^\\[\\]]+?'\\]$"); + private final AAIPatchConverter patchConverter = new AAIPatchConverter(); + protected AAIRestClient(AAIProperties props, URI uri) { super(props, Optional.of(uri)); this.aaiProperties = props; @@ -79,53 +81,20 @@ public class AAIRestClient extends RestClientSSL { @Override public Response patch(Object obj) { - String value = convertObjectToPatchFormat(obj); - validatePatchObject(value); - return super.patch(value); + return super.patch(convertToPatchFormat(obj)); } @Override public <T> T patch(Object obj, Class<T> resultClass) { - String value = convertObjectToPatchFormat(obj); - validatePatchObject(value); - return super.patch(value, resultClass); + return super.patch(convertToPatchFormat(obj), resultClass); } - protected String convertObjectToPatchFormat(Object obj) { - Object value = obj; - try { - if (!(obj instanceof Map || obj instanceof String)) { - value = patchProvider.getMapper().writeValueAsString(obj); - } else if (obj instanceof Map) { - value = standardProvider.getMapper().writeValueAsString(obj); - } - } catch (JsonProcessingException e) { - value = "{}"; - } - - return (String)value; + protected AAIPatchConverter getPatchConverter() { + return this.patchConverter; } - - protected void validatePatchObject(String payload) { - if (hasComplexObject(payload)) { - throw new GraphInventoryPatchDepthExceededException(payload); - } - } - - /** validates client side that json does not include any complex objects - * relationship-list is omitted from this validation - */ - protected boolean hasComplexObject(String json) { - if (json.isEmpty()) { - return false; - } - String complex = "$.*.*"; - String array = "$.*.*.*"; - List<String> result = JsonPathUtil.getInstance().getPathList(json, complex); - List<String> result2 = JsonPathUtil.getInstance().getPathList(json, array); - - result.addAll(result2); - return result.stream().anyMatch(item -> LOCATE_COMPLEX_OBJECT.matcher(item).find()); + protected String convertToPatchFormat(Object obj) { + return getPatchConverter().convertPatchFormat(obj); } + } diff --git a/common/src/main/java/org/onap/so/client/aai/AAISingleTransactionClient.java b/common/src/main/java/org/onap/so/client/aai/AAISingleTransactionClient.java new file mode 100644 index 0000000000..2ecdb7c480 --- /dev/null +++ b/common/src/main/java/org/onap/so/client/aai/AAISingleTransactionClient.java @@ -0,0 +1,267 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2018 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.onap.so.client.aai; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; + +import javax.ws.rs.NotFoundException; +import javax.ws.rs.core.GenericType; + +import org.onap.aai.domain.yang.Relationship; +import org.onap.so.client.RestClient; +import org.onap.so.client.aai.entities.AAIEdgeLabel; +import org.onap.so.client.aai.entities.AAIError; +import org.onap.so.client.aai.entities.bulkprocess.Transactions; +import org.onap.so.client.aai.entities.singletransaction.OperationBodyRequest; +import org.onap.so.client.aai.entities.singletransaction.OperationBodyResponse; +import org.onap.so.client.aai.entities.singletransaction.SingleTransactionRequest; +import org.onap.so.client.aai.entities.singletransaction.SingleTransactionResponse; +import org.onap.so.client.aai.entities.uri.AAIResourceUri; +import org.onap.so.client.aai.entities.uri.AAIUri; +import org.onap.so.client.aai.entities.uri.AAIUriFactory; +import org.onap.so.client.graphinventory.exceptions.BulkProcessFailed; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Joiner; + +public class AAISingleTransactionClient extends AAIClient { + + private final SingleTransactionRequest request; + private final AAIVersion version; + private int actionCount = 0; + + private final AAIPatchConverter patchConverter = new AAIPatchConverter(); + + protected AAISingleTransactionClient(AAIVersion version) { + super(); + this.version = version; + this.request = new SingleTransactionRequest(); + } + + /** + * creates a new object in A&AI + * + * @param obj - can be any object which will marshal into a valid A&AI payload + * @param uri + * @return + */ + public AAISingleTransactionClient create(AAIResourceUri uri, Object obj) { + request.getOperations().add(new OperationBodyRequest().withAction("put").withUri(uri.build().toString()).withBody(obj)); + incrementActionAmount(); + return this; + } + + /** + * creates a new object in A&AI with no payload body + * + * @param uri + * @return + */ + public AAISingleTransactionClient createEmpty(AAIResourceUri uri) { + request.getOperations().add(new OperationBodyRequest().withAction("put").withUri(uri.build().toString()).withBody(new HashMap<String, String>())); + incrementActionAmount(); + return this; + } + + /** + * Adds a relationship between two objects in A&AI + * @param uriA + * @param uriB + * @return + */ + public AAISingleTransactionClient connect(AAIResourceUri uriA, AAIResourceUri uriB) { + AAIResourceUri uriAClone = uriA.clone(); + request.getOperations().add(new OperationBodyRequest().withAction("put").withUri(uriAClone.relationshipAPI().build().toString()).withBody(this.buildRelationship(uriB))); + incrementActionAmount(); + return this; + } + + /** + * relationship between multiple objects in A&AI - connects A to all objects specified in list + * + * @param uriA + * @param uris + * @return + */ + public AAISingleTransactionClient connect(AAIResourceUri uriA, List<AAIResourceUri> uris) { + for (AAIResourceUri uri : uris) { + this.connect(uriA, uri); + } + return this; + } + + public AAISingleTransactionClient connect(AAIResourceUri uriA, AAIResourceUri uriB, AAIEdgeLabel label) { + AAIResourceUri uriAClone = uriA.clone(); + RestClient aaiRC = this.createClient(uriAClone.relationshipAPI()); + aaiRC.put(this.buildRelationship(uriB, label)); + return this; + } + + public AAISingleTransactionClient connect(AAIResourceUri uriA, List<AAIResourceUri> uris, AAIEdgeLabel label) { + for (AAIResourceUri uri : uris) { + this.connect(uriA, uri, label); + } + return this; + } + + /** + * Removes relationship from two objects in A&AI + * + * @param uriA + * @param uriB + * @return + */ + public AAISingleTransactionClient disconnect(AAIResourceUri uriA, AAIResourceUri uriB) { + AAIResourceUri uriAClone = uriA.clone(); + request.getOperations().add(new OperationBodyRequest().withAction("delete").withUri(uriAClone.relationshipAPI().build().toString()).withBody(this.buildRelationship(uriB))); + incrementActionAmount(); + return this; + } + + /** + * Removes relationship from multiple objects - disconnects A from all objects specified in list + * @param uriA + * @param uris + * @return + */ + public AAISingleTransactionClient disconnect(AAIResourceUri uriA, List<AAIResourceUri> uris) { + for (AAIResourceUri uri : uris) { + this.disconnect(uriA, uri); + } + return this; + } + /** + * Deletes object from A&AI. Automatically handles resource-version. + * + * @param uri + * @return + */ + public AAISingleTransactionClient delete(AAIResourceUri uri) { + AAIResourcesClient client = new AAIResourcesClient(); + AAIResourceUri clone = uri.clone(); + Map<String, Object> result = client.get(new GenericType<Map<String, Object>>(){}, clone) + .orElseThrow(() -> new NotFoundException(clone.build() + " does not exist in A&AI")); + String resourceVersion = (String) result.get("resource-version"); + request.getOperations().add(new OperationBodyRequest().withAction("delete").withUri(clone.resourceVersion(resourceVersion).build().toString()).withBody("")); + incrementActionAmount(); + return this; + } + + /** + * @param obj - can be any object which will marshal into a valid A&AI payload + * @param uri + * @return + */ + public AAISingleTransactionClient update(AAIResourceUri uri, Object obj) { + + final String payload = getPatchConverter().convertPatchFormat(obj); + request.getOperations().add(new OperationBodyRequest().withAction("patch").withUri(uri.build().toString()).withBody(payload)); + incrementActionAmount(); + return this; + } + + private void incrementActionAmount() { + actionCount++; + } + /** + * Executes all created transactions in A&AI + * @throws BulkProcessFailed + */ + public void execute() throws BulkProcessFailed { + RestClient client = this.createClient(AAIUriFactory.createResourceUri(AAIObjectType.SINGLE_TRANSACTION)); + try { + SingleTransactionResponse response = client.post(this.request, SingleTransactionResponse.class); + if (response != null) { + final Optional<String> errorMessage = this.locateErrorMessages(response); + if (errorMessage.isPresent()) { + throw new BulkProcessFailed("One or more transactions failed in A&AI. Check logs for payloads.\nMessages:\n" + errorMessage.get()); + } + } else { + throw new BulkProcessFailed("Transactions acccepted by A&AI, but there was no response. Unsure of result."); + } + } finally { + this.request.getOperations().clear(); + this.actionCount = 0; + } + } + + protected Optional<String> locateErrorMessages(SingleTransactionResponse response) { + final List<String> errorMessages = new ArrayList<>(); + final ObjectMapper mapper = new ObjectMapper(); + + for (OperationBodyResponse body : response.getOperationResponses()) { + if (Optional.ofNullable(body.getResponseStatusCode()).orElse(400) > 300) { + AAIError error; + try { + error = mapper.readValue(mapper.writeValueAsString(body.getResponseBody()), AAIError.class); + } catch (IOException e) { + logger.error("could not parse error object from A&AI", e); + error = new AAIError(); + } + AAIErrorFormatter formatter = new AAIErrorFormatter(error); + String outputMessage = formatter.getMessage(); + errorMessages.add(outputMessage); + } + } + + if (!errorMessages.isEmpty()) { + return Optional.of(Joiner.on("\n").join(errorMessages)); + } else { + return Optional.empty(); + } + } + + private Relationship buildRelationship(AAIResourceUri uri) { + return buildRelationship(uri, Optional.empty()); + } + + private Relationship buildRelationship(AAIResourceUri uri, AAIEdgeLabel label) { + return buildRelationship(uri, Optional.of(label)); + } + private Relationship buildRelationship(AAIResourceUri uri, Optional<AAIEdgeLabel> label) { + final Relationship result = new Relationship(); + result.setRelatedLink(uri.build().toString()); + if (label.isPresent()) { + result.setRelationshipLabel(label.toString()); + } + return result; + } + + @Override + protected AAIVersion getVersion() { + return this.version; + } + + protected SingleTransactionRequest getRequest() { + return this.request; + } + + protected AAIPatchConverter getPatchConverter() { + return this.patchConverter; + } +} diff --git a/common/src/main/java/org/onap/so/client/aai/AAITransactionalClient.java b/common/src/main/java/org/onap/so/client/aai/AAITransactionalClient.java index 884d2aaec6..118a3edf1c 100644 --- a/common/src/main/java/org/onap/so/client/aai/AAITransactionalClient.java +++ b/common/src/main/java/org/onap/so/client/aai/AAITransactionalClient.java @@ -20,6 +20,8 @@ package org.onap.so.client.aai; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; + import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -34,6 +36,7 @@ import javax.ws.rs.core.Response; import org.onap.aai.domain.yang.Relationship; import org.onap.so.client.RestClient; +import org.onap.so.client.aai.entities.AAIEdgeLabel; import org.onap.so.client.aai.entities.AAIError; import org.onap.so.client.aai.entities.bulkprocess.OperationBody; import org.onap.so.client.aai.entities.bulkprocess.Transaction; @@ -54,6 +57,9 @@ public class AAITransactionalClient extends AAIClient { private Transaction currentTransaction; private final AAIVersion version; private int actionCount = 0; + + private final AAIPatchConverter patchConverter = new AAIPatchConverter(); + protected AAITransactionalClient(AAIVersion version) { super(); this.version = version; @@ -129,6 +135,20 @@ public class AAITransactionalClient extends AAIClient { return this; } + public AAITransactionalClient connect(AAIResourceUri uriA, AAIResourceUri uriB, AAIEdgeLabel label) { + AAIResourceUri uriAClone = uriA.clone(); + RestClient aaiRC = this.createClient(uriAClone.relationshipAPI()); + aaiRC.put(this.buildRelationship(uriB, label)); + return this; + } + + public AAITransactionalClient connect(AAIResourceUri uriA, List<AAIResourceUri> uris, AAIEdgeLabel label) { + for (AAIResourceUri uri : uris) { + this.connect(uriA, uri, label); + } + return this; + } + /** * Removes relationship from two objects in A&AI * @@ -178,7 +198,8 @@ public class AAITransactionalClient extends AAIClient { * @return */ public AAITransactionalClient update(AAIResourceUri uri, Object obj) { - currentTransaction.getPatch().add(new OperationBody().withUri(uri.build().toString()).withBody(obj)); + final String payload = getPatchConverter().convertPatchFormat(obj); + currentTransaction.getPatch().add(new OperationBody().withUri(uri.build().toString()).withBody(payload)); incrementActionAmount(); return this; } @@ -247,9 +268,19 @@ public class AAITransactionalClient extends AAIClient { return Optional.empty(); } } - private Relationship buildRelationship(AAIUri uri) { + private Relationship buildRelationship(AAIResourceUri uri) { + return buildRelationship(uri, Optional.empty()); + } + + private Relationship buildRelationship(AAIResourceUri uri, AAIEdgeLabel label) { + return buildRelationship(uri, Optional.of(label)); + } + private Relationship buildRelationship(AAIResourceUri uri, Optional<AAIEdgeLabel> label) { final Relationship result = new Relationship(); result.setRelatedLink(uri.build().toString()); + if (label.isPresent()) { + result.setRelationshipLabel(label.toString()); + } return result; } @@ -261,4 +292,8 @@ public class AAITransactionalClient extends AAIClient { protected Transactions getTransactions() { return this.transactions; } + + protected AAIPatchConverter getPatchConverter() { + return this.patchConverter; + } } diff --git a/common/src/main/java/org/onap/so/client/aai/entities/bulkprocess/OperationBody.java b/common/src/main/java/org/onap/so/client/aai/entities/bulkprocess/OperationBody.java index 1803440edd..4b2aac1364 100644 --- a/common/src/main/java/org/onap/so/client/aai/entities/bulkprocess/OperationBody.java +++ b/common/src/main/java/org/onap/so/client/aai/entities/bulkprocess/OperationBody.java @@ -23,6 +23,8 @@ package org.onap.so.client.aai.entities.bulkprocess; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonRawValue; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({ @@ -34,6 +36,7 @@ public class OperationBody { @JsonProperty("uri") private String uri; @JsonProperty("body") +@JsonSerialize(using = OperationBodySerializer.class) private Object body; @JsonProperty("uri") diff --git a/common/src/main/java/org/onap/so/client/aai/entities/bulkprocess/OperationBodySerializer.java b/common/src/main/java/org/onap/so/client/aai/entities/bulkprocess/OperationBodySerializer.java new file mode 100644 index 0000000000..2981e0deef --- /dev/null +++ b/common/src/main/java/org/onap/so/client/aai/entities/bulkprocess/OperationBodySerializer.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2018 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.onap.so.client.aai.entities.bulkprocess; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +public class OperationBodySerializer extends StdSerializer<Object> { + + private static final long serialVersionUID = 5367385969270400106L; + + public OperationBodySerializer() { + this(null); + } + public OperationBodySerializer(Class<Object> t) { + super(t); + } + + @Override + public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) + throws IOException, JsonProcessingException { + + if (value instanceof String) { + gen.writeRawValue((String)value); + } else { + gen.writeObject(value); + } + + } + +} + diff --git a/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/OperationBodyRequest.java b/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/OperationBodyRequest.java new file mode 100644 index 0000000000..f2626e9e43 --- /dev/null +++ b/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/OperationBodyRequest.java @@ -0,0 +1,88 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.client.aai.entities.singletransaction; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonRawValue; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ +"action", +"uri", +"body" +}) +public class OperationBodyRequest { + +@JsonProperty("action") +private String action; +@JsonProperty("uri") +private String uri; +@JsonProperty("body") +@JsonSerialize(using = OperationBodyRequestSerializer.class) +private Object body; + + +public String getAction() { + return action; +} + +public void setAction(String action) { + this.action = action; +} + +public OperationBodyRequest withAction(String action) { + this.action = action; + return this; +} +@JsonProperty("uri") +public String getUri() { +return uri; +} + +@JsonProperty("uri") +public void setUri(String uri) { +this.uri = uri; +} + +public OperationBodyRequest withUri(String uri) { +this.uri = uri; +return this; +} + +@JsonProperty("body") +public Object getBody() { +return body; +} + +@JsonProperty("body") +public void setBody(Object body) { +this.body = body; +} + +public OperationBodyRequest withBody(Object body) { +this.body = body; +return this; +} + +} diff --git a/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/OperationBodyRequestSerializer.java b/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/OperationBodyRequestSerializer.java new file mode 100644 index 0000000000..170719962e --- /dev/null +++ b/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/OperationBodyRequestSerializer.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2018 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.onap.so.client.aai.entities.singletransaction; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +public class OperationBodyRequestSerializer extends StdSerializer<Object> { + + private static final long serialVersionUID = 5367385969270400106L; + + public OperationBodyRequestSerializer() { + this(null); + } + public OperationBodyRequestSerializer(Class<Object> t) { + super(t); + } + + @Override + public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) + throws IOException, JsonProcessingException { + + if (value instanceof String) { + gen.writeRawValue((String)value); + } else { + gen.writeObject(value); + } + + } + +} + diff --git a/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/OperationBodyResponse.java b/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/OperationBodyResponse.java new file mode 100644 index 0000000000..71f65b50db --- /dev/null +++ b/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/OperationBodyResponse.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2018 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.onap.so.client.aai.entities.singletransaction; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonPropertyOrder({ +"action", +"uri", +"response-status-code", +"response-body" +}) +public class OperationBodyResponse { + + @JsonProperty("action") + public String action; + @JsonProperty("uri") + public String uri; + @JsonProperty("response-status-code") + public Integer responseStatusCode; + @JsonProperty("response-body") + public Object responseBody; + + public String getAction() { + return action; + } + public void setAction(String action) { + this.action = action; + } + public String getUri() { + return uri; + } + public void setUri(String uri) { + this.uri = uri; + } + @JsonProperty("response-status-code") + public Integer getResponseStatusCode() { + return responseStatusCode; + } + @JsonProperty("response-status-code") + public void setResponseStatusCode(Integer responseStatusCode) { + this.responseStatusCode = responseStatusCode; + } + @JsonProperty("response-body") + public Object getResponseBody() { + return responseBody; + } + @JsonProperty("response-body") + public void getResponseBody(Object responseBody) { + this.responseBody = responseBody; + } +} diff --git a/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/SingleTransactionRequest.java b/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/SingleTransactionRequest.java new file mode 100644 index 0000000000..0d392c453f --- /dev/null +++ b/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/SingleTransactionRequest.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2018 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.onap.so.client.aai.entities.singletransaction; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class SingleTransactionRequest { + + @JsonProperty("operations") + public List<OperationBodyRequest> operations; + + public List<OperationBodyRequest> getOperations() { + + if (operations == null) { + operations = new ArrayList<>(); + } + + return operations; + } + + public void setOperations(List<OperationBodyRequest> operations) { + this.operations = operations; + } +} diff --git a/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/SingleTransactionResponse.java b/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/SingleTransactionResponse.java new file mode 100644 index 0000000000..db251b5b3b --- /dev/null +++ b/common/src/main/java/org/onap/so/client/aai/entities/singletransaction/SingleTransactionResponse.java @@ -0,0 +1,47 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2018 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.onap.so.client.aai.entities.singletransaction; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class SingleTransactionResponse { + + @JsonProperty("operation-responses") + public List<OperationBodyResponse> operationResponses; + + @JsonProperty("operation-responses") + public List<OperationBodyResponse> getOperationResponses() { + if (operationResponses == null) { + operationResponses = new ArrayList<>(); + } + return operationResponses; + } + + @JsonProperty("operation-responses") + public void setOperationResponses(List<OperationBodyResponse> operationResponses) { + this.operationResponses = operationResponses; + } + + +} diff --git a/common/src/main/java/org/onap/so/logger/LogConstants.java b/common/src/main/java/org/onap/so/logger/LogConstants.java new file mode 100644 index 0000000000..ea3c8e2c4a --- /dev/null +++ b/common/src/main/java/org/onap/so/logger/LogConstants.java @@ -0,0 +1,26 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2018 ONAP - SO + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR 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.onap.so.logger; + +public class LogConstants { + public static final String TARGET_ENTITY_HEADER="X-Target-Entity"; + public static final String UNKNOWN_TARGET_ENTITY="Unknown-Target-Entity"; +} diff --git a/common/src/main/java/org/onap/so/logger/MsoLogger.java b/common/src/main/java/org/onap/so/logger/MsoLogger.java index 94ffa71169..c4fba671bb 100644 --- a/common/src/main/java/org/onap/so/logger/MsoLogger.java +++ b/common/src/main/java/org/onap/so/logger/MsoLogger.java @@ -207,30 +207,9 @@ public class MsoLogger { private MsoLogger(MsoLogger.Catalog cat, Class<?> clazz) { this.logger = LoggerFactory.getLogger(clazz); this.auditLogger = LoggerFactory.getLogger("AUDIT"); - this.metricsLogger = LoggerFactory.getLogger("METRIC"); - MsoLogger.initialization(); + this.metricsLogger = LoggerFactory.getLogger("METRIC"); setDefaultLogCatalog(cat); } - - private static synchronized void initialization() { - if (instanceUUID == null || ("").equals(instanceUUID)) { - instanceUUID = getInstanceUUID(); - } - - if (serverIP == null || serverName == null || ("").equals(serverIP) || ("").equals(serverName)) { - try { - InetAddress server = InetAddress.getLocalHost(); - serverIP = server.getHostAddress(); - serverName = server.getHostName(); - } catch (UnknownHostException e) { - initLOGGER.error("Could not get local hostname", e); - serverIP = ""; - serverName = ""; - } - } - } - - public static MsoLogger getMsoLogger(MsoLogger.Catalog cat, Class<?> clazz) { return new MsoLogger(cat,clazz); diff --git a/common/src/main/java/org/onap/so/logging/jaxrs/filter/JaxRsClientLogging.java b/common/src/main/java/org/onap/so/logging/jaxrs/filter/JaxRsClientLogging.java index 49dc71e773..6c2a96c87d 100644 --- a/common/src/main/java/org/onap/so/logging/jaxrs/filter/JaxRsClientLogging.java +++ b/common/src/main/java/org/onap/so/logging/jaxrs/filter/JaxRsClientLogging.java @@ -64,7 +64,7 @@ public class JaxRsClientLogging implements ClientRequestFilter,ClientResponseFil private static Logger logger = LoggerFactory.getLogger(JaxRsClientLogging.class); public void setTargetService(TargetEntity targetEntity){ - MDC.put("TargetEntity", targetEntity.toString()); + MDC.put(ONAPLogConstants.MDCs.TARGET_ENTITY, targetEntity.toString()); } @Override @@ -90,7 +90,7 @@ public class JaxRsClientLogging implements ClientRequestFilter,ClientResponseFil MDC.put(ONAPLogConstants.MDCs.TARGET_SERVICE_NAME, clientRequest.getUri().toString()); MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, ONAPLogConstants.ResponseStatus.INPROGRESS.toString()); setInvocationId(); - MDC.put("TargetEntity",MDC.get("TargetEntity")); + MDC.put(ONAPLogConstants.MDCs.TARGET_ENTITY,MDC.get(ONAPLogConstants.MDCs.TARGET_ENTITY)); } private String extractRequestID(ClientRequestContext clientRequest) { @@ -123,7 +123,7 @@ public class JaxRsClientLogging implements ClientRequestFilter,ClientResponseFil MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, String.valueOf(responseContext.getStatus())); MDC.put(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION,getStringFromInputStream(responseContext)); MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, statusCode); - logger.info(MarkerFactory.getMarker("INVOKE_RETURN"), "InvokeReturn"); + logger.info(ONAPLogConstants.Markers.INVOKE_RETURN, "InvokeReturn"); clearClientMDCs(); } catch ( Exception e) { logger.warn("Error in outgoing JAX-RS Inteceptor", e); @@ -136,6 +136,10 @@ public class JaxRsClientLogging implements ClientRequestFilter,ClientResponseFil MDC.remove(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE); MDC.remove(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION); MDC.remove(ONAPLogConstants.MDCs.RESPONSE_CODE); + MDC.remove(ONAPLogConstants.MDCs.TARGET_ENTITY); + MDC.remove(ONAPLogConstants.MDCs.PARTNER_NAME); + MDC.remove(ONAPLogConstants.MDCs.TARGET_SERVICE_NAME); + MDC.remove(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP); } private static String getStringFromInputStream(ClientResponseContext clientResponseContext) { diff --git a/common/src/main/java/org/onap/so/logging/jaxrs/filter/JaxRsFilterLogging.java b/common/src/main/java/org/onap/so/logging/jaxrs/filter/JaxRsFilterLogging.java index 7d02136860..85a6498748 100644 --- a/common/src/main/java/org/onap/so/logging/jaxrs/filter/JaxRsFilterLogging.java +++ b/common/src/main/java/org/onap/so/logging/jaxrs/filter/JaxRsFilterLogging.java @@ -76,7 +76,7 @@ public class JaxRsFilterLogging implements ContainerRequestFilter,ContainerRespo mdcSetup.setClientIPAddress(httpServletRequest); mdcSetup.setInstanceUUID(); mdcSetup.setEntryTimeStamp(); - MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, "INPROGRESS"); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, ONAPLogConstants.ResponseStatus.INPROGRESS.toString()); logger.info(ONAPLogConstants.Markers.ENTRY, "Entering"); } catch (Exception e) { logger.warn("Error in incoming JAX-RS Inteceptor", e); @@ -163,6 +163,16 @@ public class JaxRsFilterLogging implements ContainerRequestFilter,ContainerRespo MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, containerRequest.getUriInfo().getPath()); } + private void clearClientMDCs() { + MDC.remove(ONAPLogConstants.MDCs.INVOCATION_ID); + MDC.remove(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION); + MDC.remove(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE); + MDC.remove(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION); + MDC.remove(ONAPLogConstants.MDCs.RESPONSE_CODE); + MDC.remove(ONAPLogConstants.MDCs.TARGET_ENTITY); + MDC.remove(ONAPLogConstants.MDCs.PARTNER_NAME); + MDC.remove(ONAPLogConstants.MDCs.TARGET_SERVICE_NAME); + } diff --git a/common/src/main/java/org/onap/so/logging/jaxrs/filter/MDCTaskDecorator.java b/common/src/main/java/org/onap/so/logging/jaxrs/filter/MDCTaskDecorator.java new file mode 100644 index 0000000000..cc2ccb5c2e --- /dev/null +++ b/common/src/main/java/org/onap/so/logging/jaxrs/filter/MDCTaskDecorator.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2018 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.onap.so.logging.jaxrs.filter; + +import java.util.Map; + +import org.slf4j.MDC; +import org.springframework.core.task.TaskDecorator; + +public class MDCTaskDecorator implements TaskDecorator { + + @Override + public Runnable decorate(Runnable runnable) { + Map<String, String> contextMap = MDC.getCopyOfContextMap(); + return () -> { + try { + MDC.setContextMap(contextMap); + runnable.run(); + } finally { + MDC.clear(); + } + }; + } +}
\ No newline at end of file diff --git a/common/src/main/java/org/onap/so/logging/jaxrs/filter/SpringClientFilter.java b/common/src/main/java/org/onap/so/logging/jaxrs/filter/SpringClientFilter.java index 6af7a916d0..cecef1945b 100644 --- a/common/src/main/java/org/onap/so/logging/jaxrs/filter/SpringClientFilter.java +++ b/common/src/main/java/org/onap/so/logging/jaxrs/filter/SpringClientFilter.java @@ -20,8 +20,12 @@ package org.onap.so.logging.jaxrs.filter; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.onap.so.logger.LogConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; @@ -30,20 +34,31 @@ import org.springframework.util.StreamUtils; import java.io.IOException; import java.nio.charset.Charset; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.UUID; +import javax.ws.rs.core.Response; public class SpringClientFilter implements ClientHttpRequestInterceptor { private final Logger log = LoggerFactory.getLogger(this.getClass()); + + private static final String TRACE = "trace-#"; + private static final String SO = "SO"; @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { - logRequest(request, body); + processRequest(request, body); ClientHttpResponse response = execution.execute(request, body); - logResponse(response); + processResponse(response); return response; } - private void logRequest(HttpRequest request, byte[] body) throws IOException { + private void processRequest(HttpRequest request, byte[] body) throws IOException { + setupHeaders(request); + setupMDC(request); if (log.isDebugEnabled()) { log.debug("===========================request begin================================================"); log.debug("URI : {}", request.getURI()); @@ -53,8 +68,60 @@ public class SpringClientFilter implements ClientHttpRequestInterceptor { log.debug("==========================request end================================================"); } } + + private void setupHeaders(HttpRequest clientRequest) { + HttpHeaders headers = clientRequest.getHeaders(); + headers.add(ONAPLogConstants.Headers.REQUEST_ID, extractRequestID(clientRequest)); + headers.add(ONAPLogConstants.Headers.INVOCATION_ID, MDC.get(ONAPLogConstants.MDCs.INVOCATION_ID)); + headers.add(ONAPLogConstants.Headers.PARTNER_NAME, SO); + } + + private String extractRequestID(HttpRequest clientRequest) { + String requestId = MDC.get(ONAPLogConstants.MDCs.REQUEST_ID); + if(requestId == null || requestId.isEmpty() || requestId.equals(TRACE)){ + requestId = UUID.randomUUID().toString(); + log.warn("Could not Find Request ID Generating New One: {}",clientRequest.getURI()); + } + return requestId; + } + + private void setupMDC(HttpRequest clientRequest) { + MDC.put(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP, ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + MDC.put(ONAPLogConstants.MDCs.TARGET_SERVICE_NAME, clientRequest.getURI().toString()); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, ONAPLogConstants.ResponseStatus.INPROGRESS.toString()); + setInvocationId(); + MDC.put(ONAPLogConstants.MDCs.TARGET_ENTITY,extractTargetEntity(clientRequest)); + } + + private String extractTargetEntity(HttpRequest clientRequest) { + HttpHeaders headers = clientRequest.getHeaders(); + String headerTargetEntity = null; + List<String> headerTargetEntityList = headers.get(LogConstants.TARGET_ENTITY_HEADER); + if(headerTargetEntityList!= null && !headerTargetEntityList.isEmpty()) + headerTargetEntity = headerTargetEntityList.get(0); + String targetEntity = MDC.get(ONAPLogConstants.MDCs.TARGET_ENTITY); + if(targetEntity != null && + !targetEntity.isEmpty() ){ + return targetEntity; + }else if(headerTargetEntity != null && + !headerTargetEntity.isEmpty()){ + targetEntity = headerTargetEntity; + }else{ + targetEntity = LogConstants.UNKNOWN_TARGET_ENTITY; + log.warn("Could not Target Entity: {}",clientRequest.getURI()); + } + return targetEntity; + } + + private void setInvocationId() { + String invocationId = MDC.get(ONAPLogConstants.MDCs.INVOCATION_ID); + if(invocationId == null || invocationId.isEmpty()) + invocationId =UUID.randomUUID().toString(); + MDC.put(ONAPLogConstants.MDCs.INVOCATION_ID, invocationId); + } + - private void logResponse(ClientHttpResponse response) throws IOException { + private void processResponse(ClientHttpResponse response) throws IOException { if (log.isDebugEnabled()) { log.debug("============================response begin=========================================="); log.debug("Status code : {}", response.getStatusCode()); @@ -63,5 +130,28 @@ public class SpringClientFilter implements ClientHttpRequestInterceptor { log.debug("Response body: {}", StreamUtils.copyToString(response.getBody(), Charset.defaultCharset())); log.debug("=======================response end================================================="); } + String statusCode; + if(Response.Status.Family.familyOf(response.getRawStatusCode()).equals(Response.Status.Family.SUCCESSFUL)){ + statusCode=ONAPLogConstants.ResponseStatus.COMPLETED.toString(); + }else{ + statusCode=ONAPLogConstants.ResponseStatus.ERROR.toString(); + } + MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, String.valueOf(response.getRawStatusCode())); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION,""); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, statusCode); + log.info(ONAPLogConstants.Markers.INVOKE_RETURN, "InvokeReturn"); + clearClientMDCs(); + } + + private void clearClientMDCs() { + MDC.remove(ONAPLogConstants.MDCs.INVOCATION_ID); + MDC.remove(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION); + MDC.remove(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE); + MDC.remove(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION); + MDC.remove(ONAPLogConstants.MDCs.RESPONSE_CODE); + MDC.remove(ONAPLogConstants.MDCs.TARGET_ENTITY); + MDC.remove(ONAPLogConstants.MDCs.PARTNER_NAME); + MDC.remove(ONAPLogConstants.MDCs.TARGET_SERVICE_NAME); + MDC.remove(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP); } } diff --git a/common/src/main/java/org/onap/so/logging/spring/interceptor/LoggingInterceptor.java b/common/src/main/java/org/onap/so/logging/spring/interceptor/LoggingInterceptor.java index 194a445ce2..4084ad3ff0 100644 --- a/common/src/main/java/org/onap/so/logging/spring/interceptor/LoggingInterceptor.java +++ b/common/src/main/java/org/onap/so/logging/spring/interceptor/LoggingInterceptor.java @@ -45,7 +45,7 @@ public class LoggingInterceptor extends HandlerInterceptorAdapter { Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class); @Autowired - MDCSetup mdcSetup; + private MDCSetup mdcSetup; @Context private Providers providers; @@ -53,7 +53,8 @@ public class LoggingInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - Map<String, String> headers = Collections.list(((HttpServletRequest) request).getHeaderNames()) + + Map<String, String> headers = Collections.list((request).getHeaderNames()) .stream() .collect(Collectors.toMap(h -> h, request::getHeader)); setRequestId(headers); @@ -64,12 +65,27 @@ public class LoggingInterceptor extends HandlerInterceptorAdapter { mdcSetup.setEntryTimeStamp(); mdcSetup.setInstanceUUID(); mdcSetup.setServerFQDN(); - MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, "INPROGRESS"); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, ONAPLogConstants.ResponseStatus.INPROGRESS.toString()); logger.info(ONAPLogConstants.Markers.ENTRY, "Entering"); + if (logger.isDebugEnabled()) + logRequestInformation(request); return true; } - @Override + protected void logRequestInformation(HttpServletRequest request) { + Map<String, String> headers = Collections.list((request).getHeaderNames()) + .stream() + .collect(Collectors.toMap(h -> h, request::getHeader)); + + logger.debug("===========================request begin================================================"); + logger.debug("URI : {}", request.getRequestURI()); + logger.debug("Method : {}", request.getMethod()); + logger.debug("Headers : {}", headers); + logger.debug("==========================request end================================================"); + + } + + @Override public void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { @@ -80,7 +96,7 @@ public class LoggingInterceptor extends HandlerInterceptorAdapter { MDC.clear(); } - private void setResponseStatusCode(HttpServletResponse response) { + protected void setResponseStatusCode(HttpServletResponse response) { String statusCode; if(Response.Status.Family.familyOf(response.getStatus()).equals(Response.Status.Family.SUCCESSFUL)){ statusCode=ONAPLogConstants.ResponseStatus.COMPLETED.toString(); @@ -90,26 +106,26 @@ public class LoggingInterceptor extends HandlerInterceptorAdapter { MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, statusCode); } - private void setServiceName(HttpServletRequest request) { + protected void setServiceName(HttpServletRequest request) { MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, request.getRequestURI()); } - private void setRequestId(Map<String, String> headers) { - String requestId=headers.get(ONAPLogConstants.Headers.REQUEST_ID); + protected void setRequestId(Map<String, String> headers) { + String requestId=headers.get(ONAPLogConstants.Headers.REQUEST_ID.toLowerCase()); if(requestId == null || requestId.isEmpty()) - requestId = UUID.randomUUID().toString(); + requestId = UUID.randomUUID().toString(); MDC.put(ONAPLogConstants.MDCs.REQUEST_ID,requestId); } - private void setInvocationId(Map<String, String> headers) { - String invocationId = headers.get(ONAPLogConstants.Headers.INVOCATION_ID); + protected void setInvocationId(Map<String, String> headers) { + String invocationId = headers.get(ONAPLogConstants.Headers.INVOCATION_ID.toLowerCase()); if(invocationId == null || invocationId.isEmpty()) invocationId =UUID.randomUUID().toString(); MDC.put(ONAPLogConstants.MDCs.INVOCATION_ID, invocationId); } - private void setMDCPartnerName(Map<String, String> headers) { - String partnerName=headers.get(ONAPLogConstants.Headers.PARTNER_NAME); + protected void setMDCPartnerName(Map<String, String> headers) { + String partnerName=headers.get(ONAPLogConstants.Headers.PARTNER_NAME.toLowerCase()); if(partnerName == null || partnerName.isEmpty()) partnerName = ""; MDC.put(ONAPLogConstants.MDCs.PARTNER_NAME,partnerName); diff --git a/common/src/main/java/org/onap/so/serviceinstancebeans/RequestParameters.java b/common/src/main/java/org/onap/so/serviceinstancebeans/RequestParameters.java index 1697a4eb5f..e89c5c7e6a 100644 --- a/common/src/main/java/org/onap/so/serviceinstancebeans/RequestParameters.java +++ b/common/src/main/java/org/onap/so/serviceinstancebeans/RequestParameters.java @@ -43,6 +43,8 @@ public class RequestParameters implements Serializable { private List<Map<String, Object>> userParams = new ArrayList<>(); @JsonProperty("aLaCarte") private Boolean aLaCarte; + @JsonProperty("payload") + private String payload; // DONOT USE. It is intended to handle older VID requests(prior to 1802) @Deprecated @@ -57,9 +59,7 @@ public class RequestParameters implements Serializable { @JsonProperty("usePreload") private Boolean usePreload; // usePreload would always be true for Update @JsonProperty("rebuildVolumeGroups") - private Boolean rebuildVolumeGroups; - @JsonProperty("payload") - private String payload; + private Boolean rebuildVolumeGroups; public String getSubscriptionServiceType() { return subscriptionServiceType; @@ -80,6 +80,13 @@ public class RequestParameters implements Serializable { public Boolean isaLaCarte() { return aLaCarte; } + + public String getPayload(){ + return payload; + } + public void setPayload(String value){ + this.payload = value; + } @Deprecated @Transient @@ -151,13 +158,7 @@ public class RequestParameters implements Serializable { public void setRebuildVolumeGroups(Boolean rebuildVolumeGroups) { this.rebuildVolumeGroups = rebuildVolumeGroups; - } - public String getPayload(){ - return payload; - } - public void setPayload(String value){ - this.payload = value; - } + } @Override public String toString() { diff --git a/common/src/test/java/org/onap/so/client/aai/AAIPatchConverterTest.java b/common/src/test/java/org/onap/so/client/aai/AAIPatchConverterTest.java new file mode 100644 index 0000000000..008b612cd8 --- /dev/null +++ b/common/src/test/java/org/onap/so/client/aai/AAIPatchConverterTest.java @@ -0,0 +1,102 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2018 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.onap.so.client.aai; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aai.domain.yang.GenericVnf; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; + + +@RunWith(MockitoJUnitRunner.class) +public class AAIPatchConverterTest { + + private ObjectMapper mapper = new AAICommonObjectMapperProvider().getMapper(); + + @Test + public void convertObjectToPatchFormatTest() throws URISyntaxException, JsonParseException, JsonMappingException, IOException { + AAIPatchConverter validator = new AAIPatchConverter(); + GenericVnf vnf = new GenericVnf(); + vnf.setIpv4Loopback0Address(""); + String result = validator.marshallObjectToPatchFormat(vnf); + GenericVnf resultObj = mapper.readValue(result.toString(), GenericVnf.class); + assertTrue("expect object to become a String to prevent double marshalling", result instanceof String); + assertNull("expect null because of custom mapper", resultObj.getIpv4Loopback0Address()); + + } + + @Test + public void convertStringToPatchFormatTest() throws URISyntaxException, JsonParseException, JsonMappingException, IOException { + AAIPatchConverter validator = new AAIPatchConverter(); + String payload = "{\"ipv4-loopback0-address\":\"\"}"; + String result = validator.marshallObjectToPatchFormat(payload); + + assertEquals("expect no change", payload, result); + } + + @Test + public void convertMapToPatchFormatTest() throws URISyntaxException, JsonParseException, JsonMappingException, IOException { + AAIPatchConverter validator = new AAIPatchConverter(); + HashMap<String, String> map = new HashMap<>(); + map.put("ipv4-loopback0-address", ""); + String result = validator.marshallObjectToPatchFormat(map); + + assertEquals("expect string", "{\"ipv4-loopback0-address\":\"\"}", result); + } + + @Test + public void hasComplexObjectTest() { + AAIPatchConverter validator = new AAIPatchConverter(); + String hasNesting = "{ \"hello\" : \"world\", \"nested\" : { \"key\" : \"value\" } }"; + String noNesting = "{ \"hello\" : \"world\" }"; + String arrayCase = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"], \"nestedComplex\" : [{\"key\" : \"value\"}]}"; + String empty = "{}"; + String arrayCaseSimpleOnly = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"]}"; + String relationshipListCaseNesting = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"], \"relationship-list\" : [{\"key\" : \"value\"}], \"nested\" : { \"key\" : \"value\" }}"; + String relationshipListCase = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"], \"relationship-list\" : [{\"key\" : \"value\"}]}"; + String nothing = ""; + + assertTrue("expect has nesting", validator.hasComplexObject(hasNesting)); + assertFalse("expect no nesting", validator.hasComplexObject(noNesting)); + assertTrue("expect has nesting", validator.hasComplexObject(arrayCase)); + assertFalse("expect no nesting", validator.hasComplexObject(empty)); + assertFalse("expect no nesting", validator.hasComplexObject(arrayCaseSimpleOnly)); + assertFalse("expect no nesting", validator.hasComplexObject(relationshipListCase)); + assertTrue("expect has nesting", validator.hasComplexObject(relationshipListCaseNesting)); + assertFalse("expect no nesting", validator.hasComplexObject(nothing)); + } + +} diff --git a/common/src/test/java/org/onap/so/client/aai/AAIRestClientTest.java b/common/src/test/java/org/onap/so/client/aai/AAIRestClientTest.java index f2e371c999..752c49eb5b 100644 --- a/common/src/test/java/org/onap/so/client/aai/AAIRestClientTest.java +++ b/common/src/test/java/org/onap/so/client/aai/AAIRestClientTest.java @@ -21,18 +21,16 @@ package org.onap.so.client.aai; import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; -import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; -import java.util.HashMap; import javax.ws.rs.core.Response; @@ -42,11 +40,9 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import org.onap.aai.domain.yang.GenericVnf; +import org.onap.so.client.RestClientSSL; import org.onap.so.client.graphinventory.exceptions.GraphInventoryPatchDepthExceededException; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; @RunWith(MockitoJUnitRunner.class) @@ -61,64 +57,22 @@ public class AAIRestClientTest { public ExpectedException thrown = ExpectedException.none(); @Test - public void convertObjectToPatchFormatTest() throws URISyntaxException, JsonParseException, JsonMappingException, IOException { - AAIRestClient client = new AAIRestClient(props, new URI("")); - GenericVnf vnf = new GenericVnf(); - vnf.setIpv4Loopback0Address(""); - String result = client.convertObjectToPatchFormat(vnf); - GenericVnf resultObj = mapper.readValue(result.toString(), GenericVnf.class); - assertTrue("expect object to become a String to prevent double marshalling", result instanceof String); - assertNull("expect null because of custom mapper", resultObj.getIpv4Loopback0Address()); - - } - - @Test - public void convertStringToPatchFormatTest() throws URISyntaxException, JsonParseException, JsonMappingException, IOException { - AAIRestClient client = new AAIRestClient(props, new URI("")); - String payload = "{\"ipv4-loopback0-address\":\"\"}"; - String result = client.convertObjectToPatchFormat(payload); - - assertEquals("expect no change", payload, result); - } - - @Test - public void convertMapToPatchFormatTest() throws URISyntaxException, JsonParseException, JsonMappingException, IOException { - AAIRestClient client = new AAIRestClient(props, new URI("")); - HashMap<String, String> map = new HashMap<>(); - map.put("ipv4-loopback0-address", ""); - String result = client.convertObjectToPatchFormat(map); - - assertEquals("expect string", "{\"ipv4-loopback0-address\":\"\"}", result); - } - - @Test public void failPatchOnComplexObject() throws URISyntaxException { AAIRestClient client = new AAIRestClient(props, new URI("")); this.thrown.expect(GraphInventoryPatchDepthExceededException.class); this.thrown.expectMessage(containsString("Object exceeds allowed depth for update action")); client.patch("{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"], \"relationship-list\" : [{\"key\" : \"value\"}], \"nested\" : { \"key\" : \"value\" }}"); - } @Test - public void hasComplexObjectTest() throws URISyntaxException { + public void verifyPatchValidation() throws URISyntaxException { AAIRestClient client = new AAIRestClient(props, new URI("")); - String hasNesting = "{ \"hello\" : \"world\", \"nested\" : { \"key\" : \"value\" } }"; - String noNesting = "{ \"hello\" : \"world\" }"; - String arrayCase = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"], \"nestedComplex\" : [{\"key\" : \"value\"}]}"; - String empty = "{}"; - String arrayCaseSimpleOnly = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"]}"; - String relationshipListCaseNesting = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"], \"relationship-list\" : [{\"key\" : \"value\"}], \"nested\" : { \"key\" : \"value\" }}"; - String relationshipListCase = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"], \"relationship-list\" : [{\"key\" : \"value\"}]}"; - String nothing = ""; - - assertTrue("expect has nesting", client.hasComplexObject(hasNesting)); - assertFalse("expect no nesting", client.hasComplexObject(noNesting)); - assertTrue("expect has nesting", client.hasComplexObject(arrayCase)); - assertFalse("expect no nesting", client.hasComplexObject(empty)); - assertFalse("expect no nesting", client.hasComplexObject(arrayCaseSimpleOnly)); - assertFalse("expect no nesting", client.hasComplexObject(relationshipListCase)); - assertTrue("expect has nesting", client.hasComplexObject(relationshipListCaseNesting)); - assertFalse("expect no nesting", client.hasComplexObject(nothing)); + AAIRestClient spy = spy(client); + AAIPatchConverter patchValidatorMock = mock(AAIPatchConverter.class); + doReturn(patchValidatorMock).when(spy).getPatchConverter(); + String payload = "{}"; + doReturn(Response.ok().build()).when(spy).method(eq("PATCH"), any()); + spy.patch(payload); + verify(patchValidatorMock, times(1)).convertPatchFormat(eq((Object)payload)); } } diff --git a/common/src/test/java/org/onap/so/client/aai/AAISingleTransactionClientTest.java b/common/src/test/java/org/onap/so/client/aai/AAISingleTransactionClientTest.java new file mode 100644 index 0000000000..8c42686e5f --- /dev/null +++ b/common/src/test/java/org/onap/so/client/aai/AAISingleTransactionClientTest.java @@ -0,0 +1,133 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2018 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.onap.so.client.aai; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Optional; + +import org.junit.Before; +import org.junit.Test; +import org.onap.aai.domain.yang.Pserver; +import org.onap.aai.domain.yang.v9.Complex; +import org.onap.so.client.aai.entities.singletransaction.SingleTransactionRequest; +import org.onap.so.client.aai.entities.singletransaction.SingleTransactionResponse; +import org.onap.so.client.aai.entities.uri.AAIResourceUri; +import org.onap.so.client.aai.entities.uri.AAIUriFactory; +import org.onap.so.client.defaultproperties.DefaultAAIPropertiesImpl; +import org.skyscreamer.jsonassert.JSONAssert; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +public class AAISingleTransactionClientTest { + + private final static String AAI_JSON_FILE_LOCATION = "src/test/resources/__files/aai/singletransaction/"; + AAIResourceUri uriA = AAIUriFactory.createResourceUri(AAIObjectType.PSERVER, "pserver-hostname"); + AAIResourceUri uriB = AAIUriFactory.createResourceUri(AAIObjectType.COMPLEX, "my-complex"); + + ObjectMapper mapper; + + @Before + public void before() throws JsonParseException, JsonMappingException, IOException { + mapper = new AAICommonObjectMapperProvider().getMapper(); + mapper.enable(SerializationFeature.INDENT_OUTPUT); + } + + @Test + public void testRequest() throws IOException { + AAIResourcesClient client = createClient(); + Pserver pserver = new Pserver(); + pserver.setHostname("pserver-hostname"); + pserver.setFqdn("pserver-bulk-process-single-transactions-multiple-actions-1-fqdn"); + Pserver pserver2 = new Pserver(); + pserver2.setFqdn("patched-fqdn"); + Complex complex = new Complex(); + complex.setCity("my-city"); + AAISingleTransactionClient singleTransaction = + client.beginSingleTransaction() + .create(uriA, pserver) + .update(uriA, pserver2) + .create(uriB, complex); + + + SingleTransactionRequest actual = singleTransaction.getRequest(); + + SingleTransactionRequest expected = mapper.readValue(this.getJson("sample-request.json"), SingleTransactionRequest.class); + + JSONAssert.assertEquals(mapper.writeValueAsString(expected),mapper.writeValueAsString(actual), false); + } + + @Test + public void testFailure() throws IOException { + AAIResourcesClient client = createClient(); + AAISingleTransactionClient singleTransaction = client.beginSingleTransaction(); + SingleTransactionResponse expected = mapper.readValue(this.getJson("sample-response-failure.json"), SingleTransactionResponse.class); + Optional<String> errorMessage = singleTransaction.locateErrorMessages(expected); + + assertThat(expected.getOperationResponses().size(), greaterThan(0)); + assertThat(errorMessage.isPresent(), equalTo(true)); + + } + + @Test + public void testSuccessResponse() throws IOException { + AAIResourcesClient client = createClient(); + AAISingleTransactionClient singleTransaction = client.beginSingleTransaction(); + SingleTransactionResponse expected = mapper.readValue(this.getJson("sample-response.json"), SingleTransactionResponse.class); + Optional<String> errorMessage = singleTransaction.locateErrorMessages(expected); + + assertThat(expected.getOperationResponses().size(), greaterThan(0)); + assertThat(errorMessage.isPresent(), equalTo(false)); + + } + + @Test + public void confirmPatchFormat() { + AAISingleTransactionClient singleTransaction = spy(new AAISingleTransactionClient(AAIVersion.LATEST)); + AAIPatchConverter mock = mock(AAIPatchConverter.class); + doReturn(mock).when(singleTransaction).getPatchConverter(); + singleTransaction.update(uriA, "{}"); + verify(mock, times(1)).convertPatchFormat(any()); + } + private String getJson(String filename) throws IOException { + return new String(Files.readAllBytes(Paths.get(AAI_JSON_FILE_LOCATION + filename))); + } + + private AAIResourcesClient createClient() { + AAIResourcesClient client = spy(new AAIResourcesClient()); + doReturn(new DefaultAAIPropertiesImpl()).when(client).getRestProperties(); + return client; + } +} diff --git a/common/src/test/java/org/onap/so/client/aai/AAITransactionalClientTest.java b/common/src/test/java/org/onap/so/client/aai/AAITransactionalClientTest.java index f6ee826a78..cbf8d67a82 100644 --- a/common/src/test/java/org/onap/so/client/aai/AAITransactionalClientTest.java +++ b/common/src/test/java/org/onap/so/client/aai/AAITransactionalClientTest.java @@ -21,8 +21,12 @@ package org.onap.so.client.aai; import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import java.io.IOException; import java.nio.file.Files; @@ -136,6 +140,15 @@ public class AAITransactionalClientTest { assertEquals(transactions.locateErrorMessages(getJson("response-failure.json")).get(), "another error message\nmy great error"); } + @Test + public void confirmPatchFormat() { + AAITransactionalClient client = spy(new AAITransactionalClient(AAIVersion.LATEST)); + AAIPatchConverter mock = mock(AAIPatchConverter.class); + doReturn(mock).when(client).getPatchConverter(); + client.update(uriA, "{}"); + verify(mock, times(1)).convertPatchFormat(any()); + } + private String getJson(String filename) throws IOException { return new String(Files.readAllBytes(Paths.get(AAI_JSON_FILE_LOCATION + filename))); } diff --git a/common/src/test/resources/__files/aai/singletransaction/sample-request.json b/common/src/test/resources/__files/aai/singletransaction/sample-request.json new file mode 100644 index 0000000000..f0761a07b6 --- /dev/null +++ b/common/src/test/resources/__files/aai/singletransaction/sample-request.json @@ -0,0 +1,26 @@ +{ + "operations": [ + { + "action": "put", + "uri": "/cloud-infrastructure/pservers/pserver/pserver-hostname", + "body": { + "hostname": "pserver-hostname", + "fqdn": "pserver-bulk-process-single-transactions-multiple-actions-1-fqdn" + } + }, + { + "action": "patch", + "uri": "/cloud-infrastructure/pservers/pserver/pserver-hostname", + "body": { + "fqdn": "patched-fqdn" + } + }, + { + "action": "put", + "uri": "/cloud-infrastructure/complexes/complex/my-complex", + "body": { + "city": "my-city" + } + } + ] +}
\ No newline at end of file diff --git a/common/src/test/resources/__files/aai/singletransaction/sample-response-failure.json b/common/src/test/resources/__files/aai/singletransaction/sample-response-failure.json new file mode 100644 index 0000000000..d0b0e39924 --- /dev/null +++ b/common/src/test/resources/__files/aai/singletransaction/sample-response-failure.json @@ -0,0 +1,30 @@ +{ + "operation-responses": [ + { + "action": "put", + "uri": "/cloud-infrastructure/pservers/pserver/pserver-hostname", + "response-status-code": 201, + "response-body": null + }, + { + "action": "patch", + "uri": "/cloud-infrastructure/pservers/pserver/pserver-hostname", + "response-status-code": 200, + "response-body": null + }, + { + "action": "put", + "uri": "/cloud-infrastructure/complexes/complex/my-complex", + "response-status-code": 400, + "response-body": { + "requestError": { + "serviceException": { + "messageId": "SVC3003", + "text": "another error message", + "variables": [] + } + } + } + } + ] +}
\ No newline at end of file diff --git a/common/src/test/resources/__files/aai/singletransaction/sample-response.json b/common/src/test/resources/__files/aai/singletransaction/sample-response.json new file mode 100644 index 0000000000..a5b322ee2e --- /dev/null +++ b/common/src/test/resources/__files/aai/singletransaction/sample-response.json @@ -0,0 +1,22 @@ +{ + "operation-responses": [ + { + "action": "put", + "uri": "/cloud-infrastructure/pservers/pserver/pserver-hostname", + "response-status-code": 201, + "response-body": null + }, + { + "action": "patch", + "uri": "/cloud-infrastructure/pservers/pserver/pserver-hostname", + "response-status-code": 200, + "response-body": null + }, + { + "action": "put", + "uri": "/cloud-infrastructure/complexes/complex/my-complex", + "response-status-code": 201, + "response-body": null + } + ] +}
\ No newline at end of file |