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