Merge "Add junit tests for AdapterRestClient"
[so.git] / common / src / main / java / org / onap / so / client / aai / AAISingleTransactionClient.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 - 2018 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
34 import org.onap.aai.domain.yang.Relationship;
35 import org.onap.so.client.RestClient;
36 import org.onap.so.client.aai.entities.AAIEdgeLabel;
37 import org.onap.so.client.aai.entities.AAIError;
38 import org.onap.so.client.aai.entities.bulkprocess.Transactions;
39 import org.onap.so.client.aai.entities.singletransaction.OperationBodyRequest;
40 import org.onap.so.client.aai.entities.singletransaction.OperationBodyResponse;
41 import org.onap.so.client.aai.entities.singletransaction.SingleTransactionRequest;
42 import org.onap.so.client.aai.entities.singletransaction.SingleTransactionResponse;
43 import org.onap.so.client.aai.entities.uri.AAIResourceUri;
44 import org.onap.so.client.aai.entities.uri.AAIUri;
45 import org.onap.so.client.aai.entities.uri.AAIUriFactory;
46 import org.onap.so.client.graphinventory.GraphInventoryPatchConverter;
47 import org.onap.so.client.graphinventory.GraphInventorySingleTransactionClient;
48 import org.onap.so.client.graphinventory.exceptions.BulkProcessFailed;
49
50 import com.fasterxml.jackson.core.type.TypeReference;
51 import com.fasterxml.jackson.databind.ObjectMapper;
52 import com.google.common.base.Joiner;
53
54 public class AAISingleTransactionClient extends AAIClient implements GraphInventorySingleTransactionClient<AAISingleTransactionClient, AAIResourceUri, AAIEdgeLabel> {
55
56         private final SingleTransactionRequest request;
57         private final AAIVersion version;
58         private int actionCount = 0;
59         
60         private final GraphInventoryPatchConverter patchConverter = new GraphInventoryPatchConverter();
61         
62         protected AAISingleTransactionClient(AAIVersion version) {
63                 super();
64                 this.version = version;
65                 this.request = new SingleTransactionRequest();
66         }
67
68         /* (non-Javadoc)
69          * @see org.onap.so.client.aai.GraphInventoryTransactionClient#create(org.onap.so.client.aai.entities.uri.AAIResourceUri, java.lang.Object)
70          */
71         @Override
72         public AAISingleTransactionClient create(AAIResourceUri uri, Object obj) {
73                 request.getOperations().add(new OperationBodyRequest().withAction("put").withUri(uri.build().toString()).withBody(obj));
74                 incrementActionAmount();
75                 return this;
76         }
77
78         /* (non-Javadoc)
79          * @see org.onap.so.client.aai.GraphInventoryTransactionClient#createEmpty(org.onap.so.client.aai.entities.uri.AAIResourceUri)
80          */
81         @Override
82         public AAISingleTransactionClient createEmpty(AAIResourceUri uri) {
83                 request.getOperations().add(new OperationBodyRequest().withAction("put").withUri(uri.build().toString()).withBody(new HashMap<String, String>()));
84                 incrementActionAmount();
85                 return this;
86         }
87
88         /* (non-Javadoc)
89          * @see org.onap.so.client.aai.GraphInventoryTransactionClient#connect(org.onap.so.client.aai.entities.uri.AAIResourceUri, org.onap.so.client.aai.entities.uri.AAIResourceUri)
90          */
91         @Override
92         public AAISingleTransactionClient connect(AAIResourceUri uriA, AAIResourceUri uriB) {
93                 AAIResourceUri uriAClone = uriA.clone();
94                 request.getOperations().add(new OperationBodyRequest().withAction("put").withUri(uriAClone.relationshipAPI().build().toString()).withBody(this.buildRelationship(uriB)));
95                 incrementActionAmount();
96                 return this;
97         }
98
99         /* (non-Javadoc)
100          * @see org.onap.so.client.aai.GraphInventoryTransactionClient#connect(org.onap.so.client.aai.entities.uri.AAIResourceUri, java.util.List)
101          */
102         @Override
103         public AAISingleTransactionClient connect(AAIResourceUri uriA, List<AAIResourceUri> uris) {
104                 for (AAIResourceUri uri : uris) {
105                         this.connect(uriA, uri);
106                 }
107                 return this;
108         }
109         
110         /* (non-Javadoc)
111          * @see org.onap.so.client.aai.GraphInventoryTransactionClient#connect(org.onap.so.client.aai.entities.uri.AAIResourceUri, org.onap.so.client.aai.entities.uri.AAIResourceUri, org.onap.so.client.aai.entities.AAIEdgeLabel)
112          */
113         @Override
114         public AAISingleTransactionClient connect(AAIResourceUri uriA, AAIResourceUri uriB, AAIEdgeLabel label) {
115                 AAIResourceUri uriAClone = uriA.clone();
116                 RestClient aaiRC = this.createClient(uriAClone.relationshipAPI());
117                 aaiRC.put(this.buildRelationship(uriB, label));
118                 return this;
119         }
120         
121         /* (non-Javadoc)
122          * @see org.onap.so.client.aai.GraphInventoryTransactionClient#connect(org.onap.so.client.aai.entities.uri.AAIResourceUri, java.util.List, org.onap.so.client.aai.entities.AAIEdgeLabel)
123          */
124         @Override
125         public AAISingleTransactionClient connect(AAIResourceUri uriA, List<AAIResourceUri> uris, AAIEdgeLabel label) {
126                 for (AAIResourceUri uri : uris) {
127                         this.connect(uriA, uri, label);
128                 }
129                 return this;
130         }
131
132         /* (non-Javadoc)
133          * @see org.onap.so.client.aai.GraphInventoryTransactionClient#disconnect(org.onap.so.client.aai.entities.uri.AAIResourceUri, org.onap.so.client.aai.entities.uri.AAIResourceUri)
134          */
135         @Override
136         public AAISingleTransactionClient disconnect(AAIResourceUri uriA, AAIResourceUri uriB) {
137                 AAIResourceUri uriAClone = uriA.clone();
138                 request.getOperations().add(new OperationBodyRequest().withAction("delete").withUri(uriAClone.relationshipAPI().build().toString()).withBody(this.buildRelationship(uriB)));
139                 incrementActionAmount();
140                 return this;
141         }
142
143         /* (non-Javadoc)
144          * @see org.onap.so.client.aai.GraphInventoryTransactionClient#disconnect(org.onap.so.client.aai.entities.uri.AAIResourceUri, java.util.List)
145          */
146         @Override
147         public AAISingleTransactionClient disconnect(AAIResourceUri uriA, List<AAIResourceUri> uris) {
148                 for (AAIResourceUri uri : uris) {
149                         this.disconnect(uriA, uri);
150                 }
151                 return this;
152         }
153         /* (non-Javadoc)
154          * @see org.onap.so.client.aai.GraphInventoryTransactionClient#delete(org.onap.so.client.aai.entities.uri.AAIResourceUri)
155          */
156         @Override
157         public AAISingleTransactionClient delete(AAIResourceUri uri) {
158                 AAIResourcesClient client = new AAIResourcesClient();
159                 AAIResourceUri clone = uri.clone();
160                 Map<String, Object> result = client.get(new GenericType<Map<String, Object>>(){}, clone)
161                                 .orElseThrow(() -> new NotFoundException(clone.build() + " does not exist in A&AI"));
162                 String resourceVersion = (String) result.get("resource-version");
163                 request.getOperations().add(new OperationBodyRequest().withAction("delete").withUri(clone.resourceVersion(resourceVersion).build().toString()).withBody(""));
164                 incrementActionAmount();
165                 return this;
166         }
167
168         /* (non-Javadoc)
169          * @see org.onap.so.client.aai.GraphInventoryTransactionClient#update(org.onap.so.client.aai.entities.uri.AAIResourceUri, java.lang.Object)
170          */
171         @Override
172         public AAISingleTransactionClient update(AAIResourceUri uri, Object obj) {
173                 
174                 final String payload = getPatchConverter().convertPatchFormat(obj);
175                 request.getOperations().add(new OperationBodyRequest().withAction("patch").withUri(uri.build().toString()).withBody(payload));
176                 incrementActionAmount();
177                 return this;
178         }
179
180         private void incrementActionAmount() {
181                 actionCount++;
182         }
183         /* (non-Javadoc)
184          * @see org.onap.so.client.aai.GraphInventoryTransactionClient#execute()
185          */
186         @Override
187         public void execute() throws BulkProcessFailed {
188                 RestClient client = this.createClient(AAIUriFactory.createResourceUri(AAIObjectType.SINGLE_TRANSACTION));
189                 try {
190                         SingleTransactionResponse response = client.post(this.request, SingleTransactionResponse.class);
191                         if (response != null) {
192                                 final Optional<String> errorMessage = this.locateErrorMessages(response);
193                                 if (errorMessage.isPresent()) {
194                                         throw new BulkProcessFailed("One or more transactions failed in A&AI. Check logs for payloads.\nMessages:\n" + errorMessage.get());
195                                 }
196                         } else {
197                                 throw new BulkProcessFailed("Transactions acccepted by A&AI, but there was no response. Unsure of result.");
198                         }
199                 } finally {
200                         this.request.getOperations().clear();
201                         this.actionCount = 0;
202                 }
203         }
204
205         protected Optional<String> locateErrorMessages(SingleTransactionResponse response) {
206                 final List<String> errorMessages = new ArrayList<>();
207                 final ObjectMapper mapper = new ObjectMapper();
208                 
209                 for (OperationBodyResponse body : response.getOperationResponses()) {
210                         if (Optional.ofNullable(body.getResponseStatusCode()).orElse(400) > 300) {
211                                 AAIError error;
212                                 try {
213                                         error = mapper.readValue(mapper.writeValueAsString(body.getResponseBody()), AAIError.class);
214                                 } catch (IOException e) {
215                                         logger.error("could not parse error object from A&AI", e);
216                                         error = new AAIError();
217                                 }
218                                 AAIErrorFormatter formatter = new AAIErrorFormatter(error);
219                                 String outputMessage = formatter.getMessage();
220                                 errorMessages.add(outputMessage);
221                         }
222                 }
223                 
224                 if (!errorMessages.isEmpty()) {
225                         return Optional.of(Joiner.on("\n").join(errorMessages));
226                 } else {
227                         return Optional.empty();
228                 }
229         }
230         
231         private Relationship buildRelationship(AAIResourceUri uri) {
232                 return buildRelationship(uri, Optional.empty());
233         }
234         
235         private Relationship buildRelationship(AAIResourceUri uri, AAIEdgeLabel label) {
236                 return buildRelationship(uri, Optional.of(label));
237         }
238         private Relationship buildRelationship(AAIResourceUri uri, Optional<AAIEdgeLabel> label) {
239                 final Relationship result = new Relationship();
240                 result.setRelatedLink(uri.build().toString());
241                 if (label.isPresent()) {
242                         result.setRelationshipLabel(label.toString());
243                 }
244                 return result;
245         }
246
247         @Override
248         protected AAIVersion getVersion() {
249                 return this.version;
250         }
251         
252         protected SingleTransactionRequest getRequest() {
253                 return this.request;
254         }
255         
256         protected GraphInventoryPatchConverter getPatchConverter() {
257                 return this.patchConverter;
258         }
259 }