Fight against the encoding in openstack
[so.git] / graph-inventory / aai-client / 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 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;
49
50 public class AAITransactionalClient extends
51         GraphInventoryTransactionClient<AAITransactionalClient, AAIBaseResourceUri<?, ?>, AAIResourceUri, AAIEdgeLabel> {
52
53     private final Transactions transactions;
54     private Transaction currentTransaction;
55
56     private AAIResourcesClient resourcesClient;
57     private AAIClient aaiClient;
58
59     protected AAITransactionalClient(AAIResourcesClient resourcesClient, AAIClient aaiClient) {
60         super();
61         this.resourcesClient = resourcesClient;
62         this.aaiClient = aaiClient;
63         this.transactions = new Transactions();
64         startTransaction();
65     }
66
67     private void startTransaction() {
68         Transaction transaction = new Transaction();
69         transactions.getTransactions().add(transaction);
70         currentTransaction = transaction;
71     }
72
73     /*
74      * (non-Javadoc)
75      * 
76      * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#beginNewTransaction()
77      */
78     public AAITransactionalClient beginNewTransaction() {
79         startTransaction();
80         return this;
81     }
82
83     /*
84      * (non-Javadoc)
85      * 
86      * @see org.onap.so.client.aai.GraphInventoryTransactionalClient#execute()
87      */
88     @Override
89     public void execute() throws BulkProcessFailed {
90         try {
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());
100                     }
101                 } else {
102                     throw new BulkProcessFailed(
103                             "Transactions acccepted by A&AI, but there was no response. Unsure of result.");
104                 }
105             }
106         } finally {
107             this.transactions.getTransactions().clear();
108             this.currentTransaction = null;
109             this.actionCount = 0;
110         }
111     }
112
113     @Override
114     public void execute(boolean dryRun) throws BulkProcessFailed {
115         final ObjectMapper mapper = new ObjectMapper();
116         if (dryRun) {
117             try {
118                 if (logger.isDebugEnabled()) {
119                     logger.debug("Would execute: {}", mapper.writeValueAsString(this.transactions));
120                 }
121             } catch (JsonProcessingException e) {
122                 logger.debug("Could not format request to JSON", e);
123             }
124         } else {
125             this.execute();
126         }
127     }
128
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<>();
135             try {
136                 for (String result : results) {
137                     parsed.add(mapper.readValue(result, new TypeReference<Map<String, Object>>() {}));
138                 }
139             } catch (IOException e) {
140                 logger.error("could not map json", e);
141             }
142             for (Map<String, Object> map : parsed) {
143                 for (Entry<String, Object> entry : map.entrySet()) {
144                     if (!entry.getKey().matches("2\\d\\d")) {
145                         AAIError error;
146                         try {
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();
151                         }
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);
156                     }
157                 }
158             }
159         }
160
161         if (!errorMessages.isEmpty()) {
162             return Optional.of(Joiner.on("\n").join(errorMessages));
163         } else {
164             return Optional.empty();
165         }
166     }
167
168     private Relationship buildRelationship(AAIResourceUri uri) {
169         return buildRelationship(uri, Optional.empty());
170     }
171
172     private Relationship buildRelationship(AAIResourceUri uri, AAIEdgeLabel label) {
173         return buildRelationship(uri, Optional.of(label));
174     }
175
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());
181         }
182         return result;
183     }
184
185     protected Transactions getTransactions() {
186         return this.transactions;
187     }
188
189     @Override
190     protected void put(String uri, Object body) {
191         currentTransaction.getPut().add(new OperationBody().withUri(uri).withBody(body));
192     }
193
194     @Override
195     protected void delete(String uri) {
196         currentTransaction.getDelete().add(new OperationBody().withUri(uri).withBody(null));
197     }
198
199     @Override
200     protected void delete(String uri, Object obj) {
201         currentTransaction.getDelete().add(new OperationBody().withUri(uri).withBody(obj));
202     }
203
204     @Override
205     protected void patch(String uri, Object body) {
206         currentTransaction.getPatch().add(new OperationBody().withUri(uri).withBody(body));
207     }
208
209     @Override
210     protected <T> Optional<T> get(GenericType<T> genericType, AAIBaseResourceUri<?, ?> clone) {
211         return resourcesClient.get(genericType, clone);
212     }
213
214     @Override
215     protected boolean exists(AAIBaseResourceUri<?, ?> uri) {
216         return resourcesClient.exists(uri);
217     }
218
219     @Override
220     protected String getGraphDBName() {
221         return aaiClient.getGraphDBName();
222     }
223
224     @Override
225     protected GraphInventoryPatchConverter getPatchConverter() {
226         return this.patchConverter;
227     }
228 }