2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 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
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.aai.serialization.db;
23 import java.util.List;
24 import java.util.Objects;
26 import org.apache.commons.lang3.StringUtils;
27 import org.apache.tinkerpop.gremlin.structure.Vertex;
28 import org.onap.aai.exceptions.AAIException;
29 import org.onap.aai.introspection.Introspector;
30 import org.onap.aai.logging.LogFormatTools;
31 import org.onap.aai.serialization.engines.TransactionalGraphEngine;
32 import org.onap.aai.serialization.engines.query.QueryEngine;
33 import org.onap.aai.util.AAIConfigProxy;
34 import org.onap.aai.util.AAIConstants;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
39 * <b>ImpliedDelete</b> class is responsible for deleting children
40 * of a parent vertex if the client explicitly asks to remove them
41 * It will check if they are allowed and based on that information
42 * it will decide whether to proceed with the deletion or
43 * throw an exception back to the requester if they are not allowed
45 * It implements the AAIProxy Interface and any calls to the
46 * AAIConfig should be using the proxy methods and any new
47 * methods that needs to be invoked should be added there first
49 * @see org.onap.aai.util.AAIConfigProxy
51 public class ImpliedDelete implements AAIConfigProxy {
53 private static final Logger LOGGER = LoggerFactory.getLogger(ImpliedDelete.class);
55 private static final String IMPLICIT_DELETE = "Implicit DELETE";
56 private static final String STAR = "*";
58 private TransactionalGraphEngine engine;
59 private DBSerializer serializer;
61 public ImpliedDelete(TransactionalGraphEngine engine, DBSerializer serializer) {
63 this.serializer = serializer;
67 * Checks if the user is allowed to execute implied delete
68 * If they are allowed to do the delete, then for all the dependent vertices
69 * it will identify all the deletable vertices to them
70 * and log them based on the following aaiconfig properties:
72 * aai.implied.delete.log.enabled=true
73 * aai.implied.delete.log.limit=-1
75 * Above properties are the default assumption of the code if they are not overwritten
76 * So the code will log for every vertex it is about to delete
77 * If there are thousands of vertexes that get implicitly deleted,
78 * its preferable that the operation timeout rather than
79 * someone accidentally deleting thousands of children
81 * @param id - Identifier of the vertex whose children could be potentially deleted
82 * @param sot - source of truth of who the requester who is making the request
83 * @param objectType - type of the parent object whose children are being deleted
84 * @param dependentVertexes - list of children vertexes
85 * @throws AAIException if the user is not allowed to implicitly delete children
87 public List<Vertex> execute(Object id, String sot, String objectType, List<Vertex> dependentVertexes)
89 if (dependentVertexes != null && !dependentVertexes.isEmpty()) {
90 // Find all the deletable vertices from the dependent vertices that should be deleted
91 // So for each of the following dependent vertices,
92 // we will use the edge properties and do the cascade delete
93 QueryEngine queryEngine = this.engine.getQueryEngine();
94 List<Vertex> impliedDeleteVertices = queryEngine.findDeletable(dependentVertexes);
95 if (this.allow(sot, objectType)) {
97 int impliedDeleteCount = impliedDeleteVertices.size();
100 "For the vertex with id {}, doing an implicit delete on update will delete total of {} vertexes",
101 id, impliedDeleteCount);
103 String impliedDeleteLogEnabled = get(AAIConstants.AAI_IMPLIED_DELETE_LOG_ENABLED, "true");
105 int impliedDeleteLogLimit = getInt(AAIConstants.AAI_IMPLIED_DELETE_LOG_LIMIT, "-1");
107 if (impliedDeleteLogLimit == -1) {
108 impliedDeleteLogLimit = Integer.MAX_VALUE;
111 // If the logging is enabled for implied delete
112 // then log the payload in the latest format
113 if ("true".equals(impliedDeleteLogEnabled) && impliedDeleteCount <= impliedDeleteLogLimit) {
114 for (Vertex vertex : impliedDeleteVertices) {
115 Introspector introspector = null;
117 introspector = serializer.getLatestVersionView(vertex);
118 if (LOGGER.isInfoEnabled()) {
119 LOGGER.info("Implied delete object in json format {}", introspector.marshal(false));
121 } catch (Exception ex) {
123 "Encountered an exception during retrieval of vertex properties with vertex-id {} -> {}",
124 id, LogFormatTools.getStackTop(ex));
129 LOGGER.error("User {} is not allowed to implicit delete on parent object {}", sot, objectType);
130 throw new AAIException("AAI_9109");
132 return impliedDeleteVertices;
134 // Return null or an empty list back to the user based on input
135 return dependentVertexes;
139 public void delete(List<Vertex> vertices) {
140 // After all the appropriate logging, calling the serializer delete to delete the affected vertices
141 if (vertices != null && !vertices.isEmpty()) {
142 serializer.delete(vertices);
147 * Checks the property in the aaiconfig properties
148 * to see if the user is allowed to do implicit delete
150 * Expecting the aaiconfig.properties to have following type of properties
153 * aai.implied.delete.whitelist.sdnc=*
154 * aai.implied.delete.whitelist.sdc='pserver','vserver'
157 * So in the above code, the expectation is for any of the following user:
169 * They are allowed to delete the children of pserver and vserver by implicit delete
171 * Note: The reason the property values are placed inside the single quotes is
172 * so if there is an object called volume and there is another object called volume-group
173 * when doing an contains it can falsely allow volume-group children to be implicitly deleted
174 * and the cost of turning the string into an array and then searching if its inside it
175 * or loading into an set which is unnecessary and it could potentially be done for every request
177 * @param sourceOfTruth - the original requester that the request is coming from,
178 * derived from HTTP Header X-FromAppId
179 * @param parentObjectType - parent object in which they are trying to do the implicit delete against
181 * @return true - if the requester is allowed to implicit delete against the object type
182 * false - if they are not allowed
184 private boolean allow(String sourceOfTruth, String parentObjectType) {
185 Objects.requireNonNull(sourceOfTruth);
186 Objects.requireNonNull(parentObjectType);
188 String propertyName = AAIConstants.AAI_IMPLIED_DELETE_WHITELIST + sourceOfTruth.toLowerCase();
189 String whitelist = get(propertyName, StringUtils.EMPTY);
191 if (whitelist.isEmpty()) {
195 if (STAR.equals(whitelist)) {
199 if (whitelist.contains("'" + parentObjectType + "'")) {