Merge "use encrypted auth for dmaap"
[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.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Map.Entry;
29 import java.util.Optional;
30
31 import javax.ws.rs.NotFoundException;
32 import javax.ws.rs.core.GenericType;
33 import javax.ws.rs.core.Response;
34
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;
48
49 import com.fasterxml.jackson.core.type.TypeReference;
50 import com.fasterxml.jackson.databind.ObjectMapper;
51 import com.google.common.base.Joiner;
52
53 public class AAITransactionalClient extends AAIClient implements GraphInventoryTransactionalClient<AAITransactionalClient, AAIResourceUri, AAIEdgeLabel> {
54
55         private final Transactions transactions;
56         private Transaction currentTransaction;
57         private final AAIVersion version;
58         private int actionCount = 0;
59         
60         private final GraphInventoryPatchConverter patchConverter = new GraphInventoryPatchConverter();
61         
62         protected AAITransactionalClient(AAIVersion version) {
63                 super();
64                 this.version = version;
65                 this.transactions = new Transactions();
66                 startTransaction();
67         }
68         
69         private void startTransaction() {
70                 Transaction transaction = new Transaction();
71                 transactions.getTransactions().add(transaction);
72                 currentTransaction = transaction;
73         }
74         
75         /* (non-Javadoc)
76          * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#beginNewTransaction()
77          */
78         @Override
79         public AAITransactionalClient beginNewTransaction() {
80                 startTransaction();
81                 return this;
82         }
83         
84         /* (non-Javadoc)
85          * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#create(org.onap.so.client.aai.entities.uri.AAIResourceUri, java.lang.Object)
86          */
87         @Override
88         public AAITransactionalClient create(AAIResourceUri uri, Object obj) {
89                 currentTransaction.getPut().add(new OperationBody().withUri(uri.build().toString()).withBody(obj));
90                 incrementActionAmount();
91                 return this;
92         }
93         
94         /* (non-Javadoc)
95          * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#createEmpty(org.onap.so.client.aai.entities.uri.AAIResourceUri)
96          */
97         @Override
98         public AAITransactionalClient createEmpty(AAIResourceUri uri) {
99                 currentTransaction.getPut().add(new OperationBody().withUri(uri.build().toString()).withBody(new HashMap<String, String>()));
100                 incrementActionAmount();
101                 return this;
102         }
103         
104         /* (non-Javadoc)
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)
106          */
107         @Override
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();
112                 return this;
113         }
114         
115         /* (non-Javadoc)
116          * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#connect(org.onap.so.client.aai.entities.uri.AAIResourceUri, java.util.List)
117          */
118         @Override
119         public AAITransactionalClient connect(AAIResourceUri uriA, List<AAIResourceUri> uris) {
120                 for (AAIResourceUri uri : uris) {
121                         this.connect(uriA, uri);
122                 }
123                 return this;
124         }
125         
126         /* (non-Javadoc)
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)
128          */
129         @Override
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));
134                 return this;
135         }
136         
137         /* (non-Javadoc)
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)
139          */
140         @Override
141         public AAITransactionalClient connect(AAIResourceUri uriA, List<AAIResourceUri> uris, AAIEdgeLabel label) {
142                 for (AAIResourceUri uri : uris) {
143                         this.connect(uriA, uri, label);
144                 }
145                 return this;
146         }
147         
148         /* (non-Javadoc)
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)
150          */
151         @Override
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();
156                 return this;
157         }
158         
159         /* (non-Javadoc)
160          * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#disconnect(org.onap.so.client.aai.entities.uri.AAIResourceUri, java.util.List)
161          */
162         @Override
163         public AAITransactionalClient disconnect(AAIResourceUri uriA, List<AAIResourceUri> uris) {
164                 for (AAIResourceUri uri : uris) {
165                         this.disconnect(uriA, uri);
166                 }
167                 return this;
168         }
169         /* (non-Javadoc)
170          * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#delete(org.onap.so.client.aai.entities.uri.AAIResourceUri)
171          */
172         @Override
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();
181                 return this;
182         }
183         
184         /* (non-Javadoc)
185          * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#update(org.onap.so.client.aai.entities.uri.AAIResourceUri, java.lang.Object)
186          */
187         @Override
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();
192                 return this;
193         }
194         
195         private void incrementActionAmount() {
196                 actionCount++;
197         }
198         /* (non-Javadoc)
199          * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#execute()
200          */
201         @Override
202         public void execute() throws BulkProcessFailed {
203                 RestClient client = this.createClient(AAIUriFactory.createResourceUri(AAIObjectType.BULK_PROCESS));
204                 try {
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());
210                                 }
211                         } else {
212                                 throw new BulkProcessFailed("Transactions acccepted by A&AI, but there was no response. Unsure of result.");
213                         }
214                 } finally {
215                         this.transactions.getTransactions().clear();
216                         this.currentTransaction = null;
217                         this.actionCount = 0;
218                 }
219         }
220         
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<>();
227                         try {
228                                 for (String result : results) {
229                                         parsed.add(mapper.readValue(result, new TypeReference<Map<String, Object>>(){}));
230                                 }
231                         } catch (IOException e) {
232                                 logger.error("could not map json", e);
233                         }
234                         for (Map<String, Object> map : parsed) {
235                                 for (Entry<String, Object> entry : map.entrySet()) {
236                                         if (!entry.getKey().matches("2\\d\\d")) {
237                                                 AAIError error;
238                                                 try {
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();
243                                                 }
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);
248                                         }
249                                 }
250                         }
251                 }
252                 
253                 if (!errorMessages.isEmpty()) {
254                         return Optional.of(Joiner.on("\n").join(errorMessages));
255                 } else {
256                         return Optional.empty();
257                 }
258         }
259         private Relationship buildRelationship(AAIResourceUri uri) {
260                 return buildRelationship(uri, Optional.empty());
261         }
262         
263         private Relationship buildRelationship(AAIResourceUri uri, AAIEdgeLabel label) {
264                 return buildRelationship(uri, Optional.of(label));
265         }
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());
271                 }
272                 return result;
273         }
274
275         @Override
276         protected AAIVersion getVersion() {
277                 return this.version;
278         }
279         
280         protected Transactions getTransactions() {
281                 return this.transactions;
282         }
283         
284         protected GraphInventoryPatchConverter getPatchConverter() {
285                 return this.patchConverter;
286         }
287 }