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