2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.so.client.aai;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.List;
27 import java.util.Map.Entry;
28 import java.util.Optional;
29 import javax.ws.rs.core.GenericType;
30 import javax.ws.rs.core.Response;
31 import org.onap.aai.domain.yang.Relationship;
32 import org.onap.so.client.RestClient;
33 import org.onap.so.client.aai.entities.AAIEdgeLabel;
34 import org.onap.so.client.aai.entities.AAIError;
35 import org.onap.so.client.aai.entities.bulkprocess.OperationBody;
36 import org.onap.so.client.aai.entities.bulkprocess.Transaction;
37 import org.onap.so.client.aai.entities.bulkprocess.Transactions;
38 import org.onap.so.client.aai.entities.uri.AAIBaseResourceUri;
39 import org.onap.so.client.aai.entities.uri.AAIResourceUri;
40 import org.onap.so.client.aai.entities.uri.AAIUriFactory;
41 import org.onap.so.client.graphinventory.GraphInventoryPatchConverter;
42 import org.onap.so.client.graphinventory.GraphInventoryTransactionClient;
43 import org.onap.so.client.graphinventory.exceptions.BulkProcessFailed;
44 import org.onap.so.jsonpath.JsonPathUtil;
45 import com.fasterxml.jackson.core.JsonProcessingException;
46 import com.fasterxml.jackson.core.type.TypeReference;
47 import com.fasterxml.jackson.databind.ObjectMapper;
48 import com.google.common.base.Joiner;
50 public class AAITransactionalClient extends
51 GraphInventoryTransactionClient<AAITransactionalClient, AAIBaseResourceUri<?, ?>, AAIResourceUri, AAIEdgeLabel> {
53 private final Transactions transactions;
54 private Transaction currentTransaction;
56 private AAIResourcesClient resourcesClient;
57 private AAIClient aaiClient;
59 protected AAITransactionalClient(AAIResourcesClient resourcesClient, AAIClient aaiClient) {
61 this.resourcesClient = resourcesClient;
62 this.aaiClient = aaiClient;
63 this.transactions = new Transactions();
67 private void startTransaction() {
68 Transaction transaction = new Transaction();
69 transactions.getTransactions().add(transaction);
70 currentTransaction = transaction;
76 * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#beginNewTransaction()
78 public AAITransactionalClient beginNewTransaction() {
86 * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#execute()
89 public void execute() throws BulkProcessFailed {
91 if (!this.transactions.getTransactions().isEmpty()) {
92 RestClient client = aaiClient.createClient(AAIUriFactory.createResourceUri(AAIObjectType.BULK_PROCESS));
93 Response response = client.put(this.transactions);
94 if (response.hasEntity()) {
95 final Optional<String> errorMessage = this.locateErrorMessages(response.readEntity(String.class));
96 if (errorMessage.isPresent()) {
97 throw new BulkProcessFailed(
98 "One or more transactions failed in A&AI. Check logs for payloads.\nMessages:\n"
99 + errorMessage.get());
102 throw new BulkProcessFailed(
103 "Transactions acccepted by A&AI, but there was no response. Unsure of result.");
107 this.transactions.getTransactions().clear();
108 this.currentTransaction = null;
109 this.actionCount = 0;
114 public void execute(boolean dryRun) throws BulkProcessFailed {
115 final ObjectMapper mapper = new ObjectMapper();
118 if (logger.isDebugEnabled()) {
119 logger.debug("Would execute: {}", mapper.writeValueAsString(this.transactions));
121 } catch (JsonProcessingException e) {
122 logger.debug("Could not format request to JSON", e);
129 protected Optional<String> locateErrorMessages(String response) {
130 final List<String> errorMessages = new ArrayList<>();
131 final List<String> results = JsonPathUtil.getInstance().locateResultList(response, "$..body");
132 final ObjectMapper mapper = new ObjectMapper();
133 if (!results.isEmpty()) {
134 List<Map<String, Object>> parsed = new ArrayList<>();
136 for (String result : results) {
137 parsed.add(mapper.readValue(result, new TypeReference<Map<String, Object>>() {}));
139 } catch (IOException e) {
140 logger.error("could not map json", e);
142 for (Map<String, Object> map : parsed) {
143 for (Entry<String, Object> entry : map.entrySet()) {
144 if (!entry.getKey().matches("2\\d\\d")) {
147 error = mapper.readValue(entry.getValue().toString(), AAIError.class);
148 } catch (IOException e) {
149 logger.error("could not parse error object from A&AI", e);
150 error = new AAIError();
152 AAIErrorFormatter formatter = new AAIErrorFormatter(error);
153 String outputMessage = formatter.getMessage();
154 logger.error("part of a bulk action failed in A&AI: " + entry.getValue());
155 errorMessages.add(outputMessage);
161 if (!errorMessages.isEmpty()) {
162 return Optional.of(Joiner.on("\n").join(errorMessages));
164 return Optional.empty();
168 private Relationship buildRelationship(AAIResourceUri uri) {
169 return buildRelationship(uri, Optional.empty());
172 private Relationship buildRelationship(AAIResourceUri uri, AAIEdgeLabel label) {
173 return buildRelationship(uri, Optional.of(label));
176 private Relationship buildRelationship(AAIResourceUri uri, Optional<AAIEdgeLabel> label) {
177 final Relationship result = new Relationship();
178 result.setRelatedLink(uri.build().toString());
179 if (label.isPresent()) {
180 result.setRelationshipLabel(label.toString());
185 protected Transactions getTransactions() {
186 return this.transactions;
190 protected void put(String uri, Object body) {
191 currentTransaction.getPut().add(new OperationBody().withUri(uri).withBody(body));
195 protected void delete(String uri) {
196 currentTransaction.getDelete().add(new OperationBody().withUri(uri).withBody(null));
200 protected void delete(String uri, Object obj) {
201 currentTransaction.getDelete().add(new OperationBody().withUri(uri).withBody(obj));
205 protected void patch(String uri, Object body) {
206 currentTransaction.getPatch().add(new OperationBody().withUri(uri).withBody(body));
210 protected <T> Optional<T> get(GenericType<T> genericType, AAIBaseResourceUri<?, ?> clone) {
211 return resourcesClient.get(genericType, clone);
215 protected boolean exists(AAIBaseResourceUri<?, ?> uri) {
216 return resourcesClient.exists(uri);
220 protected String getGraphDBName() {
221 return aaiClient.getGraphDBName();
225 protected GraphInventoryPatchConverter getPatchConverter() {
226 return this.patchConverter;