2  * ============LICENSE_START=======================================================
 
   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
 
  11  *      http://www.apache.org/licenses/LICENSE-2.0
 
  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=========================================================
 
  21 package org.onap.aaiclient.client.graphinventory;
 
  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;
 
  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;
 
  46 public abstract class GraphInventoryResourcesClient<Self, Uri extends GraphInventoryResourceUri<?, ?>, SingleUri extends GraphInventorySingleResourceUri<?, ?, ?, ?, ?, ?>, PluralUri extends GraphInventoryPluralResourceUri<?, ?>, EdgeLabel extends GraphInventoryEdgeLabel, Wrapper extends GraphInventoryResultWrapper, TransactionalClient, SingleTransactionClient> {
 
  48     protected GraphInventoryClient client;
 
  50     protected GraphInventoryResourcesClient(GraphInventoryClient client) {
 
  55      * creates a new object in GraphInventory
 
  57      * @param obj - can be any object which will marshal into a valid GraphInventory payload
 
  61     public void create(SingleUri uri, Object obj) {
 
  62         RestClient giRC = client.createClient(uri);
 
  67      * creates a new object in GraphInventory with no payload body
 
  72     public void createEmpty(SingleUri uri) {
 
  73         RestClient giRC = client.createClient(uri);
 
  78      * returns false if the object does not exist in GraphInventory
 
  83     public boolean exists(Uri uri) {
 
  84         GraphInventoryResourceUri<?, ?> forceMinimal = (Uri) uri.clone();
 
  85         forceMinimal.format(Format.COUNT);
 
  86         forceMinimal.limit(1);
 
  88             RestClient giRC = client.createClient(forceMinimal);
 
  90             return giRC.get().getStatus() == Status.OK.getStatusCode();
 
  91         } catch (NotFoundException e) {
 
  97      * Adds a relationship between two objects in GraphInventory
 
 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));
 
 110      * Adds a relationship between two objects in GraphInventory with a given edge label
 
 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));
 
 124      * Removes relationship from two objects in GraphInventory
 
 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));
 
 137      * Deletes object from GraphInventory. Automatically handles resource-version.
 
 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));
 
 153      * @param obj - can be any object which will marshal into a valid GraphInventory payload
 
 157     public void update(SingleUri uri, Object obj) {
 
 158         RestClient giRC = client.createClient(uri);
 
 163      * Retrieves an object from GraphInventory and unmarshalls it into the Class specified
 
 169     public <T> Optional<T> get(Class<T> clazz, Uri uri) {
 
 171             return client.createClient(uri).get(clazz);
 
 172         } catch (NotFoundException e) {
 
 173             if (this.getRestProperties().mapNotFoundToEmpty()) {
 
 174                 return Optional.empty();
 
 182      * Retrieves an object from GraphInventory and returns complete response
 
 187     public Response getFullResponse(Uri uri) {
 
 189             return client.createClient(uri).get();
 
 190         } catch (NotFoundException e) {
 
 191             if (this.getRestProperties().mapNotFoundToEmpty()) {
 
 192                 return e.getResponse();
 
 200      * Retrieves an object from GraphInventory and automatically unmarshalls it into a Map or List
 
 206     public <T> Optional<T> get(GenericType<T> resultClass, Uri uri) {
 
 208             return client.createClient(uri).get(resultClass);
 
 209         } catch (NotFoundException e) {
 
 210             if (this.getRestProperties().mapNotFoundToEmpty()) {
 
 211                 return Optional.empty();
 
 218     public <T, R> Optional<R> getOne(Class<T> pluralClass, Class<R> resultClass, PluralUri uri) {
 
 219         Optional<List<R>> result = unwrapPlural(pluralClass, resultClass, uri);
 
 221         if (result.isPresent()) {
 
 222             if (result.get().size() == 1) {
 
 223                 return Optional.of(result.get().get(0));
 
 225                 throw new GraphInventoryMultipleItemsException(result.get().size(), uri);
 
 229         return Optional.empty();
 
 232     public <T, R> Optional<R> getFirst(Class<T> pluralClass, Class<R> resultClass, PluralUri uri) {
 
 233         Optional<List<R>> result = unwrapPlural(pluralClass, resultClass, uri);
 
 235         if (result.isPresent() && !result.get().isEmpty()) {
 
 236             return Optional.of(result.get().get(0));
 
 239         return Optional.empty();
 
 242     public <T, R> Optional<Wrapper> getFirstWrapper(Class<T> pluralClass, Class<R> resultClass, PluralUri uri) {
 
 244         Optional<R> result = getFirst(pluralClass, resultClass, uri);
 
 245         if (result.isPresent()) {
 
 246             return Optional.of(this.createWrapper(result.get()));
 
 248             return Optional.empty();
 
 252     public <T, R> Optional<Wrapper> getOneWrapper(Class<T> pluralClass, Class<R> resultClass, PluralUri uri) {
 
 254         Optional<R> result = getOne(pluralClass, resultClass, uri);
 
 255         if (result.isPresent()) {
 
 256             return Optional.of(this.createWrapper(result.get()));
 
 258             return Optional.empty();
 
 262     protected <T, R> Optional<List<R>> unwrapPlural(Class<T> pluralClass, Class<R> resultClass, PluralUri uri) {
 
 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 -> {
 
 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);
 
 280                 if (listMethod.isPresent()) {
 
 282                         return Optional.of((List<R>) listMethod.get().invoke(obj.get()));
 
 284                     } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
 
 285                         throw new RuntimeException(e);
 
 289             return Optional.empty();
 
 291         } catch (NotFoundException e) {
 
 292             if (this.getRestProperties().mapNotFoundToEmpty()) {
 
 293                 return Optional.empty();
 
 301      * Retrieves an object from GraphInventory wrapped in a helper class which offer additional features
 
 306     public Wrapper get(Uri uri) {
 
 309             json = client.createClient(uri).get(String.class).orElse(null);
 
 310         } catch (NotFoundException e) {
 
 311             if (this.getRestProperties().mapNotFoundToEmpty()) {
 
 317         return this.createWrapper(json);
 
 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
 
 327     public Wrapper get(Uri uri, Class<? extends RuntimeException> c) {
 
 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));
 
 336         return this.createWrapper(json);
 
 339     private RuntimeException createException(Class<? extends RuntimeException> c, String message,
 
 340             Optional<Throwable> t) {
 
 344                 e = c.getConstructor(String.class, Throwable.class).newInstance(message, t.get());
 
 346                 e = c.getConstructor(String.class).newInstance(message);
 
 348         } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
 
 349                 | NoSuchMethodException | SecurityException e1) {
 
 350             throw new IllegalArgumentException("could not create instance for " + c.getName());
 
 357      * Will automatically create the object if it does not exist
 
 359      * @param obj - Optional object which serializes to a valid GraphInventory payload
 
 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());
 
 368                 this.createEmpty(uri);
 
 375     protected Relationship buildRelationship(SingleUri uri) {
 
 376         return buildRelationship(uri, Optional.empty());
 
 379     protected Relationship buildRelationship(SingleUri uri, GraphInventoryEdgeLabel label) {
 
 380         return buildRelationship(uri, Optional.of(label));
 
 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());
 
 388             result.setRelatedLink(uri.build().toString());
 
 390         if (label.isPresent()) {
 
 391             result.setRelationshipLabel(label.get().toString());
 
 396     public abstract Wrapper createWrapper(String json);
 
 398     public abstract Wrapper createWrapper(Object json);
 
 401      * Starts a transaction which encloses multiple GraphInventory mutations
 
 405     public abstract TransactionalClient beginTransaction();
 
 408      * Starts a transaction groups multiple GraphInventory mutations
 
 412     public abstract SingleTransactionClient beginSingleTransaction();
 
 414     public <T extends RestProperties> T getRestProperties() {
 
 415         return client.getRestProperties();