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