343e888ce18d61fff787c147987d4bcff3c3d2b9
[so.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 - 2019 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.aaiclient.client.graphinventory;
22
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.lang.reflect.ParameterizedType;
26 import java.lang.reflect.Type;
27 import java.util.Arrays;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Optional;
31 import javax.ws.rs.NotFoundException;
32 import javax.ws.rs.core.GenericType;
33 import javax.ws.rs.core.Response;
34 import javax.ws.rs.core.Response.Status;
35 import org.onap.aai.domain.yang.Relationship;
36 import org.onap.aaiclient.client.graphinventory.entities.GraphInventoryEdgeLabel;
37 import org.onap.aaiclient.client.graphinventory.entities.GraphInventoryResultWrapper;
38 import org.onap.aaiclient.client.graphinventory.entities.uri.GraphInventoryPluralResourceUri;
39 import org.onap.aaiclient.client.graphinventory.entities.uri.GraphInventoryResourceUri;
40 import org.onap.aaiclient.client.graphinventory.entities.uri.GraphInventorySingleResourceUri;
41 import org.onap.aaiclient.client.graphinventory.entities.uri.HttpAwareUri;
42 import org.onap.aaiclient.client.graphinventory.exceptions.GraphInventoryMultipleItemsException;
43 import org.onap.so.client.RestClient;
44 import org.onap.so.client.RestProperties;
45
46 public abstract class GraphInventoryResourcesClient<Self, Uri extends GraphInventoryResourceUri<?, ?>, SingleUri extends GraphInventorySingleResourceUri<?, ?, ?, ?, ?, ?>, PluralUri extends GraphInventoryPluralResourceUri<?, ?>, EdgeLabel extends GraphInventoryEdgeLabel, Wrapper extends GraphInventoryResultWrapper, TransactionalClient, SingleTransactionClient> {
47
48     protected GraphInventoryClient client;
49
50     protected GraphInventoryResourcesClient(GraphInventoryClient client) {
51         this.client = client;
52     }
53
54     /**
55      * creates a new object in GraphInventory
56      * 
57      * @param obj - can be any object which will marshal into a valid GraphInventory payload
58      * @param uri
59      * @return
60      */
61     public void create(SingleUri uri, Object obj) {
62         RestClient giRC = client.createClient(uri);
63         giRC.put(obj);
64     }
65
66     /**
67      * creates a new object in GraphInventory with no payload body
68      * 
69      * @param uri
70      * @return
71      */
72     public void createEmpty(SingleUri uri) {
73         RestClient giRC = client.createClient(uri);
74         giRC.put("");
75     }
76
77     /**
78      * returns false if the object does not exist in GraphInventory
79      * 
80      * @param uri
81      * @return
82      */
83     public boolean exists(Uri uri) {
84         GraphInventoryResourceUri<?, ?> forceMinimal = (Uri) uri.clone();
85         forceMinimal.format(Format.COUNT);
86         forceMinimal.limit(1);
87         try {
88             RestClient giRC = client.createClient(forceMinimal);
89
90             return giRC.get().getStatus() == Status.OK.getStatusCode();
91         } catch (NotFoundException e) {
92             return false;
93         }
94     }
95
96     /**
97      * Adds a relationship between two objects in GraphInventory
98      * 
99      * @param uriA
100      * @param uriB
101      * @return
102      */
103     public void connect(SingleUri uriA, SingleUri uriB) {
104         GraphInventorySingleResourceUri<?, ?, ?, ?, ?, ?> uriAClone = (SingleUri) uriA.clone();
105         RestClient giRC = client.createClient(uriAClone.relationshipAPI());
106         giRC.put(this.buildRelationship(uriB));
107     }
108
109     /**
110      * Adds a relationship between two objects in GraphInventory with a given edge label
111      * 
112      * @param uriA
113      * @param uriB
114      * @param edge label
115      * @return
116      */
117     public void connect(SingleUri uriA, SingleUri uriB, EdgeLabel label) {
118         GraphInventorySingleResourceUri<?, ?, ?, ?, ?, ?> uriAClone = (SingleUri) uriA.clone();
119         RestClient giRC = client.createClient(uriAClone.relationshipAPI());
120         giRC.put(this.buildRelationship(uriB, label));
121     }
122
123     /**
124      * Removes relationship from two objects in GraphInventory
125      * 
126      * @param uriA
127      * @param uriB
128      * @return
129      */
130     public void disconnect(SingleUri uriA, SingleUri uriB) {
131         GraphInventorySingleResourceUri<?, ?, ?, ?, ?, ?> uriAClone = (SingleUri) uriA.clone();
132         RestClient giRC = client.createClient(uriAClone.relationshipAPI());
133         giRC.delete(this.buildRelationship(uriB));
134     }
135
136     /**
137      * Deletes object from GraphInventory. Automatically handles resource-version.
138      * 
139      * @param uri
140      * @return
141      */
142     public void delete(SingleUri uri) {
143         GraphInventorySingleResourceUri<?, ?, ?, ?, ?, ?> clone = (SingleUri) uri.clone();
144         RestClient giRC = client.createClient(clone);
145         Map<String, Object> result = giRC.get(new GenericType<Map<String, Object>>() {}).orElseThrow(
146                 () -> new NotFoundException(clone.build() + " does not exist in " + client.getGraphDBName()));
147         String resourceVersion = (String) result.get("resource-version");
148         giRC = client.createClient(clone.resourceVersion(resourceVersion));
149         giRC.delete();
150     }
151
152     /**
153      * @param obj - can be any object which will marshal into a valid GraphInventory payload
154      * @param uri
155      * @return
156      */
157     public void update(SingleUri uri, Object obj) {
158         RestClient giRC = client.createClient(uri);
159         giRC.patch(obj);
160     }
161
162     /**
163      * Retrieves an object from GraphInventory and unmarshalls it into the Class specified
164      * 
165      * @param clazz
166      * @param uri
167      * @return
168      */
169     public <T> Optional<T> get(Class<T> clazz, Uri uri) {
170         try {
171             return client.createClient(uri).get(clazz);
172         } catch (NotFoundException e) {
173             if (this.getRestProperties().mapNotFoundToEmpty()) {
174                 return Optional.empty();
175             } else {
176                 throw e;
177             }
178         }
179     }
180
181     /**
182      * Retrieves an object from GraphInventory and returns complete response
183      * 
184      * @param uri
185      * @return
186      */
187     public Response getFullResponse(Uri uri) {
188         try {
189             return client.createClient(uri).get();
190         } catch (NotFoundException e) {
191             if (this.getRestProperties().mapNotFoundToEmpty()) {
192                 return e.getResponse();
193             } else {
194                 throw e;
195             }
196         }
197     }
198
199     /**
200      * Retrieves an object from GraphInventory and automatically unmarshalls it into a Map or List
201      * 
202      * @param resultClass
203      * @param uri
204      * @return
205      */
206     public <T> Optional<T> get(GenericType<T> resultClass, Uri uri) {
207         try {
208             return client.createClient(uri).get(resultClass);
209         } catch (NotFoundException e) {
210             if (this.getRestProperties().mapNotFoundToEmpty()) {
211                 return Optional.empty();
212             } else {
213                 throw e;
214             }
215         }
216     }
217
218     public <T, R> Optional<R> getOne(Class<T> pluralClass, Class<R> resultClass, PluralUri uri) {
219         Optional<List<R>> result = unwrapPlural(pluralClass, resultClass, uri);
220
221         if (result.isPresent()) {
222             if (result.get().size() == 1) {
223                 return Optional.of(result.get().get(0));
224             } else {
225                 throw new GraphInventoryMultipleItemsException(result.get().size(), uri);
226             }
227         }
228
229         return Optional.empty();
230     }
231
232     public <T, R> Optional<R> getFirst(Class<T> pluralClass, Class<R> resultClass, PluralUri uri) {
233         Optional<List<R>> result = unwrapPlural(pluralClass, resultClass, uri);
234
235         if (result.isPresent() && !result.get().isEmpty()) {
236             return Optional.of(result.get().get(0));
237         }
238
239         return Optional.empty();
240     }
241
242     public <T, R> Optional<Wrapper> getFirstWrapper(Class<T> pluralClass, Class<R> resultClass, PluralUri uri) {
243
244         Optional<R> result = getFirst(pluralClass, resultClass, uri);
245         if (result.isPresent()) {
246             return Optional.of(this.createWrapper(result.get()));
247         } else {
248             return Optional.empty();
249         }
250     }
251
252     public <T, R> Optional<Wrapper> getOneWrapper(Class<T> pluralClass, Class<R> resultClass, PluralUri uri) {
253
254         Optional<R> result = getOne(pluralClass, resultClass, uri);
255         if (result.isPresent()) {
256             return Optional.of(this.createWrapper(result.get()));
257         } else {
258             return Optional.empty();
259         }
260     }
261
262     protected <T, R> Optional<List<R>> unwrapPlural(Class<T> pluralClass, Class<R> resultClass, PluralUri uri) {
263         try {
264             PluralUri clone = (PluralUri) uri.clone().limit(1);
265             Optional<T> obj = client.createClient(clone).get(pluralClass);
266             if (obj.isPresent()) {
267                 Optional<Method> listMethod = Arrays.stream(obj.get().getClass().getMethods()).filter(method -> {
268
269                     Type returnType = method.getGenericReturnType();
270                     if (returnType instanceof ParameterizedType) {
271                         Type[] types = ((ParameterizedType) returnType).getActualTypeArguments();
272                         if (types != null && types[0] instanceof Class) {
273                             Class<?> listClass = (Class<?>) types[0];
274                             return resultClass.equals(listClass);
275                         }
276                     }
277
278                     return false;
279                 }).findFirst();
280                 if (listMethod.isPresent()) {
281                     try {
282                         return Optional.of((List<R>) listMethod.get().invoke(obj.get()));
283
284                     } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
285                         throw new RuntimeException(e);
286                     }
287                 }
288             }
289             return Optional.empty();
290
291         } catch (NotFoundException e) {
292             if (this.getRestProperties().mapNotFoundToEmpty()) {
293                 return Optional.empty();
294             } else {
295                 throw e;
296             }
297         }
298     }
299
300     /**
301      * Retrieves an object from GraphInventory wrapped in a helper class which offer additional features
302      * 
303      * @param uri
304      * @return
305      */
306     public Wrapper get(Uri uri) {
307         String json;
308         try {
309             json = client.createClient(uri).get(String.class).orElse(null);
310         } catch (NotFoundException e) {
311             if (this.getRestProperties().mapNotFoundToEmpty()) {
312                 json = null;
313             } else {
314                 throw e;
315             }
316         }
317         return this.createWrapper(json);
318     }
319
320     /**
321      * Retrieves an object from GraphInventory wrapped in a helper class which offer additional features If the object
322      * cannot be found in GraphInventory the method will throw the runtime exception included as an argument
323      * 
324      * @param uri
325      * @return
326      */
327     public Wrapper get(Uri uri, Class<? extends RuntimeException> c) {
328         String json;
329         try {
330             json = client.createClient(uri).get(String.class).orElseThrow(() -> createException(c,
331                     uri.build() + " not found in " + client.getGraphDBName(), Optional.empty()));
332         } catch (NotFoundException e) {
333             throw createException(c, "could not construct uri for use with " + client.getGraphDBName(), Optional.of(e));
334         }
335
336         return this.createWrapper(json);
337     }
338
339     private RuntimeException createException(Class<? extends RuntimeException> c, String message,
340             Optional<Throwable> t) {
341         RuntimeException e;
342         try {
343             if (t.isPresent()) {
344                 e = c.getConstructor(String.class, Throwable.class).newInstance(message, t.get());
345             } else {
346                 e = c.getConstructor(String.class).newInstance(message);
347             }
348         } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
349                 | NoSuchMethodException | SecurityException e1) {
350             throw new IllegalArgumentException("could not create instance for " + c.getName());
351         }
352
353         return e;
354     }
355
356     /**
357      * Will automatically create the object if it does not exist
358      * 
359      * @param obj - Optional object which serializes to a valid GraphInventory payload
360      * @param uri
361      * @return
362      */
363     public Self createIfNotExists(SingleUri uri, Optional<Object> obj) {
364         if (!this.exists((Uri) uri)) {
365             if (obj.isPresent()) {
366                 this.create(uri, obj.get());
367             } else {
368                 this.createEmpty(uri);
369             }
370
371         }
372         return (Self) this;
373     }
374
375     protected Relationship buildRelationship(SingleUri uri) {
376         return buildRelationship(uri, Optional.empty());
377     }
378
379     protected Relationship buildRelationship(SingleUri uri, GraphInventoryEdgeLabel label) {
380         return buildRelationship(uri, Optional.of(label));
381     }
382
383     protected Relationship buildRelationship(SingleUri uri, Optional<GraphInventoryEdgeLabel> label) {
384         final Relationship result = new Relationship();
385         if (uri instanceof HttpAwareUri) {
386             result.setRelatedLink(((HttpAwareUri) uri).locateAndBuild().toString());
387         } else {
388             result.setRelatedLink(uri.build().toString());
389         }
390         if (label.isPresent()) {
391             result.setRelationshipLabel(label.get().toString());
392         }
393         return result;
394     }
395
396     public abstract Wrapper createWrapper(String json);
397
398     public abstract Wrapper createWrapper(Object json);
399
400     /**
401      * Starts a transaction which encloses multiple GraphInventory mutations
402      * 
403      * @return
404      */
405     public abstract TransactionalClient beginTransaction();
406
407     /**
408      * Starts a transaction groups multiple GraphInventory mutations
409      * 
410      * @return
411      */
412     public abstract SingleTransactionClient beginSingleTransaction();
413
414     public <T extends RestProperties> T getRestProperties() {
415         return client.getRestProperties();
416     }
417
418 }