Reformat catalog-model
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / jsonjanusgraph / operations / ArchiveOperation.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2019 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.jsonjanusgraph.operations;
21
22 import static org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArchiveOperation.Action.ARCHIVE;
23 import static org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArchiveOperation.Action.RESTORE;
24
25 import fj.data.Either;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.LinkedList;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.stream.Collectors;
32 import org.openecomp.sdc.be.dao.api.ActionStatus;
33 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
34 import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
35 import org.openecomp.sdc.be.dao.jsongraph.JanusGraphDao;
36 import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
37 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
38 import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
39 import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition;
40 import org.openecomp.sdc.be.datatypes.elements.CompositionDataDefinition;
41 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
42 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
43 import org.openecomp.sdc.be.model.LifecycleStateEnum;
44 import org.openecomp.sdc.be.model.jsonjanusgraph.enums.JsonConstantKeysEnum;
45 import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation;
46 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
47 import org.openecomp.sdc.common.log.wrappers.Logger;
48 import org.springframework.beans.factory.annotation.Autowired;
49 import org.springframework.stereotype.Component;
50
51 /**
52  * Created by yavivi on 25/03/2018.
53  */
54 @Component
55 public class ArchiveOperation extends BaseOperation {
56
57     private static final Logger log = Logger.getLogger(ArchiveOperation.class.getName());
58     @Autowired
59     private IGraphLockOperation graphLockOperation;
60
61     public ArchiveOperation(JanusGraphDao janusGraphDao, IGraphLockOperation graphLockOperation) {
62         this.janusGraphDao = janusGraphDao;
63         this.graphLockOperation = graphLockOperation;
64     }
65
66     public Either<List<String>, ActionStatus> archiveComponent(String componentId) {
67         final Either<GraphVertex, JanusGraphOperationStatus> vertexResult = this.janusGraphDao.getVertexById(componentId);
68         if (vertexResult.isLeft()) {
69             return doAction(ARCHIVE, vertexResult.left().value());
70         } else {
71             return Either.right(onError(ARCHIVE.name(), componentId, vertexResult.right().value()));
72         }
73     }
74
75     public Either<List<String>, ActionStatus> restoreComponent(String componentId) {
76         final Either<GraphVertex, JanusGraphOperationStatus> vertexResult = this.janusGraphDao.getVertexById(componentId);
77         if (vertexResult.isLeft()) {
78             return doAction(RESTORE, vertexResult.left().value());
79         } else {
80             return Either.right(onError(RESTORE.name(), componentId, vertexResult.right().value()));
81         }
82     }
83
84     public ActionStatus onVspRestored(String csarId) {
85         return onVspStateChanged(RESTORE, csarId);
86     }
87
88     public ActionStatus onVspArchived(String csarId) {
89         return onVspStateChanged(ARCHIVE, csarId);
90     }
91
92     private ActionStatus onVspStateChanged(Action action, String csarId) {
93         Map<GraphPropertyEnum, Object> props = new HashMap<>();
94         props.put(GraphPropertyEnum.CSAR_UUID, csarId);
95         Either<List<GraphVertex>, JanusGraphOperationStatus> vfsE = janusGraphDao.getByCriteria(VertexTypeEnum.TOPOLOGY_TEMPLATE, props);
96         return vfsE.either(vList -> setVspArchived(action, vList), s -> onError("VSP_" + action.name(), csarId, s));
97     }
98
99     private ActionStatus setVspArchived(Action action, List<GraphVertex> vList) {
100         if (!vList.isEmpty()) {
101             //Find & Lock the highest version component
102             GraphVertex highestVersion = this.getHighestVersionFrom(vList.get(0));
103             StorageOperationStatus lockStatus = this.graphLockOperation
104                 .lockComponent(highestVersion.getUniqueId(), highestVersion.getType().getNodeType());
105             if (lockStatus != StorageOperationStatus.OK) {
106                 return onError(action.name(), highestVersion.getUniqueId(), JanusGraphOperationStatus.ALREADY_LOCKED);
107             }
108             try {
109                 //Set isVspArchived flag
110                 for (GraphVertex v : vList) {
111                     boolean val = action == ARCHIVE ? true : false;
112                     v.setJsonMetadataField(JsonPresentationFields.IS_VSP_ARCHIVED, val);
113                     v.addMetadataProperty(GraphPropertyEnum.IS_VSP_ARCHIVED, val);
114                     janusGraphDao.updateVertex(v);
115                 }
116                 return commitAndCheck("VSP_" + action.name(), vList.toString());
117             } finally {
118                 this.graphLockOperation.unlockComponent(highestVersion.getUniqueId(), highestVersion.getType().getNodeType());
119             }
120         }
121         return ActionStatus.OK;
122     }
123
124     public List<String> setArchivedOriginsFlagInComponentInstances(GraphVertex compositionService) {
125         List<String> ciUidsWithArchivedOrigins = new LinkedList();
126         Either<List<GraphVertex>, JanusGraphOperationStatus> instanceOfVerticesE = janusGraphDao
127             .getChildrenVertices(compositionService, EdgeLabelEnum.INSTANCE_OF, JsonParseFlagEnum.NoParse);
128         Either<List<GraphVertex>, JanusGraphOperationStatus> proxyOfVerticesE = janusGraphDao
129             .getChildrenVertices(compositionService, EdgeLabelEnum.PROXY_OF, JsonParseFlagEnum.NoParse);
130         List<GraphVertex> all = new LinkedList<>();
131         if (instanceOfVerticesE.isLeft()) {
132             all.addAll(instanceOfVerticesE.left().value());
133         }
134         if (proxyOfVerticesE.isLeft()) {
135             all.addAll(proxyOfVerticesE.left().value());
136         }
137         List<GraphVertex> archivedOrigins = all.stream().filter(v -> Boolean.TRUE.equals(v.getMetadataProperty(GraphPropertyEnum.IS_ARCHIVED)))
138             .collect(Collectors.toList());
139         List<String> archivedOriginsUids = archivedOrigins.stream().map(GraphVertex::getUniqueId).collect(Collectors.toList());
140         Map<String, CompositionDataDefinition> compositionsJson = (Map<String, CompositionDataDefinition>) compositionService.getJson();
141         if (compositionsJson != null) {
142             CompositionDataDefinition composition = compositionsJson.get(JsonConstantKeysEnum.COMPOSITION.getValue());
143             if (composition != null) {
144                 //Get all component instances from composition
145                 Map<String, ComponentInstanceDataDefinition> componentInstances = composition.getComponentInstances();
146                 //Extract component instances uids that has archived origins
147                 ciUidsWithArchivedOrigins = componentInstances.values().stream().
148                     //filter CIs whose origins are marked as archived (componentUid is in archivedOriginsUids) the second condition handles the PROXY_OF case)
149                         filter(ci -> archivedOriginsUids.contains(ci.getComponentUid()) || archivedOriginsUids
150                         .contains(ci.getToscaPresentationValue(JsonPresentationFields.CI_SOURCE_MODEL_UID)))
151                     .map(ComponentInstanceDataDefinition::getUniqueId).collect(Collectors.toList());
152                 //set archived origins flag
153                 componentInstances.values().stream().filter(ci -> archivedOriginsUids.contains(ci.getComponentUid()) || archivedOriginsUids
154                     .contains(ci.getToscaPresentationValue(JsonPresentationFields.CI_SOURCE_MODEL_UID))).forEach(ci -> ci.setOriginArchived(true));
155             }
156         }
157         return ciUidsWithArchivedOrigins;
158     }
159
160     private Either<List<String>, ActionStatus> doAction(Action action, GraphVertex componentVertex) {
161         GraphVertex highestVersion = this.getHighestVersionFrom(componentVertex);
162         if (action.equals(ARCHIVE) && isInCheckoutState(highestVersion)) {
163             return Either.right(ActionStatus.INVALID_SERVICE_STATE);
164         }
165         //Lock the Highest Version
166         StorageOperationStatus lockStatus = this.graphLockOperation
167             .lockComponent(highestVersion.getUniqueId(), highestVersion.getType().getNodeType());
168         if (lockStatus != StorageOperationStatus.OK) {
169             return Either.right(onError(action.name(), componentVertex.getUniqueId(), JanusGraphOperationStatus.ALREADY_LOCKED));
170         }
171         //Refetch latest version with full parsing
172         highestVersion = this.janusGraphDao.getVertexById(highestVersion.getUniqueId(), JsonParseFlagEnum.ParseAll).left().value();
173         try {
174             //Get Catalog and Archive Roots
175             GraphVertex catalogRoot = janusGraphDao.getVertexByLabel(VertexTypeEnum.CATALOG_ROOT).left().value();
176             GraphVertex archiveRoot = janusGraphDao.getVertexByLabel(VertexTypeEnum.ARCHIVE_ROOT).left().value();
177             if (action == ARCHIVE) {
178                 archiveEdges(catalogRoot, archiveRoot, highestVersion);
179             } else if (action == RESTORE) {
180                 restoreEdges(catalogRoot, archiveRoot, highestVersion);
181             }
182             setPropertiesByAction(highestVersion, action);
183             janusGraphDao.updateVertex(highestVersion);
184             List<String> affectedComponentIds = handleParents(highestVersion, catalogRoot, archiveRoot, action);
185             ActionStatus sc = commitAndCheck(action.name(), highestVersion.getUniqueId());
186             return sc == ActionStatus.OK ? Either.left(affectedComponentIds) : Either.right(sc);
187         } finally {
188             this.graphLockOperation.unlockComponent(highestVersion.getUniqueId(), highestVersion.getType().getNodeType());
189         }
190     }
191
192     private ActionStatus commitAndCheck(String action, String componentId) {
193         JanusGraphOperationStatus status = janusGraphDao.commit();
194         if (!status.equals(JanusGraphOperationStatus.OK)) {
195             return onError(action, componentId, status);
196         }
197         return ActionStatus.OK;
198     }
199
200     private boolean isInCheckoutState(GraphVertex v) {
201         if (LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name().equals(v.getMetadataProperty(GraphPropertyEnum.STATE))) {
202             return true;
203         }
204         return false;
205     }
206
207     /**
208      * Walks on children until highest version is reached
209      *
210      * @param v
211      * @return
212      */
213     private GraphVertex getHighestVersionFrom(GraphVertex v) {
214         Either<GraphVertex, JanusGraphOperationStatus> childVertexE = janusGraphDao
215             .getChildVertex(v, EdgeLabelEnum.VERSION, JsonParseFlagEnum.NoParse);
216         GraphVertex highestVersionVertex = v;
217         while (childVertexE.isLeft()) {
218             highestVersionVertex = childVertexE.left().value();
219             childVertexE = janusGraphDao.getChildVertex(highestVersionVertex, EdgeLabelEnum.VERSION, JsonParseFlagEnum.NoParse);
220         }
221         return highestVersionVertex;
222     }
223
224     private boolean isHighestVersion(GraphVertex v) {
225         Boolean highest = (Boolean) v.getMetadataProperty(GraphPropertyEnum.IS_HIGHEST_VERSION);
226         return highest != null && highest;
227     }
228
229     private List<String> handleParents(GraphVertex v, GraphVertex catalogRoot, GraphVertex archiveRoot, Action action) {
230         Either<GraphVertex, JanusGraphOperationStatus> parentVertexE = janusGraphDao
231             .getParentVertex(v, EdgeLabelEnum.VERSION, JsonParseFlagEnum.ParseAll);
232         List<String> affectedCompIds = new ArrayList();
233         affectedCompIds.add(v.getUniqueId());
234         while (parentVertexE.isLeft()) {
235             GraphVertex cv = parentVertexE.left().value();
236             affectedCompIds.add(cv.getUniqueId());
237             boolean isHighestVersion = isHighestVersion(cv);
238             if (isHighestVersion) {
239                 if (action == ARCHIVE) {
240                     archiveEdges(catalogRoot, archiveRoot, cv);
241                 } else {
242                     restoreEdges(catalogRoot, archiveRoot, cv);
243                 }
244             }
245             setPropertiesByAction(cv, action);
246             janusGraphDao.updateVertex(cv);
247             parentVertexE = janusGraphDao.getParentVertex(cv, EdgeLabelEnum.VERSION, JsonParseFlagEnum.ParseAll);
248         }
249         return affectedCompIds;
250     }
251
252     private void archiveEdges(GraphVertex catalogRoot, GraphVertex archiveRoot, GraphVertex v) {
253         janusGraphDao.deleteAllEdges(catalogRoot, v, EdgeLabelEnum.CATALOG_ELEMENT);
254         janusGraphDao.createEdge(archiveRoot, v, EdgeLabelEnum.ARCHIVE_ELEMENT, null);
255         setPropertiesByAction(v, ARCHIVE);
256     }
257
258     private void restoreEdges(GraphVertex catalogRoot, GraphVertex archiveRoot, GraphVertex v) {
259         janusGraphDao.deleteAllEdges(archiveRoot, v, EdgeLabelEnum.ARCHIVE_ELEMENT);
260         janusGraphDao.createEdge(catalogRoot, v, EdgeLabelEnum.CATALOG_ELEMENT, null);
261         setPropertiesByAction(v, RESTORE);
262     }
263
264     private void setPropertiesByAction(GraphVertex v, Action action) {
265         long now = System.currentTimeMillis();
266         boolean isArchived = action == ARCHIVE ? true : false;
267         v.addMetadataProperty(GraphPropertyEnum.IS_ARCHIVED, isArchived);
268         v.addMetadataProperty(GraphPropertyEnum.ARCHIVE_TIME, now);
269         v.setJsonMetadataField(JsonPresentationFields.IS_ARCHIVED, isArchived);
270         v.setJsonMetadataField(JsonPresentationFields.ARCHIVE_TIME, now);
271     }
272
273     private ActionStatus onError(String action, String componentId, JanusGraphOperationStatus s) {
274         ActionStatus ret = ActionStatus.GENERAL_ERROR;
275         if (s == JanusGraphOperationStatus.NOT_FOUND) {
276             ret = ActionStatus.RESOURCE_NOT_FOUND;
277         } else if (s == JanusGraphOperationStatus.ALREADY_LOCKED) {
278             ret = ActionStatus.COMPONENT_IN_USE;
279         }
280         String retCodeVal = ret.name();
281         log.error("error occurred when trying to {} {}. Return code is: {}", action, componentId, retCodeVal);
282         return ret;
283     }
284
285     public enum Action {ARCHIVE, RESTORE;}
286 }