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=========================================================
20 package org.onap.aai.serialization.db;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24 import org.apache.commons.lang.StringUtils;
25 import org.apache.tinkerpop.gremlin.structure.Vertex;
26 import org.onap.aai.exceptions.AAIException;
27 import org.onap.aai.introspection.Introspector;
28 import org.onap.aai.logging.LogFormatTools;
29 import org.onap.aai.serialization.engines.TransactionalGraphEngine;
30 import org.onap.aai.serialization.engines.query.QueryEngine;
31 import org.onap.aai.util.AAIConfigProxy;
32 import org.onap.aai.util.AAIConstants;
34 import java.util.List;
35 import java.util.Objects;
38 * <b>ImpliedDelete</b> class is responsible for deleting children
39 * of a parent vertex if the client explicitly asks to remove them
40 * It will check if they are allowed and based on that information
41 * it will decide whether to proceed with the deletion or
42 * throw an exception back to the requester if they are not allowed
44 * It implements the AAIProxy Interface and any calls to the
45 * AAIConfig should be using the proxy methods and any new
46 * methods that needs to be invoked should be added there first
48 * @see org.onap.aai.util.AAIConfigProxy
50 public class ImpliedDelete implements AAIConfigProxy {
52 private static final Logger LOGGER = LoggerFactory.getLogger(ImpliedDelete.class);
54 private static final String IMPLICIT_DELETE = "Implicit DELETE";
55 private static final String STAR = "*";
57 private TransactionalGraphEngine engine;
58 private DBSerializer serializer;
60 public ImpliedDelete(TransactionalGraphEngine engine, DBSerializer serializer){
62 this.serializer = serializer;
66 * Checks if the user is allowed to execute implied delete
67 * If they are allowed to do the delete, then for all the dependent vertices
68 * it will identify all the deletable vertices to them
69 * and log them based on the following aaiconfig properties:
71 * aai.implied.delete.log.enabled=true
72 * aai.implied.delete.log.limit=-1
74 * Above properties are the default assumption of the code if they are not overwritten
75 * So the code will log for every vertex it is about to delete
76 * If there are thousands of vertexes that get implicitly deleted,
77 * its preferable that the operation timeout rather than
78 * someone accidentally deleting thousands of children
80 * @param id - Identifier of the vertex whose children could be potentially deleted
81 * @param sot - source of truth of who the requester who is making the request
82 * @param objectType - type of the parent object whose children are being deleted
83 * @param dependentVertexes - list of children vertexes
84 * @throws AAIException if the user is not allowed to implicitly delete children
86 public List<Vertex> execute(Object id, String sot, String objectType, List<Vertex> dependentVertexes) throws AAIException {
87 if(dependentVertexes != null && !dependentVertexes.isEmpty()){
88 // Find all the deletable vertices from the dependent vertices that should be deleted
89 // So for each of the following dependent vertices,
90 // we will use the edge properties and do the cascade delete
91 QueryEngine queryEngine = this.engine.getQueryEngine();
92 List<Vertex> impliedDeleteVertices = queryEngine.findDeletable(dependentVertexes);
93 if(this.allow(sot, objectType)){
95 int impliedDeleteCount = impliedDeleteVertices.size();
98 "For the vertex with id {}, doing an implicit delete on update will delete total of {} vertexes",
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 + "'")){