Merge "fix major sonar bug"
[so.git] / common / src / main / java / org / onap / so / client / aai / AAITransactionalClient.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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=========================================================
19  */
20
21 package org.onap.so.client.aai;
22
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Map.Entry;
28 import java.util.Optional;
29
30 import javax.ws.rs.core.GenericType;
31 import javax.ws.rs.core.Response;
32
33 import org.onap.aai.domain.yang.Relationship;
34 import org.onap.so.client.RestClient;
35 import org.onap.so.client.aai.entities.AAIEdgeLabel;
36 import org.onap.so.client.aai.entities.AAIError;
37 import org.onap.so.client.aai.entities.bulkprocess.OperationBody;
38 import org.onap.so.client.aai.entities.bulkprocess.Transaction;
39 import org.onap.so.client.aai.entities.bulkprocess.Transactions;
40 import org.onap.so.client.aai.entities.uri.AAIResourceUri;
41 import org.onap.so.client.aai.entities.uri.AAIUriFactory;
42 import org.onap.so.client.graphinventory.GraphInventoryPatchConverter;
43 import org.onap.so.client.graphinventory.GraphInventoryTransactionClient;
44 import org.onap.so.client.graphinventory.exceptions.BulkProcessFailed;
45 import org.onap.so.jsonpath.JsonPathUtil;
46
47 import com.fasterxml.jackson.core.type.TypeReference;
48 import com.fasterxml.jackson.databind.ObjectMapper;
49 import com.google.common.base.Joiner;
50
51 public class AAITransactionalClient extends GraphInventoryTransactionClient<AAITransactionalClient, AAIResourceUri, AAIEdgeLabel> {
52
53         private final Transactions transactions;
54         private Transaction currentTransaction;
55         
56         private AAIResourcesClient resourcesClient;
57         private AAIClient aaiClient;
58         protected AAITransactionalClient(AAIResourcesClient resourcesClient, AAIClient aaiClient) {
59                 super();
60                 this.resourcesClient = resourcesClient;
61                 this.aaiClient = aaiClient;
62                 this.transactions = new Transactions();
63                 startTransaction();
64         }
65         
66         private void startTransaction() {
67                 Transaction transaction = new Transaction();
68                 transactions.getTransactions().add(transaction);
69                 currentTransaction = transaction;
70         }
71         
72         /* (non-Javadoc)
73          * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#beginNewTransaction()
74          */
75         public AAITransactionalClient beginNewTransaction() {
76                 startTransaction();
77                 return this;
78         }
79         
80         /* (non-Javadoc)
81          * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#execute()
82          */
83         @Override
84         public void execute() throws BulkProcessFailed {
85                 RestClient client = aaiClient.createClient(AAIUriFactory.createResourceUri(AAIObjectType.BULK_PROCESS));
86                 try {
87                         Response response = client.put(this.transactions);
88                         if (response.hasEntity()) {
89                                 final Optional<String> errorMessage = this.locateErrorMessages(response.readEntity(String.class));
90                                 if (errorMessage.isPresent()) {
91                                         throw new BulkProcessFailed("One or more transactions failed in A&AI. Check logs for payloads.\nMessages:\n" + errorMessage.get());
92                                 }
93                         } else {
94                                 throw new BulkProcessFailed("Transactions acccepted by A&AI, but there was no response. Unsure of result.");
95                         }
96                 } finally {
97                         this.transactions.getTransactions().clear();
98                         this.currentTransaction = null;
99                         this.actionCount = 0;
100                 }
101         }
102         
103         protected Optional<String> locateErrorMessages(String response) {
104                 final List<String> errorMessages = new ArrayList<>();
105                 final List<String> results = JsonPathUtil.getInstance().locateResultList(response, "$..body");
106                 final ObjectMapper mapper = new ObjectMapper();
107                 if (!results.isEmpty()) {
108                         List<Map<String, Object>> parsed = new ArrayList<>();
109                         try {
110                                 for (String result : results) {
111                                         parsed.add(mapper.readValue(result, new TypeReference<Map<String, Object>>(){}));
112                                 }
113                         } catch (IOException e) {
114                                 logger.error("could not map json", e);
115                         }
116                         for (Map<String, Object> map : parsed) {
117                                 for (Entry<String, Object> entry : map.entrySet()) {
118                                         if (!entry.getKey().matches("2\\d\\d")) {
119                                                 AAIError error;
120                                                 try {
121                                                         error = mapper.readValue(entry.getValue().toString(), AAIError.class);
122                                                 } catch (IOException e) {
123                                                         logger.error("could not parse error object from A&AI", e);
124                                                         error = new AAIError();
125                                                 }
126                                                 AAIErrorFormatter formatter = new AAIErrorFormatter(error);
127                                                 String outputMessage = formatter.getMessage();
128                                                 logger.error("part of a bulk action failed in A&AI: " + entry.getValue());
129                                                 errorMessages.add(outputMessage);
130                                         }
131                                 }
132                         }
133                 }
134                 
135                 if (!errorMessages.isEmpty()) {
136                         return Optional.of(Joiner.on("\n").join(errorMessages));
137                 } else {
138                         return Optional.empty();
139                 }
140         }
141         private Relationship buildRelationship(AAIResourceUri uri) {
142                 return buildRelationship(uri, Optional.empty());
143         }
144         
145         private Relationship buildRelationship(AAIResourceUri uri, AAIEdgeLabel label) {
146                 return buildRelationship(uri, Optional.of(label));
147         }
148         private Relationship buildRelationship(AAIResourceUri uri, Optional<AAIEdgeLabel> label) {
149                 final Relationship result = new Relationship();
150                 result.setRelatedLink(uri.build().toString());
151                 if (label.isPresent()) {
152                         result.setRelationshipLabel(label.toString());
153                 }
154                 return result;
155         }
156         
157         protected Transactions getTransactions() {
158                 return this.transactions;
159         }
160
161         @Override
162         public void put(String uri, Object body) {
163                 currentTransaction.getPut().add(new OperationBody().withUri(uri).withBody(body));
164         }
165
166         @Override
167         public void delete(String uri, Object body) {
168                 currentTransaction.getDelete().add(new OperationBody().withUri(uri).withBody(body));
169                 
170         }
171
172         @Override
173         public void patch(String uri, Object body) {
174                 currentTransaction.getPatch().add(new OperationBody().withUri(uri).withBody(body));
175         }
176
177         @Override
178         protected <T> Optional<T> get(GenericType<T> genericType, AAIResourceUri clone) {
179                 return resourcesClient.get(genericType, clone);
180         }
181         
182         @Override
183         protected boolean exists(AAIResourceUri uri) {
184                 return resourcesClient.exists(uri);
185         }
186
187         @Override
188         protected String getGraphDBName() {
189                 return aaiClient.getGraphDBName();
190         }
191         
192         @Override
193         protected GraphInventoryPatchConverter getPatchConverter() {
194                 return this.patchConverter;
195         }
196 }