re base code
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / operations / impl / UserAdminOperation.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 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.openecomp.sdc.be.model.operations.impl;
22
23 import com.thinkaurelius.titan.core.TitanVertex;
24 import fj.data.Either;
25 import org.apache.commons.lang3.BooleanUtils;
26 import org.apache.tinkerpop.gremlin.structure.Direction;
27 import org.apache.tinkerpop.gremlin.structure.Edge;
28 import org.apache.tinkerpop.gremlin.structure.Vertex;
29 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
30 import org.openecomp.sdc.be.dao.api.ActionStatus;
31 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
32 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
33 import org.openecomp.sdc.be.dao.titan.TitanGenericDao;
34 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
35 import org.openecomp.sdc.be.dao.utils.UserStatusEnum;
36 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
37 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
38 import org.openecomp.sdc.be.model.User;
39 import org.openecomp.sdc.be.model.operations.api.IUserAdminOperation;
40 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
41 import org.openecomp.sdc.be.resources.data.UserData;
42 import org.openecomp.sdc.common.datastructure.Wrapper;
43 import org.openecomp.sdc.common.log.wrappers.Logger;
44 import org.openecomp.sdc.common.util.MethodActivationStatusEnum;
45 import org.springframework.beans.factory.annotation.Qualifier;
46 import org.springframework.stereotype.Component;
47
48 import java.util.*;
49
50 import static org.apache.commons.collections.CollectionUtils.isEmpty;
51
52 @Component("user-operation")
53 public class UserAdminOperation implements IUserAdminOperation {
54
55     private TitanGenericDao titanGenericDao;
56
57     public UserAdminOperation(@Qualifier("titan-generic-dao") TitanGenericDao titanGenericDao) {
58         super();
59         this.titanGenericDao = titanGenericDao;
60
61     }
62
63     private static final Logger log = Logger.getLogger(UserAdminOperation.class.getName());
64
65     @Override
66     public Either<User, ActionStatus> getUserData(String id, boolean inTransaction) {
67         return getUserData(id, true, inTransaction);
68     }
69
70     private Either<User, ActionStatus> getUserData(String id, boolean isActive, boolean inTransaction) {
71         log.debug("getUserData - start");
72         Wrapper<Either<User, ActionStatus>> resultWrapper = new Wrapper<>();
73         Wrapper<UserData> userWrapper = new Wrapper<>();
74         try {
75             validateUserExists(resultWrapper, userWrapper, id);
76
77             if (resultWrapper.isEmpty()) {
78                 validateUserData(resultWrapper, userWrapper.getInnerElement(), id);
79
80             }
81             if (resultWrapper.isEmpty()) {
82                 if (isActive) {
83                     validateActiveUser(resultWrapper, userWrapper.getInnerElement());
84                 } else {
85                     validateInActiveUser(resultWrapper, userWrapper.getInnerElement());
86                 }
87             }
88
89             if (resultWrapper.isEmpty()) {
90                 resultWrapper.setInnerElement(Either.left(convertToUser(userWrapper.getInnerElement())));
91             }
92
93             return resultWrapper.getInnerElement();
94         } finally {
95             if (!inTransaction) {
96                 titanGenericDao.commit();
97             }
98             log.debug("getUserData - end");
99         }
100     }
101
102     private void validateInActiveUser(Wrapper<Either<User, ActionStatus>> resultWrapper, UserData userData) {
103         User user = convertToUser(userData);
104         if (user.getStatus() == UserStatusEnum.ACTIVE) {
105             resultWrapper.setInnerElement(Either.right(ActionStatus.USER_NOT_FOUND));
106         }
107     }
108
109     private void validateActiveUser(Wrapper<Either<User, ActionStatus>> resultWrapper, UserData userData) {
110         User user = convertToUser(userData);
111         if (user.getStatus() == UserStatusEnum.INACTIVE) {
112             resultWrapper.setInnerElement(Either.right(ActionStatus.USER_INACTIVE));
113         }
114     }
115
116     private void validateUserData(Wrapper<Either<User, ActionStatus>> resultWrapper, UserData userData, String id) {
117         if (userData == null) {
118             log.debug("Problem get User with userId {}. Reason -  either.left().value() = null", id);
119             resultWrapper.setInnerElement(Either.right(ActionStatus.GENERAL_ERROR));
120         }
121     }
122
123     private void validateUserExists(Wrapper<Either<User, ActionStatus>> resultWrapper, Wrapper<UserData> userWrapper, String id) {
124         if (id == null) {
125             log.info("User userId  is empty");
126             resultWrapper.setInnerElement(Either.right(ActionStatus.MISSING_INFORMATION));
127             return;
128         }
129         id = id.toLowerCase();
130         Either<UserData, TitanOperationStatus> either = titanGenericDao.getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.User), id, UserData.class);
131
132         if (either.isRight()) {
133             resultWrapper.setInnerElement(getUserNotFoundError(id, either.right().value()));
134         } else {
135             userWrapper.setInnerElement(either.left().value());
136         }
137     }
138
139     @Override
140     public Either<User, StorageOperationStatus> saveUserData(User user) {
141         Either<UserData, TitanOperationStatus> result = null;
142         try {
143             UserData userData = convertToUserData(user);
144             result = titanGenericDao.createNode(userData, UserData.class);
145             if (result.isRight()) {
146                 log.debug("Problem while saving User  {}. Reason - {}", userData.getUserId(), result.right().value());
147                 return Either.right(StorageOperationStatus.GENERAL_ERROR);
148             }
149             log.debug("User {} saved successfully", userData.getUserId());
150             return Either.left(convertToUser(result.left().value()));
151
152         } finally {
153
154             if (result == null || result.isRight()) {
155                 log.error("saveUserData - Failed");
156                 titanGenericDao.rollback();
157             } else {
158                 log.debug("saveUserData - end");
159                 titanGenericDao.commit();
160             }
161         }
162     }
163
164     @Override
165     public Either<User, StorageOperationStatus> updateUserData(User user) {
166         Either<UserData, TitanOperationStatus> result = null;
167         try {
168             log.debug("updateUserData - start");
169             UserData userData = convertToUserData(user);
170             result = titanGenericDao.updateNode(userData, UserData.class);
171             if (result.isRight()) {
172                 if (log.isDebugEnabled()) {
173                     log.debug("Problem while updating User {}. Reason - {}", userData.toString(), result.right().value());
174                 }
175                 return Either.right(StorageOperationStatus.GENERAL_ERROR);
176             }
177             log.debug("User {} updated successfully",userData.getUserId());
178             return Either.left(convertToUser(result.left().value()));
179
180         } finally {
181
182             if (result == null || result.isRight()) {
183                 log.error("updateUserData - Failed");
184                 titanGenericDao.rollback();
185             } else {
186                 log.debug("updateUserData - end");
187                 titanGenericDao.commit();
188             }
189
190         }
191     }
192
193     @Override
194     public Either<User, StorageOperationStatus> deActivateUser(User user) {
195         Either<User, StorageOperationStatus> result;
196         user.setStatus(UserStatusEnum.INACTIVE);
197         Either<User, StorageOperationStatus> status = updateUserData(user);
198         if (status.isRight()) {
199             result = Either.right(status.right().value());
200         } else {
201             result = Either.left(user);
202         }
203         return result;
204     }
205
206     @Override
207     public Either<User, ActionStatus> deleteUserData(String id) {
208         Either<User, ActionStatus> result;
209         Either<UserData, TitanOperationStatus> eitherGet = titanGenericDao.getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.User), id, UserData.class);
210         if (eitherGet.isRight()) {
211             log.debug("Problem while retriving user with userId {}",id);
212             if (eitherGet.right().value() == TitanOperationStatus.NOT_FOUND) {
213                 result = Either.right(ActionStatus.USER_NOT_FOUND);
214             } else {
215                 result = Either.right(ActionStatus.GENERAL_ERROR);
216             }
217         } else {
218             result = deleteUserLogic(eitherGet.left().value());
219         }
220         return result;
221     }
222
223     private Either<User, ActionStatus> deleteUserLogic(UserData userData) {
224         Wrapper<Either<User, ActionStatus>> resultWrapper = new Wrapper<>();
225         try {
226             validateUserHasNoConnections(resultWrapper, userData);
227             if (resultWrapper.isEmpty()) {
228                 deleteUser(resultWrapper, userData);
229             }
230         } finally {
231             titanGenericDao.commit();
232         }
233         return resultWrapper.getInnerElement();
234     }
235
236     private void deleteUser(Wrapper<Either<User, ActionStatus>> resultWrapper, UserData userData) {
237         Either<UserData, TitanOperationStatus> eitherDelete = titanGenericDao.deleteNode(userData, UserData.class);
238         if (eitherDelete.isRight()) {
239             if (log.isDebugEnabled()) {
240                 log.debug("Problem while deleting User {}. Reason - {}", userData.toString(), eitherDelete.right().value());
241             }
242             resultWrapper.setInnerElement(Either.right(ActionStatus.GENERAL_ERROR));
243         } else {
244             log.debug("User {} deleted successfully",userData.getUserId());
245             resultWrapper.setInnerElement(Either.left(convertToUser(eitherDelete.left().value())));
246         }
247     }
248
249     private void validateUserHasNoConnections(Wrapper<Either<User, ActionStatus>> resultWrapper, UserData userData) {
250         if (resultWrapper.isEmpty()) {
251
252             Either<List<Edge>, TitanOperationStatus> edgesForNode = titanGenericDao.getEdgesForNode(userData, Direction.BOTH);
253             if (edgesForNode.isRight()) {
254                 if (log.isDebugEnabled()) {
255                     log.debug("Problem while deleting User {}. Reason - {}", userData.getUserId(), edgesForNode.right().value());
256                 }
257                 resultWrapper.setInnerElement(Either.right(ActionStatus.GENERAL_ERROR));
258             } else {
259                 List<Edge> vertexEdges = edgesForNode.left().value();
260                 if (!isEmpty(vertexEdges)) {
261                     resultWrapper.setInnerElement(Either.right(ActionStatus.USER_HAS_ACTIVE_ELEMENTS));
262                 }
263             }
264         }
265     }
266
267     public Either<List<Edge>, StorageOperationStatus> getUserPendingTasksList(User user, Map<String, Object> properties) {
268
269         Either<TitanVertex, TitanOperationStatus> vertexUser = titanGenericDao.getVertexByProperty(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.User), user.getUserId());
270         if (vertexUser.isRight()) {
271             TitanOperationStatus tos = vertexUser.right().value();
272             log.debug("Failed to get User {} from graph while retrieving pending tasks. Reason - {}", user.getUserId(), tos);
273             return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(tos));
274         }
275         List<Edge> pendingTasks = new ArrayList<>();
276         Either<List<Edge>, TitanOperationStatus> edges = titanGenericDao.getOutgoingEdgesByCriteria(vertexUser.left().value(), GraphEdgeLabels.STATE, properties);
277         if (edges.isRight() || edges.left().value() == null) {
278             TitanOperationStatus tos = edges.right().value();
279             if (tos == TitanOperationStatus.NOT_FOUND) {
280                 return Either.left(pendingTasks);
281             } else {
282                 log.debug("Failed while retrieving pending tasks for user {} . Reason - {}", user.getUserId(), tos);
283                 return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(tos));
284             }
285         }
286         for (Edge edge : edges.left().value()) {
287             if (!isComponentDeleted(edge.inVertex())) {
288                 pendingTasks.add(edge);
289             }
290         }
291         logPendingTasks(user, pendingTasks);
292         return Either.left(pendingTasks);
293     }
294
295     private boolean isComponentDeleted(Vertex componentVertex) {
296         VertexProperty<Object> property = componentVertex.property(GraphPropertiesDictionary.IS_DELETED.getProperty());
297         if (property.isPresent()) {
298             return BooleanUtils.isTrue((Boolean) property.value());
299         }
300         return false;
301     }
302
303     private void logPendingTasks(User user, List<Edge> pendingTasks) {
304         if (log.isDebugEnabled()) {
305             for (Edge edge : pendingTasks) {
306                 Object resourceUuid = edge.inVertex().property(GraphPropertyEnum.UNIQUE_ID.getProperty()).value();
307                 Object componentName = edge.inVertex().property(GraphPropertyEnum.NAME.getProperty()).value();
308                 Object componentState = edge.inVertex().property(GraphPropertyEnum.STATE.getProperty()).value();
309                 log.debug("The user userId = {} is working on the component name = {} uid = {} in state {}", user.getUserId(), componentName, resourceUuid, componentState);
310             }
311         }
312     }
313
314     @Override
315     public Either<List<User>, ActionStatus> getAllUsersWithRole(String role, String status) {
316         try {
317             Map<String, Object> propertiesToMatch = new HashMap<>();
318             if (role != null && !role.trim().isEmpty()) {
319                 propertiesToMatch.put(GraphPropertiesDictionary.ROLE.getProperty(), role);
320             }
321             if (status != null && !status.isEmpty()) {
322                 propertiesToMatch.put(GraphPropertiesDictionary.USER_STATUS.getProperty(), status);
323             }
324
325             Either<List<UserData>, TitanOperationStatus> userNodes = titanGenericDao.getByCriteria(NodeTypeEnum.User, propertiesToMatch, UserData.class);
326
327             titanGenericDao.commit();
328             return convertToUsers(role, userNodes);
329         } finally {
330             titanGenericDao.commit();
331         }
332     }
333
334     private Either<List<User>, ActionStatus> convertToUsers(String role, Either<List<UserData>, TitanOperationStatus> userNodes) {
335
336         if (userNodes.isRight()) {
337             // in case of NOT_FOUND from Titan return empty list
338             TitanOperationStatus tos = userNodes.right().value();
339             if (tos.equals(TitanOperationStatus.NOT_FOUND)) {
340                 return Either.left(Collections.emptyList());
341             } else {
342                 log.error("Problem while getting all users with role {}. Reason - {}", role, tos);
343                 return Either.right(ActionStatus.GENERAL_ERROR);
344             }
345         } else {
346             List<UserData> userDataList = userNodes.left().value();
347             if (userDataList != null) {
348                 return Either.left(convertToUsers(userDataList));
349             }
350             log.debug("No users were found with role {}", role);
351             return Either.left(Collections.emptyList());
352         }
353     }
354
355     private List<User> convertToUsers(List<UserData> usersData) {
356         List<User> result = new ArrayList<>();
357         for (UserData userData : usersData) {
358             User user = convertToUser(userData);
359             result.add(user);
360         }
361         return result;
362     }
363
364     private Either<User, ActionStatus> getUserNotFoundError(String uid, TitanOperationStatus status) {
365         if (status == TitanOperationStatus.NOT_FOUND) {
366             log.debug("User with userId {} not found", uid);
367             return Either.right(ActionStatus.USER_NOT_FOUND);
368         } else {
369             log.debug("Problem get User with userId {}. Reason - {}", uid, status);
370             return  Either.right(ActionStatus.GENERAL_ERROR);
371         }
372     }
373
374     protected User convertToUser(UserData userData) {
375         User user = new User();
376         user.setUserId(userData.getUserId());
377         user.setEmail(userData.getEmail());
378         user.setFirstName(userData.getFirstName());
379         user.setLastName(userData.getLastName());
380         user.setRole(userData.getRole());
381         user.setLastLoginTime(userData.getLastLoginTime());
382         // Support backward compatibility - user status may not exist in old
383         // users
384         Either<UserStatusEnum, MethodActivationStatusEnum> either = UserStatusEnum.findByName(userData.getStatus());
385         user.setStatus(either.isLeft() ? either.left().value() : UserStatusEnum.ACTIVE);
386         return user;
387     }
388
389     protected UserData convertToUserData(User user) {
390         UserData userData = new UserData();
391         userData.setUserId(user.getUserId().toLowerCase());
392         userData.setEmail(user.getEmail());
393         userData.setFirstName(user.getFirstName());
394         userData.setLastName(user.getLastName());
395         userData.setRole(user.getRole());
396         userData.setStatus(user.getStatus().name());
397         userData.setLastLoginTime(user.getLastLoginTime());
398         return userData;
399     }
400
401 }