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