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