437f16347221267562cb0b2e564bb956b6a576d3
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / serialization / db / ImpliedDelete.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
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
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 package org.onap.aai.serialization.db;
21
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;
33
34 import java.util.List;
35 import java.util.Objects;
36
37 /**
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
43  *
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
47  *
48  * @see org.onap.aai.util.AAIConfigProxy
49  */
50 public class ImpliedDelete implements AAIConfigProxy {
51
52     private static final Logger LOGGER = LoggerFactory.getLogger(ImpliedDelete.class);
53
54     private static final String IMPLICIT_DELETE = "Implicit DELETE";
55     private static final String STAR = "*";
56
57     private TransactionalGraphEngine engine;
58     private DBSerializer serializer;
59
60     public ImpliedDelete(TransactionalGraphEngine engine, DBSerializer serializer){
61         this.engine = engine;
62         this.serializer = serializer;
63     }
64
65     /**
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:
70      *
71      * aai.implied.delete.log.enabled=true
72      * aai.implied.delete.log.limit=-1
73      *
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
79      *
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
85      */
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)){
94
95                 int impliedDeleteCount = impliedDeleteVertices.size();
96
97                 LOGGER.warn(
98                     "For the vertex with id {}, doing an implicit delete on update will delete total of {} vertexes",
99                     id,
100                     impliedDeleteCount
101                 );
102
103                 String impliedDeleteLogEnabled = get(AAIConstants.AAI_IMPLIED_DELETE_LOG_ENABLED, "true");
104
105                 int impliedDeleteLogLimit = getInt(AAIConstants.AAI_IMPLIED_DELETE_LOG_LIMIT, "-1");
106
107                 if (impliedDeleteLogLimit == -1) {
108                     impliedDeleteLogLimit = Integer.MAX_VALUE;
109                 }
110
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;
116                         try {
117                             introspector = serializer.getLatestVersionView(vertex);
118                             if (LOGGER.isInfoEnabled()) {
119                                 LOGGER.info("Implied delete object in json format {}", introspector.marshal(false));
120                             }
121                         } catch (Exception ex) {
122                             LOGGER.warn(
123                                 "Encountered an exception during retrieval of vertex properties with vertex-id {} -> {}",
124                                 id, LogFormatTools.getStackTop(ex));
125                         }
126                     }
127                 }
128             } else {
129                 LOGGER.error("User {} is not allowed to implicit delete on parent object {}", sot, objectType);
130                 throw new AAIException("AAI_9109");
131             }
132             return impliedDeleteVertices;
133         } else {
134             // Return null or an empty list back to the user based on input
135             return dependentVertexes;
136         }
137     }
138
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);
143        }
144     }
145
146     /**
147      * Checks the property in the aaiconfig properties
148      * to see if the user is allowed to do implicit delete
149      *
150      * Expecting the aaiconfig.properties to have following type of properties
151      *
152      * <code>
153      * aai.implied.delete.whitelist.sdnc=*
154      * aai.implied.delete.whitelist.sdc='pserver','vserver'
155      * </code>
156      *
157      * So in the above code, the expectation is for any of the following user:
158      *
159      * <ul>
160      *     <li>SDC</li>
161      *     <li>SDc</li>
162      *     <li>Sdc</li>
163      *     <li>sDc</li>
164      *     <li>SdC</li>
165      *     <li>sdC</li>
166      *     <li>sdc</li>
167      * </ul>
168      *
169      * They are allowed to delete the children of pserver and vserver by implicit delete
170      *
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
176      *
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
180      *
181      * @return true  - if the requester is allowed to implicit delete against the object type
182      *         false - if they are not allowed
183      */
184     private boolean allow(String sourceOfTruth, String parentObjectType){
185         Objects.requireNonNull(sourceOfTruth);
186         Objects.requireNonNull(parentObjectType);
187
188         String propertyName = AAIConstants.AAI_IMPLIED_DELETE_WHITELIST + sourceOfTruth.toLowerCase();
189         String whitelist = get(propertyName, StringUtils.EMPTY);
190
191         if(whitelist.isEmpty()){
192             return false;
193         }
194
195         if(STAR.equals(whitelist)){
196             return true;
197         }
198
199         if(whitelist.contains("'" + parentObjectType + "'")){
200             return true;
201         }
202
203         return false;
204     }
205 }