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.HashMap;
26 import java.util.List;
28 import java.util.Map.Entry;
29 import java.util.Optional;
31 import javax.ws.rs.NotFoundException;
32 import javax.ws.rs.core.GenericType;
33 import javax.ws.rs.core.Response;
35 import org.onap.aai.domain.yang.Relationship;
36 import org.onap.so.client.RestClient;
37 import org.onap.so.client.aai.entities.AAIEdgeLabel;
38 import org.onap.so.client.aai.entities.AAIError;
39 import org.onap.so.client.aai.entities.bulkprocess.OperationBody;
40 import org.onap.so.client.aai.entities.bulkprocess.Transaction;
41 import org.onap.so.client.aai.entities.bulkprocess.Transactions;
42 import org.onap.so.client.aai.entities.uri.AAIResourceUri;
43 import org.onap.so.client.aai.entities.uri.AAIUriFactory;
44 import org.onap.so.client.graphinventory.GraphInventoryPatchConverter;
45 import org.onap.so.client.graphinventory.GraphInventoryTransactionalClient;
46 import org.onap.so.client.graphinventory.exceptions.BulkProcessFailed;
47 import org.onap.so.jsonpath.JsonPathUtil;
49 import com.fasterxml.jackson.core.type.TypeReference;
50 import com.fasterxml.jackson.databind.ObjectMapper;
51 import com.google.common.base.Joiner;
53 public class AAITransactionalClient extends AAIClient implements GraphInventoryTransactionalClient<AAITransactionalClient, AAIResourceUri, AAIEdgeLabel> {
55 private final Transactions transactions;
56 private Transaction currentTransaction;
57 private final AAIVersion version;
58 private int actionCount = 0;
60 private final GraphInventoryPatchConverter patchConverter = new GraphInventoryPatchConverter();
62 protected AAITransactionalClient(AAIVersion version) {
64 this.version = version;
65 this.transactions = new Transactions();
69 private void startTransaction() {
70 Transaction transaction = new Transaction();
71 transactions.getTransactions().add(transaction);
72 currentTransaction = transaction;
76 * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#beginNewTransaction()
79 public AAITransactionalClient beginNewTransaction() {
85 * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#create(org.onap.so.client.aai.entities.uri.AAIResourceUri, java.lang.Object)
88 public AAITransactionalClient create(AAIResourceUri uri, Object obj) {
89 currentTransaction.getPut().add(new OperationBody().withUri(uri.build().toString()).withBody(obj));
90 incrementActionAmount();
95 * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#createEmpty(org.onap.so.client.aai.entities.uri.AAIResourceUri)
98 public AAITransactionalClient createEmpty(AAIResourceUri uri) {
99 currentTransaction.getPut().add(new OperationBody().withUri(uri.build().toString()).withBody(new HashMap<String, String>()));
100 incrementActionAmount();
105 * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#connect(org.onap.so.client.aai.entities.uri.AAIResourceUri, org.onap.so.client.aai.entities.uri.AAIResourceUri)
108 public AAITransactionalClient connect(AAIResourceUri uriA, AAIResourceUri uriB) {
109 AAIResourceUri uriAClone = uriA.clone();
110 currentTransaction.getPut().add(new OperationBody().withUri(uriAClone.relationshipAPI().build().toString()).withBody(this.buildRelationship(uriB)));
111 incrementActionAmount();
116 * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#connect(org.onap.so.client.aai.entities.uri.AAIResourceUri, java.util.List)
119 public AAITransactionalClient connect(AAIResourceUri uriA, List<AAIResourceUri> uris) {
120 for (AAIResourceUri uri : uris) {
121 this.connect(uriA, uri);
127 * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#connect(org.onap.so.client.aai.entities.uri.AAIResourceUri, org.onap.so.client.aai.entities.uri.AAIResourceUri, org.onap.so.client.aai.entities.AAIEdgeLabel)
130 public AAITransactionalClient connect(AAIResourceUri uriA, AAIResourceUri uriB, AAIEdgeLabel label) {
131 AAIResourceUri uriAClone = uriA.clone();
132 RestClient aaiRC = this.createClient(uriAClone.relationshipAPI());
133 aaiRC.put(this.buildRelationship(uriB, label));
138 * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#connect(org.onap.so.client.aai.entities.uri.AAIResourceUri, java.util.List, org.onap.so.client.aai.entities.AAIEdgeLabel)
141 public AAITransactionalClient connect(AAIResourceUri uriA, List<AAIResourceUri> uris, AAIEdgeLabel label) {
142 for (AAIResourceUri uri : uris) {
143 this.connect(uriA, uri, label);
149 * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#disconnect(org.onap.so.client.aai.entities.uri.AAIResourceUri, org.onap.so.client.aai.entities.uri.AAIResourceUri)
152 public AAITransactionalClient disconnect(AAIResourceUri uriA, AAIResourceUri uriB) {
153 AAIResourceUri uriAClone = uriA.clone();
154 currentTransaction.getDelete().add(new OperationBody().withUri(uriAClone.relationshipAPI().build().toString()).withBody(this.buildRelationship(uriB)));
155 incrementActionAmount();
160 * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#disconnect(org.onap.so.client.aai.entities.uri.AAIResourceUri, java.util.List)
163 public AAITransactionalClient disconnect(AAIResourceUri uriA, List<AAIResourceUri> uris) {
164 for (AAIResourceUri uri : uris) {
165 this.disconnect(uriA, uri);
170 * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#delete(org.onap.so.client.aai.entities.uri.AAIResourceUri)
173 public AAITransactionalClient delete(AAIResourceUri uri) {
174 AAIResourcesClient client = new AAIResourcesClient();
175 AAIResourceUri clone = uri.clone();
176 Map<String, Object> result = client.get(new GenericType<Map<String, Object>>(){}, clone)
177 .orElseThrow(() -> new NotFoundException(clone.build() + " does not exist in A&AI"));
178 String resourceVersion = (String) result.get("resource-version");
179 currentTransaction.getDelete().add(new OperationBody().withUri(clone.resourceVersion(resourceVersion).build().toString()).withBody(""));
180 incrementActionAmount();
185 * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#update(org.onap.so.client.aai.entities.uri.AAIResourceUri, java.lang.Object)
188 public AAITransactionalClient update(AAIResourceUri uri, Object obj) {
189 final String payload = getPatchConverter().convertPatchFormat(obj);
190 currentTransaction.getPatch().add(new OperationBody().withUri(uri.build().toString()).withBody(payload));
191 incrementActionAmount();
195 private void incrementActionAmount() {
199 * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#execute()
202 public void execute() throws BulkProcessFailed {
203 RestClient client = this.createClient(AAIUriFactory.createResourceUri(AAIObjectType.BULK_PROCESS));
205 Response response = client.put(this.transactions);
206 if (response.hasEntity()) {
207 final Optional<String> errorMessage = this.locateErrorMessages(response.readEntity(String.class));
208 if (errorMessage.isPresent()) {
209 throw new BulkProcessFailed("One or more transactions failed in A&AI. Check logs for payloads.\nMessages:\n" + errorMessage.get());
212 throw new BulkProcessFailed("Transactions acccepted by A&AI, but there was no response. Unsure of result.");
215 this.transactions.getTransactions().clear();
216 this.currentTransaction = null;
217 this.actionCount = 0;
221 protected Optional<String> locateErrorMessages(String response) {
222 final List<String> errorMessages = new ArrayList<>();
223 final List<String> results = JsonPathUtil.getInstance().locateResultList(response, "$..body");
224 final ObjectMapper mapper = new ObjectMapper();
225 if (!results.isEmpty()) {
226 List<Map<String, Object>> parsed = new ArrayList<>();
228 for (String result : results) {
229 parsed.add(mapper.readValue(result, new TypeReference<Map<String, Object>>(){}));
231 } catch (IOException e) {
232 logger.error("could not map json", e);
234 for (Map<String, Object> map : parsed) {
235 for (Entry<String, Object> entry : map.entrySet()) {
236 if (!entry.getKey().matches("2\\d\\d")) {
239 error = mapper.readValue(entry.getValue().toString(), AAIError.class);
240 } catch (IOException e) {
241 logger.error("could not parse error object from A&AI", e);
242 error = new AAIError();
244 AAIErrorFormatter formatter = new AAIErrorFormatter(error);
245 String outputMessage = formatter.getMessage();
246 logger.error("part of a bulk action failed in A&AI: " + entry.getValue());
247 errorMessages.add(outputMessage);
253 if (!errorMessages.isEmpty()) {
254 return Optional.of(Joiner.on("\n").join(errorMessages));
256 return Optional.empty();
259 private Relationship buildRelationship(AAIResourceUri uri) {
260 return buildRelationship(uri, Optional.empty());
263 private Relationship buildRelationship(AAIResourceUri uri, AAIEdgeLabel label) {
264 return buildRelationship(uri, Optional.of(label));
266 private Relationship buildRelationship(AAIResourceUri uri, Optional<AAIEdgeLabel> label) {
267 final Relationship result = new Relationship();
268 result.setRelatedLink(uri.build().toString());
269 if (label.isPresent()) {
270 result.setRelationshipLabel(label.toString());
276 protected AAIVersion getVersion() {
280 protected Transactions getTransactions() {
281 return this.transactions;
284 protected GraphInventoryPatchConverter getPatchConverter() {
285 return this.patchConverter;