2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.openecomp.sdc.be.model.jsonjanusgraph.operations;
26 import org.janusgraph.core.JanusGraphVertex;
27 import fj.data.Either;
28 import org.apache.commons.collections.CollectionUtils;
29 import org.apache.commons.collections.MapUtils;
30 import org.apache.commons.lang.StringUtils;
31 import org.apache.commons.lang3.tuple.ImmutablePair;
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.openecomp.sdc.be.config.ConfigurationManager;
36 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
37 import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
38 import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
39 import org.openecomp.sdc.be.dao.jsongraph.types.EdgePropertyEnum;
40 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
41 import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
42 import org.openecomp.sdc.be.dao.jsongraph.utils.IdBuilderUtils;
43 import org.openecomp.sdc.be.dao.jsongraph.utils.JsonParserUtils;
44 import org.openecomp.sdc.be.datatypes.elements.*;
45 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
46 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
47 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
48 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
49 import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
50 import org.openecomp.sdc.be.model.DistributionStatusEnum;
51 import org.openecomp.sdc.be.model.LifecycleStateEnum;
52 import org.openecomp.sdc.be.model.User;
53 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.TopologyTemplate;
54 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElement;
55 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElementTypeEnum;
56 import org.openecomp.sdc.be.model.jsonjanusgraph.enums.JsonConstantKeysEnum;
57 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
58 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
59 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
60 import org.openecomp.sdc.common.jsongraph.util.CommonUtility;
61 import org.openecomp.sdc.common.jsongraph.util.CommonUtility.LogLevelEnum;
62 import org.openecomp.sdc.common.log.wrappers.Logger;
65 import java.util.stream.Collectors;
67 @org.springframework.stereotype.Component("tosca-element-lifecycle-operation")
70 * Allows to perform lifecycle operations: checkin, checkout, submit for testing, start certification and certification process for tosca element
72 public class ToscaElementLifecycleOperation extends BaseOperation {
74 private static final String FAILED_TO_DELETE_LAST_STATE_EDGE_STATUS_IS = "Failed to delete last state edge. Status is {}. ";
75 private static final String FAILED_TO_GET_VERTICES = "Failed to get vertices by id {}. Status is {}. ";
76 public static final String VERSION_DELIMITER = ".";
77 public static final String VERSION_DELIMITER_REGEXP = "\\.";
79 private static final Logger log = Logger.getLogger(ToscaElementLifecycleOperation.class);
82 * Performs changing a lifecycle state of tosca element from "checked out" or "ready for certification" to "checked in"
85 * @param toscaElementId
90 public Either<ToscaElement, StorageOperationStatus> checkinToscaELement(LifecycleStateEnum currState,
91 String toscaElementId, String modifierId, String ownerId) {
94 .getVerticesByUniqueIdAndParseFlag(
95 prepareParametersToGetVerticesForCheckin(toscaElementId, modifierId, ownerId))
96 .right().map(status -> handleFailureToPrepareParameters(status, toscaElementId))
101 verticesMap.get(toscaElementId),
102 verticesMap.get(ownerId),
103 verticesMap.get(modifierId),
104 LifecycleStateEnum.NOT_CERTIFIED_CHECKIN
105 ).left().bind(checkinResult -> {
106 //We retrieve the operation
107 ToscaElementOperation operation =
108 getToscaElementOperation(verticesMap.get(toscaElementId).getLabel());
110 //We retrieve the ToscaElement from the operation
111 return getToscaElementFromOperation(operation, checkinResult.getUniqueId(), toscaElementId);
114 } catch (Exception e) {
115 CommonUtility.addRecordToLog(
116 log, LogLevelEnum.DEBUG, "Exception occurred during checkin of tosca element {}. {} ", toscaElementId,
118 return Either.right(StorageOperationStatus.GENERAL_ERROR);
122 static StorageOperationStatus handleFailureToPrepareParameters(final JanusGraphOperationStatus status, final String toscaElementId) {
123 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId);
124 return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status);
127 static Either<ToscaElement, StorageOperationStatus> getToscaElementFromOperation(final ToscaElementOperation operation,
128 final String uniqueId, final String toscaElementId) {
129 return operation.getToscaElement(uniqueId)
130 .right().map(status -> {
131 //We log a potential error we got while retrieving the ToscaElement
133 .addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to get updated tosca element {}. Status is {}",
134 toscaElementId, status);
140 * Returns vertex presenting owner of tosca element specified by uniqueId
142 * @param toscaElementId
145 public Either<User, StorageOperationStatus> getToscaElementOwner(String toscaElementId) {
146 Either<User, StorageOperationStatus> result = null;
147 GraphVertex toscaElement = null;
148 Either<GraphVertex, JanusGraphOperationStatus> getToscaElementRes = janusGraphDao
149 .getVertexById(toscaElementId, JsonParseFlagEnum.NoParse);
150 if (getToscaElementRes.isRight()) {
151 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(getToscaElementRes.right().value()));
153 if (result == null) {
154 toscaElement = getToscaElementRes.left().value();
155 Iterator<Vertex> vertices = toscaElement.getVertex().vertices(Direction.IN, EdgeLabelEnum.STATE.name());
156 if (vertices == null || !vertices.hasNext()) {
157 result = Either.right(StorageOperationStatus.NOT_FOUND);
159 result = Either.left(convertToUser(vertices.next()));
166 * Returns vertex presenting owner of tosca element specified by uniqueId
168 * @param toscaElement
171 public Either<User, StorageOperationStatus> getToscaElementOwner(GraphVertex toscaElement) {
172 Either<User, StorageOperationStatus> result = null;
173 Iterator<Vertex> vertices = toscaElement.getVertex().vertices(Direction.IN, EdgeLabelEnum.STATE.name());
174 if (vertices == null || !vertices.hasNext()) {
175 result = Either.right(StorageOperationStatus.NOT_FOUND);
177 result = Either.left(convertToUser(vertices.next()));
183 * Performs checkout of a tosca element
185 * @param toscaElementId
190 public Either<ToscaElement, StorageOperationStatus> checkoutToscaElement(String toscaElementId, String modifierId, String ownerId) {
191 Either<ToscaElement, StorageOperationStatus> result = null;
192 Map<String, GraphVertex> vertices = null;
194 Either<Map<String, GraphVertex>, JanusGraphOperationStatus> getVerticesRes = janusGraphDao
195 .getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForCheckout(toscaElementId, modifierId, ownerId));
196 if (getVerticesRes.isRight()) {
197 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId);
198 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(getVerticesRes.right().value()));
200 if (result == null) {
201 vertices = getVerticesRes.left().value();
202 // update previous component if not certified
203 StorageOperationStatus status = updatePreviousVersion(vertices.get(toscaElementId), vertices.get(ownerId));
204 if (status != StorageOperationStatus.OK) {
205 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update vertex with id {} . Status is {}. ", status);
206 result = Either.right(status);
209 if (result == null) {
210 result = cloneToscaElementForCheckout(vertices.get(toscaElementId), vertices.get(modifierId));
211 if (result.isRight()) {
212 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to checkout tosca element {}. Status is {} ", toscaElementId, result.right().value());
216 } catch (Exception e) {
217 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Exception occured during checkout tosca element {}. {}", toscaElementId, e.getMessage());
223 * Performs undo checkout for tosca element
225 * @param toscaElementId
228 public Either<ToscaElement, StorageOperationStatus> undoCheckout(String toscaElementId) {
230 return janusGraphDao.getVertexById(toscaElementId, JsonParseFlagEnum.ParseMetadata)
231 .right().map(errorStatus -> {
232 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId);
233 return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(errorStatus);
235 .left().bind(this::retrieveAndUpdatePreviousVersion)
236 .left().bind(this::updateEdgeToCatalogRootAndReturnPreVersionElement);
237 } catch (Exception e) {
238 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Exception occurred during undo checkout tosca element {}. {}", toscaElementId, e.getMessage());
243 private Either<P2<GraphVertex, JanusGraphVertex>, StorageOperationStatus> retrieveAndUpdatePreviousVersion(
244 final GraphVertex currVersionV) {
245 if (!hasPreviousVersion(currVersionV)) {
246 return Either.left(p(currVersionV, null));
248 // find previous version
249 Iterator<Edge> nextVersionComponentIter = currVersionV.getVertex()
250 .edges(Direction.IN, EdgeLabelEnum.VERSION.name());
252 if (nextVersionComponentIter == null || !nextVersionComponentIter.hasNext()) {
253 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG,
254 "Failed to fetch previous version of tosca element with name {}. ",
255 currVersionV.getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME).toString());
256 return Either.right(StorageOperationStatus.NOT_FOUND);
258 Vertex preVersionVertex = nextVersionComponentIter.next().outVertex();
259 StorageOperationStatus updateOldResourceResult = updateOldToscaElementBeforeUndoCheckout(
261 if (updateOldResourceResult != StorageOperationStatus.OK) {
262 return Either.right(updateOldResourceResult);
264 P2<GraphVertex, JanusGraphVertex> result = p(currVersionV, (JanusGraphVertex) preVersionVertex);
266 return Either.left(result);
272 private Either<ToscaElement, StorageOperationStatus> updateEdgeToCatalogRootAndReturnPreVersionElement(
273 final P2<GraphVertex, JanusGraphVertex> tuple) {
275 final GraphVertex currVersionV = tuple._1();
276 final JanusGraphVertex preVersionVertex = tuple._2();
278 StorageOperationStatus updateCatalogRes = updateEdgeToCatalogRootByUndoCheckout(preVersionVertex, currVersionV);
279 if (updateCatalogRes != StorageOperationStatus.OK) {
280 return Either.right(updateCatalogRes);
282 final ToscaElementOperation operation = getToscaElementOperation(currVersionV.getLabel());
284 return operation.deleteToscaElement(currVersionV)
285 .left().bind(discarded -> getUpdatedPreVersionElement(operation, preVersionVertex));
289 private Either<ToscaElement, StorageOperationStatus> getUpdatedPreVersionElement(
290 final ToscaElementOperation operation,
291 final JanusGraphVertex preVersionVertex) {
293 if (preVersionVertex == null) {
294 return Either.left(null);
296 String uniqueIdPreVer = (String) janusGraphDao
297 .getProperty(preVersionVertex, GraphPropertyEnum.UNIQUE_ID.getProperty());
298 return operation.getToscaElement(uniqueIdPreVer);
302 private boolean hasPreviousVersion(GraphVertex toscaElementVertex) {
303 boolean hasPreviousVersion = true;
304 String version = (String) toscaElementVertex.getMetadataProperty(GraphPropertyEnum.VERSION);
305 if (StringUtils.isEmpty(version) || "0.1".equals(version))
306 hasPreviousVersion = false;
307 return hasPreviousVersion;
310 public Either<ToscaElement, StorageOperationStatus> certifyToscaElement(
311 String toscaElementId,
316 .getVerticesByUniqueIdAndParseFlag(
317 prepareParametersToGetVerticesForRequestCertification(toscaElementId, modifierId, ownerId))
318 .right().map(status ->
319 logDebugMessageAndReturnStorageOperationStatus(
320 DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status),
321 FAILED_TO_GET_VERTICES,
323 .left().bind(verticesRes -> {
324 GraphVertex toscaElement = verticesRes.get(toscaElementId);
325 GraphVertex modifier = verticesRes.get(modifierId);
326 Integer majorVersion = getMajorVersion(
327 (String) toscaElement.getMetadataProperty(GraphPropertyEnum.VERSION));
329 return handleRelationsBeforeCertifyingAndProcessClone(toscaElement,
330 modifier, majorVersion);
332 } catch (Exception e) {
334 logDebugMessageAndReturnStorageOperationStatus(StorageOperationStatus.GENERAL_ERROR,
335 "Exception occurred during certification tosca element {}.",
341 private Either<ToscaElement, StorageOperationStatus> handleRelationsBeforeCertifyingAndProcessClone(
342 GraphVertex toscaElement,
343 GraphVertex modifier,
344 Integer majorVersion) {
345 StorageOperationStatus status = handleRelationsOfPreviousToscaElementBeforeCertifying(toscaElement,
346 modifier, majorVersion);
347 if (status != StorageOperationStatus.OK) {
349 logDebugMessageAndReturnStorageOperationStatus(status,
350 "Failed to handle relations of previous tosca element before certifying {}. Status is {}. ",
351 toscaElement.getUniqueId(), status));
353 return cloneToscaElementAndHandleRelations(toscaElement, modifier, majorVersion);
357 private Either<ToscaElement, StorageOperationStatus> cloneToscaElementAndHandleRelations(
358 GraphVertex toscaElement,
359 GraphVertex modifier,
360 Integer majorVersion) {
361 return cloneToscaElementForCertify(toscaElement, modifier, majorVersion)
362 .right().map(status -> logDebugMessageAndReturnStorageOperationStatus(status,
363 "Failed to clone tosca element during certification. "))
364 .left().bind(certifiedToscaElement ->
365 handleRelationsOfNewestCertifiedToscaElementAndReturn(toscaElement, certifiedToscaElement));
368 private Either<ToscaElement, StorageOperationStatus> handleRelationsOfNewestCertifiedToscaElementAndReturn(
369 GraphVertex toscaElement,
370 GraphVertex certifiedToscaElement) {
371 StorageOperationStatus status = handleRelationsOfNewestCertifiedToscaElement(toscaElement,
372 certifiedToscaElement);
373 if (status != StorageOperationStatus.OK) {
375 logDebugMessageAndReturnStorageOperationStatus(status,
376 "Failed to handle relations of newest certified tosca element {}. Status is {}. ",
377 certifiedToscaElement.getUniqueId(), status));
379 return getToscaElementOperation(toscaElement.getLabel())
380 .getToscaElement(certifiedToscaElement.getUniqueId());
384 private static StorageOperationStatus logDebugMessageAndReturnStorageOperationStatus(
385 final StorageOperationStatus status,
387 final Object... args) {
388 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, msg, args);
392 private StorageOperationStatus handleRelationsOfNewestCertifiedToscaElement(GraphVertex toscaElement, GraphVertex certifiedToscaElement) {
394 JanusGraphOperationStatus createVersionEdgeStatus = janusGraphDao.createEdge(toscaElement, certifiedToscaElement, EdgeLabelEnum.VERSION, new HashMap<>());
395 if (createVersionEdgeStatus != JanusGraphOperationStatus.OK) {
396 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to create version edge from last element {} to new certified element {}. status=", toscaElement.getUniqueId(), certifiedToscaElement.getUniqueId(),
397 createVersionEdgeStatus);
398 return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(createVersionEdgeStatus);
400 return StorageOperationStatus.OK;
403 public Either<GraphVertex, JanusGraphOperationStatus> findUser(String userId) {
404 return findUserVertex(userId);
407 private Either<Boolean, StorageOperationStatus> markToscaElementsAsDeleted(ToscaElementOperation operation, List<GraphVertex> toscaElements) {
408 Either<Boolean, StorageOperationStatus> result = Either.left(true);
409 for (GraphVertex resourceToDelete : toscaElements) {
410 if (!(resourceToDelete.getJsonMetadataField(JsonPresentationFields.LIFECYCLE_STATE)).equals(LifecycleStateEnum.CERTIFIED.name())) {
411 Either<GraphVertex, StorageOperationStatus> deleteElementRes = operation.markComponentToDelete(resourceToDelete);
412 if (deleteElementRes.isRight()) {
413 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to delete tosca element {}. Status is {}. ", resourceToDelete.getUniqueId(), deleteElementRes.right().value());
414 result = Either.right(deleteElementRes.right().value());
422 private StorageOperationStatus handleRelationsOfPreviousToscaElementBeforeCertifying(GraphVertex toscaElement, GraphVertex modifier, Integer majorVersion) {
423 StorageOperationStatus result = null;
424 if (majorVersion > 0) {
425 Either<Vertex, StorageOperationStatus> findRes = findLastCertifiedToscaElementVertex(toscaElement);
426 if (findRes.isRight()) {
427 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to fetch last certified tosca element {} . Status is {}. ", toscaElement.getMetadataProperty(GraphPropertyEnum.NAME), findRes.right().value());
428 result = findRes.right().value();
430 if (result == null) {
431 Vertex lastCertifiedVertex = findRes.left().value();
432 Map<GraphPropertyEnum, Object> properties = new EnumMap<>(GraphPropertyEnum.class);
433 properties.put(GraphPropertyEnum.IS_HIGHEST_VERSION, false);
434 JanusGraphOperationStatus status = janusGraphDao
435 .updateVertexMetadataPropertiesWithJson(lastCertifiedVertex, properties);
436 if (status != JanusGraphOperationStatus.OK) {
437 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to set highest version of tosca element {} to [{}]. Status is {}", toscaElement.getUniqueId(), false, status);
438 result = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status);
440 // remove previous certified version from the catalog
441 GraphVertex lastCertifiedV = new GraphVertex();
442 lastCertifiedV.setVertex((JanusGraphVertex) lastCertifiedVertex);
443 lastCertifiedV.setUniqueId((String) janusGraphDao
444 .getProperty((JanusGraphVertex) lastCertifiedVertex, GraphPropertyEnum.UNIQUE_ID.getProperty()));
445 lastCertifiedV.addMetadataProperty(GraphPropertyEnum.IS_ABSTRACT,
446 (Boolean) janusGraphDao.getProperty((JanusGraphVertex) lastCertifiedVertex, GraphPropertyEnum.IS_ABSTRACT.getProperty()));
447 StorageOperationStatus res = updateEdgeToCatalogRoot(null, lastCertifiedV);
448 if (res != StorageOperationStatus.OK) {
453 if (result == null) {
454 result = StorageOperationStatus.OK;
459 private Either<Vertex, StorageOperationStatus> findLastCertifiedToscaElementVertex(GraphVertex toscaElement) {
460 return findLastCertifiedToscaElementVertexRecursively(toscaElement.getVertex());
463 private Either<Vertex, StorageOperationStatus> findLastCertifiedToscaElementVertexRecursively(Vertex vertex) {
464 if (isCertifiedVersion((String) vertex.property(GraphPropertyEnum.VERSION.getProperty()).value())) {
465 return Either.left(vertex);
467 Iterator<Edge> edgeIter = vertex.edges(Direction.IN, EdgeLabelEnum.VERSION.name());
468 if (!edgeIter.hasNext()) {
469 return Either.right(StorageOperationStatus.NOT_FOUND);
471 return findLastCertifiedToscaElementVertexRecursively(edgeIter.next().outVertex());
474 private boolean isCertifiedVersion(String version) {
475 String[] versionParts = version.split(VERSION_DELIMITER_REGEXP);
476 if (Integer.parseInt(versionParts[0]) > 0 && Integer.parseInt(versionParts[1]) == 0) {
482 private StorageOperationStatus updateOldToscaElementBeforeUndoCheckout(Vertex previousVersionToscaElement) {
484 StorageOperationStatus result = StorageOperationStatus.OK;
485 String previousVersion = (String) previousVersionToscaElement.property(GraphPropertyEnum.VERSION.getProperty()).value();
486 if (!previousVersion.endsWith(".0")) {
488 CommonUtility.addRecordToLog(log, LogLevelEnum.TRACE, "Going to update vertex of previous version of tosca element", previousVersionToscaElement.property(GraphPropertyEnum.NORMALIZED_NAME.getProperty()));
490 Map<String, Object> propertiesToUpdate = new HashMap<>();
491 propertiesToUpdate.put(GraphPropertyEnum.IS_HIGHEST_VERSION.getProperty(), true);
492 Map<String, Object> jsonMetadataMap = JsonParserUtils.toMap((String) previousVersionToscaElement.property(GraphPropertyEnum.METADATA.getProperty()).value());
493 jsonMetadataMap.put(GraphPropertyEnum.IS_HIGHEST_VERSION.getProperty(), true);
494 propertiesToUpdate.put(GraphPropertyEnum.METADATA.getProperty(), JsonParserUtils.toJson(jsonMetadataMap));
496 janusGraphDao.setVertexProperties(previousVersionToscaElement, propertiesToUpdate);
498 Iterator<Edge> edgesIter = previousVersionToscaElement.edges(Direction.IN, EdgeLabelEnum.LAST_STATE.name());
499 if (!edgesIter.hasNext()) {
500 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to fetch last modifier vertex for tosca element {}. ", previousVersionToscaElement.property(GraphPropertyEnum.NORMALIZED_NAME.getProperty()));
501 result = StorageOperationStatus.NOT_FOUND;
503 Edge lastStateEdge = edgesIter.next();
504 Vertex lastModifier = lastStateEdge.outVertex();
505 JanusGraphOperationStatus replaceRes = janusGraphDao
506 .replaceEdgeLabel(lastModifier, previousVersionToscaElement, lastStateEdge, EdgeLabelEnum.LAST_STATE, EdgeLabelEnum.STATE);
507 if (replaceRes != JanusGraphOperationStatus.OK) {
508 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to replace label from {} to {}. status = {}", EdgeLabelEnum.LAST_STATE, EdgeLabelEnum.STATE, replaceRes);
509 result = StorageOperationStatus.INCONSISTENCY;
510 if (replaceRes != JanusGraphOperationStatus.INVALID_ID) {
511 result = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(replaceRes);
516 } catch (Exception e) {
517 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Exception occured during update previous tosca element {} before undo checkout. {} ", e.getMessage());
523 private StorageOperationStatus updatePreviousVersion(GraphVertex toscaElementVertex, GraphVertex ownerVertex) {
524 StorageOperationStatus result = null;
525 String ownerId = (String) ownerVertex.getMetadataProperty(GraphPropertyEnum.USERID);
526 String toscaElementId = toscaElementVertex.getUniqueId();
527 if (!toscaElementVertex.getMetadataProperty(GraphPropertyEnum.STATE).equals(LifecycleStateEnum.CERTIFIED.name())) {
528 toscaElementVertex.addMetadataProperty(GraphPropertyEnum.IS_HIGHEST_VERSION, false);
529 Either<GraphVertex, JanusGraphOperationStatus> updateVertexRes = janusGraphDao.updateVertex(toscaElementVertex);
530 if (updateVertexRes.isRight()) {
531 JanusGraphOperationStatus titatStatus = updateVertexRes.right().value();
532 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update tosca element vertex {}. Status is {}", toscaElementVertex.getUniqueId(), titatStatus);
533 result = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(titatStatus);
535 Either<Edge, JanusGraphOperationStatus> deleteEdgeRes = null;
536 if (result == null) {
537 CommonUtility.addRecordToLog(log, LogLevelEnum.TRACE, "Going to replace edge with label {} to label {} from {} to {}. ", EdgeLabelEnum.STATE, EdgeLabelEnum.LAST_STATE, ownerId, toscaElementId);
539 deleteEdgeRes = janusGraphDao
540 .deleteEdge(ownerVertex, toscaElementVertex, EdgeLabelEnum.STATE);
541 if (deleteEdgeRes.isRight()) {
542 JanusGraphOperationStatus janusGraphStatus = deleteEdgeRes.right().value();
543 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to delete edge with label {} from {} to {}. Status is {} ", EdgeLabelEnum.STATE, EdgeLabelEnum.LAST_STATE, ownerId, toscaElementId, janusGraphStatus);
544 if (!janusGraphStatus.equals(JanusGraphOperationStatus.INVALID_ID)) {
545 result = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(janusGraphStatus);
547 result = StorageOperationStatus.INCONSISTENCY;
551 if (result == null) {
552 JanusGraphOperationStatus
553 createEdgeRes = janusGraphDao
554 .createEdge(ownerVertex.getVertex(), toscaElementVertex.getVertex(), EdgeLabelEnum.LAST_STATE, deleteEdgeRes.left().value());
555 if (createEdgeRes != JanusGraphOperationStatus.OK) {
556 result = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(createEdgeRes);
560 if (result == null) {
561 result = StorageOperationStatus.OK;
566 private Either<ToscaElement, StorageOperationStatus> cloneToscaElementForCheckout(GraphVertex toscaElementVertex, GraphVertex modifierVertex) {
568 Either<ToscaElement, StorageOperationStatus> result = null;
569 Either<GraphVertex, StorageOperationStatus> cloneResult = null;
570 ToscaElementOperation operation = getToscaElementOperation(toscaElementVertex.getLabel());
571 // check if component with the next version doesn't exist.
572 Iterator<Edge> nextVersionComponentIter = toscaElementVertex.getVertex().edges(Direction.OUT, EdgeLabelEnum.VERSION.name());
573 if (nextVersionComponentIter != null && nextVersionComponentIter.hasNext()) {
574 Vertex nextVersionVertex = nextVersionComponentIter.next().inVertex();
575 String fetchedVersion = (String) nextVersionVertex.property(GraphPropertyEnum.VERSION.getProperty()).value();
576 String fetchedName = (String) nextVersionVertex.property(GraphPropertyEnum.NORMALIZED_NAME.getProperty()).value();
577 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to checkout component {} with version {}. The component with name {} and version {} was fetched from graph as existing following version. ",
578 toscaElementVertex.getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME).toString(), toscaElementVertex.getMetadataProperty(GraphPropertyEnum.VERSION).toString(), fetchedName, fetchedVersion);
579 result = Either.right(StorageOperationStatus.ENTITY_ALREADY_EXISTS);
581 if (result == null) {
582 toscaElementVertex.getOrSetDefaultInstantiationTypeForToscaElementJson();
583 cloneResult = operation.cloneToscaElement(toscaElementVertex, cloneGraphVertexForCheckout(toscaElementVertex, modifierVertex), modifierVertex);
584 if (cloneResult.isRight()) {
585 result = Either.right(cloneResult.right().value());
588 GraphVertex clonedVertex = null;
589 if (result == null) {
590 clonedVertex = cloneResult.left().value();
591 JanusGraphOperationStatus
592 status = janusGraphDao
593 .createEdge(toscaElementVertex.getVertex(), cloneResult.left().value().getVertex(), EdgeLabelEnum.VERSION, new HashMap<>());
594 if (status != JanusGraphOperationStatus.OK) {
595 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to create edge with label {} from vertex {} to tosca element vertex {} on graph. Status is {}. ", EdgeLabelEnum.VERSION,
596 toscaElementVertex.getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME), cloneResult.left().value().getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME), status);
597 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
600 if (result == null) {
601 Boolean isHighest = (Boolean) toscaElementVertex.getMetadataProperty(GraphPropertyEnum.IS_HIGHEST_VERSION);
602 GraphVertex prevVersionInCatalog = (isHighest != null && isHighest) ? null : toscaElementVertex;
603 StorageOperationStatus updateCatalogRes = updateEdgeToCatalogRoot(clonedVertex, prevVersionInCatalog);
604 if (updateCatalogRes != StorageOperationStatus.OK) {
605 return Either.right(updateCatalogRes);
607 result = operation.getToscaElement(cloneResult.left().value().getUniqueId());
608 if (result.isRight()) {
611 ToscaElement toscaElement = result.left().value();
612 if (toscaElement.getToscaType() == ToscaElementTypeEnum.TOPOLOGY_TEMPLATE) {
613 result = handleFixTopologyTemplate(toscaElementVertex, result, operation, clonedVertex, toscaElement);
620 private Either<ToscaElement, StorageOperationStatus> handleFixTopologyTemplate(GraphVertex toscaElementVertex, Either<ToscaElement, StorageOperationStatus> result, ToscaElementOperation operation, GraphVertex clonedVertex,
621 ToscaElement toscaElement) {
622 TopologyTemplate topologyTemplate = (TopologyTemplate) toscaElement;
623 Map<String, MapPropertiesDataDefinition> instInputs = topologyTemplate.getInstInputs();
624 Map<String, MapGroupsDataDefinition> instGroups = topologyTemplate.getInstGroups();
625 Map<String, MapArtifactDataDefinition> instArtifactsMap = topologyTemplate.getInstanceArtifacts();
626 Map<String, ToscaElement> origCompMap = new HashMap<>();
627 if (instInputs == null) {
628 instInputs = new HashMap<>();
630 if (instGroups == null) {
631 instGroups = new HashMap<>();
633 if (instArtifactsMap == null) {
634 instArtifactsMap = new HashMap<>();
636 Map<String, ComponentInstanceDataDefinition> instancesMap = topologyTemplate.getComponentInstances();
637 boolean isAddInstGroup = instGroups == null || instGroups.isEmpty();
638 boolean needUpdateComposition = false;
640 if (instancesMap != null && !instancesMap.isEmpty()) {
641 for (ComponentInstanceDataDefinition vfInst : instancesMap.values()) {
642 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "vfInst name is {} . OriginType {}. ", vfInst.getName(), vfInst.getOriginType());
643 if (vfInst.getOriginType().name().equals(OriginTypeEnum.VF.name())) {
644 collectInstanceInputAndGroups(instInputs, instGroups, instArtifactsMap, origCompMap, isAddInstGroup, vfInst, clonedVertex);
646 needUpdateComposition = needUpdateComposition || fixToscaComponentName(vfInst, origCompMap);
647 if (needUpdateComposition) {
648 instancesMap.put(vfInst.getUniqueId(), vfInst);
651 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "before add to graph instInputs {} instGroups {} needUpdateComposition {}", instInputs, instGroups, needUpdateComposition);
652 if (!instInputs.isEmpty()) {
653 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "before add inst inputs {} ", instInputs == null ? 0 : instInputs.size());
654 GraphVertex toscaDataVertex = null;
655 Either<GraphVertex, JanusGraphOperationStatus> instInpVertexEither = janusGraphDao
656 .getChildVertex(toscaElementVertex, EdgeLabelEnum.INST_INPUTS, JsonParseFlagEnum.ParseJson);
657 if (instInpVertexEither.isLeft()) {
658 toscaDataVertex = instInpVertexEither.left().value();
661 StorageOperationStatus status = handleToscaData(clonedVertex, VertexTypeEnum.INST_INPUTS, EdgeLabelEnum.INST_INPUTS, toscaDataVertex, instInputs);
662 if (status != StorageOperationStatus.OK) {
663 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update instance inputs . Status is {}. ", status);
664 result = Either.right(status);
669 if (!instGroups.isEmpty()) {
670 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "before add inst groups {} ", instGroups == null ? 0 : instGroups.size());
671 GraphVertex toscaDataVertex = null;
672 Either<GraphVertex, JanusGraphOperationStatus> instGrVertexEither = janusGraphDao
673 .getChildVertex(toscaElementVertex, EdgeLabelEnum.INST_GROUPS, JsonParseFlagEnum.ParseJson);
674 if (instGrVertexEither.isLeft()) {
675 toscaDataVertex = instGrVertexEither.left().value();
678 StorageOperationStatus status = handleToscaData(clonedVertex, VertexTypeEnum.INST_GROUPS, EdgeLabelEnum.INST_GROUPS, toscaDataVertex, instGroups);
679 if (status != StorageOperationStatus.OK) {
680 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update instance group . Status is {}. ", status);
681 result = Either.right(status);
686 if (needUpdateComposition) {
687 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "before update Instances ");
688 Map<String, CompositionDataDefinition> jsonComposition = (Map<String, CompositionDataDefinition>) clonedVertex.getJson();
689 CompositionDataDefinition compositionDataDefinition = jsonComposition.get(JsonConstantKeysEnum.COMPOSITION.getValue());
690 compositionDataDefinition.setComponentInstances(instancesMap);
691 Either<GraphVertex, JanusGraphOperationStatus> updateElement = janusGraphDao.updateVertex(clonedVertex);
692 if (updateElement.isRight()) {
693 JanusGraphOperationStatus status = updateElement.right().value();
694 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update instances on metadata vertex . Status is {}. ", status);
695 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
700 result = operation.getToscaElement(clonedVertex.getUniqueId());
703 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "RI map empty on component {}", toscaElement.getUniqueId());
708 // TODO remove after jsonModelMigration
709 public boolean resolveToscaComponentName(ComponentInstanceDataDefinition vfInst, Map<String, ToscaElement> origCompMap) {
710 return fixToscaComponentName(vfInst, origCompMap);
713 private boolean fixToscaComponentName(ComponentInstanceDataDefinition vfInst, Map<String, ToscaElement> origCompMap) {
714 if (vfInst.getToscaComponentName() == null || vfInst.getToscaComponentName().isEmpty()) {
715 String ciUid = vfInst.getUniqueId();
716 String origCompUid = vfInst.getComponentUid();
717 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "fixToscaComponentName:: Ri id {} . origin component id is {}. type is{} ", ciUid, origCompUid, vfInst.getOriginType());
718 ToscaElement origComp = null;
719 if (!origCompMap.containsKey(origCompUid)) {
720 Either<ToscaElement, StorageOperationStatus> origCompEither;
721 if (vfInst.getOriginType() == null || vfInst.getOriginType().name().equals(OriginTypeEnum.VF.name())) {
722 origCompEither = topologyTemplateOperation.getToscaElement(origCompUid);
724 origCompEither = nodeTypeOperation.getToscaElement(origCompUid);
726 if (origCompEither.isRight()) {
727 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to find orig component {} . Status is {}. ", origCompEither.right().value());
730 origComp = origCompEither.left().value();
731 origCompMap.put(origCompUid, origComp);
733 origComp = origCompMap.get(origCompUid);
735 String toscaName = (String) origComp.getMetadataValue(JsonPresentationFields.TOSCA_RESOURCE_NAME);
736 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Origin component id is {}. toscaName {}", origCompUid, toscaName);
737 vfInst.setToscaComponentName(toscaName);
743 private void collectInstanceInputAndGroups(Map<String, MapPropertiesDataDefinition> instInputs, Map<String, MapGroupsDataDefinition> instGroups, Map<String, MapArtifactDataDefinition> instArtifactsMap, Map<String, ToscaElement> origCompMap,
744 boolean isAddInstGroup, ComponentInstanceDataDefinition vfInst, GraphVertex clonedVertex) {
745 String ciUid = vfInst.getUniqueId();
746 String origCompUid = vfInst.getComponentUid();
747 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "collectInstanceInputAndGroups:: Ri id {} . origin component id is {}. ", ciUid, origCompUid);
748 TopologyTemplate origComp = null;
749 if (!origCompMap.containsKey(origCompUid)) {
750 Either<ToscaElement, StorageOperationStatus> origCompEither = topologyTemplateOperation.getToscaElement(origCompUid);
751 if (origCompEither.isRight()) {
752 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to find orig component {} . Status is {}. ", origCompEither.right().value());
755 origComp = (TopologyTemplate) origCompEither.left().value();
756 origCompMap.put(origCompUid, origComp);
758 origComp = (TopologyTemplate) origCompMap.get(origCompUid);
760 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Orig component {}. ", origComp.getUniqueId());
762 Map<String, PropertyDataDefinition> origInputs = origComp.getInputs();
763 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Orig component inputs size {}. ", origInputs == null ? 0 : origInputs.size());
764 if (origInputs != null) {
765 if (!instInputs.containsKey(ciUid)) {
766 MapPropertiesDataDefinition instProperties = new MapPropertiesDataDefinition(origInputs);
767 instInputs.put(ciUid, instProperties);
770 MapPropertiesDataDefinition instInputMap = instInputs.get(ciUid);
771 Map<String, PropertyDataDefinition> instProp = instInputMap.getMapToscaDataDefinition();
772 origInputs.forEach((propName, propMap) -> {
773 if (!instProp.containsKey(propName)) {
774 instProp.put(propName, propMap);
778 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "ComponentInstanseInputs {}. ", instInputs.get(ciUid));
781 if (isAddInstGroup) {
782 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "before create group instance. ");
783 List<GroupDataDefinition> filteredGroups = null;
785 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "check vf groups before filter. Size is {} ", filteredGroups == null ? 0 : filteredGroups.size());
786 if (origComp.getGroups() != null && !origComp.getGroups().isEmpty()) {
787 filteredGroups = origComp.getGroups().values().stream().filter(g -> g.getType().equals(VF_MODULE)).collect(Collectors.toList());
788 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "check vf groups . Size is {} ", filteredGroups == null ? 0 : filteredGroups.size());
790 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "check vf groups after filter. Size is {} ", filteredGroups == null ? 0 : filteredGroups.size());
791 if (CollectionUtils.isNotEmpty(filteredGroups)) {
792 MapArtifactDataDefinition instArifacts = null;
793 if (!instArtifactsMap.containsKey(ciUid)) {
795 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "istance artifacts not found ");
797 Map<String, ArtifactDataDefinition> deploymentArtifacts = origComp.getDeploymentArtifacts();
799 instArifacts = new MapArtifactDataDefinition(deploymentArtifacts);
800 addToscaDataDeepElementsBlockToToscaElement(clonedVertex, EdgeLabelEnum.INST_DEPLOYMENT_ARTIFACTS, VertexTypeEnum.INST_DEPLOYMENT_ARTIFACTS, instArifacts, ciUid);
802 instArtifactsMap.put(ciUid, instArifacts);
805 instArifacts = instArtifactsMap.get(ciUid);
808 if (instArifacts != null) {
809 Map<String, ArtifactDataDefinition> instDeplArtifMap = instArifacts.getMapToscaDataDefinition();
811 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "check group dep artifacts. Size is {} ", instDeplArtifMap == null ? 0 : instDeplArtifMap.values().size());
812 Map<String, GroupInstanceDataDefinition> groupInstanceToCreate = new HashMap<>();
813 for (GroupDataDefinition group : filteredGroups) {
814 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "create new groupInstance {} ", group.getName());
815 GroupInstanceDataDefinition groupInstance = buildGroupInstanceDataDefinition(group, vfInst, instDeplArtifMap);
816 List<String> artifactsUid = new ArrayList<>();
817 List<String> artifactsId = new ArrayList<>();
818 if (instDeplArtifMap!=null) {
819 for (ArtifactDataDefinition artifact : instDeplArtifMap.values()) {
820 Optional<String> op = group.getArtifacts().stream().filter(p -> p.equals(artifact.getGeneratedFromId())).findAny();
821 if (op.isPresent()) {
822 artifactsUid.add(artifact.getArtifactUUID());
823 artifactsId.add(artifact.getUniqueId());
828 groupInstance.setGroupInstanceArtifacts(artifactsId);
829 groupInstance.setGroupInstanceArtifactsUuid(artifactsUid);
830 groupInstanceToCreate.put(groupInstance.getName(), groupInstance);
832 if (MapUtils.isNotEmpty(groupInstanceToCreate)) {
833 instGroups.put(vfInst.getUniqueId(), new MapGroupsDataDefinition(groupInstanceToCreate));
841 private GraphVertex cloneGraphVertexForCheckout(GraphVertex toscaElementVertex, GraphVertex modifierVertex) {
842 GraphVertex nextVersionToscaElementVertex = new GraphVertex();
843 String uniqueId = UniqueIdBuilder.buildComponentUniqueId();
844 Map<GraphPropertyEnum, Object> metadataProperties = new HashMap<>(toscaElementVertex.getMetadataProperties());
845 nextVersionToscaElementVertex.setMetadataProperties(metadataProperties);
846 nextVersionToscaElementVertex.setUniqueId(uniqueId);
847 nextVersionToscaElementVertex.setLabel(toscaElementVertex.getLabel());
848 nextVersionToscaElementVertex.setType(toscaElementVertex.getType());
850 nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.UNIQUE_ID, uniqueId);
851 nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.COMPONENT_TYPE, nextVersionToscaElementVertex.getType().name());
852 String nextVersion = getNextVersion((String) toscaElementVertex.getMetadataProperty(GraphPropertyEnum.VERSION));
853 if (isFirstCheckoutAfterCertification(nextVersion)) {
854 nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.UUID, IdBuilderUtils.generateUUID());
856 nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.VERSION, nextVersion);
857 nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name());
858 nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.IS_HIGHEST_VERSION, true);
860 if (toscaElementVertex.getType() == ComponentTypeEnum.SERVICE) {
861 nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.DISTRIBUTION_STATUS, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name());
863 if (!MapUtils.isEmpty(toscaElementVertex.getMetadataJson())) {
864 nextVersionToscaElementVertex.setMetadataJson(new HashMap<>(toscaElementVertex.getMetadataJson()));
865 nextVersionToscaElementVertex.updateMetadataJsonWithCurrentMetadataProperties();
867 long currTime = System.currentTimeMillis();
868 nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.CREATION_DATE, currTime);
869 nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, currTime);
870 nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.USER_ID_CREATOR, modifierVertex.getUniqueId());
871 nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.USER_ID_LAST_UPDATER, modifierVertex.getUniqueId());
872 if (toscaElementVertex.getType() == ComponentTypeEnum.SERVICE) {
873 nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.CONFORMANCE_LEVEL, ConfigurationManager.getConfigurationManager().getConfiguration().getToscaConformanceLevel());
876 if (!MapUtils.isEmpty(toscaElementVertex.getJson())) {
877 nextVersionToscaElementVertex.setJson(new HashMap<String, ToscaDataDefinition>(toscaElementVertex.getJson()));
879 return nextVersionToscaElementVertex;
882 private Either<GraphVertex, StorageOperationStatus> cloneToscaElementForCertify(GraphVertex toscaElementVertex,
883 GraphVertex modifierVertex, Integer majorVersion) {
884 return getToscaElementOperation(toscaElementVertex.getLabel())
887 cloneGraphVertexForCertify(toscaElementVertex, modifierVertex, majorVersion),
889 .right().map(status ->
890 logDebugMessageAndReturnStorageOperationStatus(status,
891 "Failed to clone tosca element {} for certification. Status is {}. ",
892 toscaElementVertex.getUniqueId(), status))
893 .left().bind(clonedToscaElement ->
894 updateEdgesDeleteNotCertifiedVersionsAndHandlePreviousVersions(
895 clonedToscaElement, toscaElementVertex, majorVersion
899 private Either<GraphVertex, StorageOperationStatus> updateEdgesDeleteNotCertifiedVersionsAndHandlePreviousVersions(
900 GraphVertex clonedToscaElement,
901 GraphVertex toscaElementVertex,
904 StorageOperationStatus updateEdgeToCatalog = updateEdgeToCatalogRoot(clonedToscaElement, toscaElementVertex);
905 if (updateEdgeToCatalog != StorageOperationStatus.OK) {
906 return Either.right(updateEdgeToCatalog);
908 Either<List<GraphVertex>, StorageOperationStatus> deleteResultEither =
909 deleteAllPreviousNotCertifiedVersions(toscaElementVertex);
911 if (deleteResultEither == null) {
913 logDebugMessageAndReturnStorageOperationStatus(StorageOperationStatus.GENERAL_ERROR,
914 "Failed to delete all previous not certified versions of tosca element {}. Null value returned.",
915 toscaElementVertex.getUniqueId()));
917 return deleteResultEither
918 .right().map(status ->
919 logDebugMessageAndReturnStorageOperationStatus(status,
920 "Failed to delete all previous not certified versions of tosca element {}. Status is {}. ",
921 toscaElementVertex.getUniqueId(), status))
922 .left().bind(deleteResult ->
923 handlePreviousVersionRelation(clonedToscaElement, deleteResult, majorVersion));
928 private Either<GraphVertex, StorageOperationStatus> handlePreviousVersionRelation(GraphVertex clonedToscaElement, List<GraphVertex> deletedVersions, Integer majorVersion) {
929 Either<GraphVertex, StorageOperationStatus> result = null;
930 Vertex previousCertifiedToscaElement = null;
931 if (majorVersion > 0) {
932 List<GraphVertex> firstMinorVersionVertex = deletedVersions.stream().filter(gv -> getMinorVersion((String) gv.getMetadataProperty(GraphPropertyEnum.VERSION)) == 1).collect(Collectors.toList());
934 if (CollectionUtils.isEmpty(firstMinorVersionVertex)) {
935 result = Either.right(StorageOperationStatus.NOT_FOUND);
937 previousCertifiedToscaElement = getPreviousCertifiedToscaElement(firstMinorVersionVertex.get(0));
938 if (previousCertifiedToscaElement == null) {
939 result = Either.right(StorageOperationStatus.NOT_FOUND);
942 if (result == null) {
943 JanusGraphOperationStatus
944 status = janusGraphDao
945 .createEdge(previousCertifiedToscaElement, clonedToscaElement.getVertex(), EdgeLabelEnum.VERSION, new HashMap<>());
946 if (status != JanusGraphOperationStatus.OK) {
947 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to create edge with label {} from vertex {} to tosca element vertex {} on graph. Status is {}. ", EdgeLabelEnum.VERSION,
948 previousCertifiedToscaElement.property(GraphPropertyEnum.UNIQUE_ID.getProperty()), clonedToscaElement.getUniqueId(), status);
949 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
954 if (result == null) {
955 result = Either.left(clonedToscaElement);
960 private Vertex getPreviousCertifiedToscaElement(GraphVertex graphVertex) {
962 Iterator<Edge> edges = graphVertex.getVertex().edges(Direction.IN, EdgeLabelEnum.VERSION.name());
963 if (edges.hasNext()) {
964 return edges.next().outVertex();
969 private Either<List<GraphVertex>, StorageOperationStatus> deleteAllPreviousNotCertifiedVersions(GraphVertex toscaElementVertex) {
970 Either<List<GraphVertex>, StorageOperationStatus> result = null;
972 ToscaElementOperation operation = getToscaElementOperation(toscaElementVertex.getLabel());
973 List<GraphVertex> previosVersions = null;
974 Object uuid = toscaElementVertex.getMetadataProperty(GraphPropertyEnum.UUID);
975 Object componentName = toscaElementVertex.getMetadataProperty(GraphPropertyEnum.NAME);
977 Map<GraphPropertyEnum, Object> properties = new HashMap<>();
978 properties.put(GraphPropertyEnum.UUID, uuid);
979 properties.put(GraphPropertyEnum.NAME, componentName);
980 Either<List<GraphVertex>, JanusGraphOperationStatus> getToscaElementsRes = janusGraphDao
981 .getByCriteria(toscaElementVertex.getLabel(), properties, JsonParseFlagEnum.ParseMetadata);
982 if (getToscaElementsRes.isRight()) {
983 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(getToscaElementsRes.right().value()));
985 if (result == null) {
986 previosVersions = getToscaElementsRes.left().value();
987 Either<Boolean, StorageOperationStatus> deleteResult = markToscaElementsAsDeleted(operation, getToscaElementsRes.left().value());
988 if (deleteResult.isRight()) {
989 result = Either.right(deleteResult.right().value());
992 if (result == null) {
993 result = Either.left(previosVersions);
995 } catch (Exception e) {
996 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Exception occurred during deleting all tosca elements by UUID {} and name {}. {} ", uuid, componentName, e.getMessage());
1001 private GraphVertex cloneGraphVertexForCertify(GraphVertex toscaElementVertex, GraphVertex modifierVertex, Integer majorVersion) {
1003 GraphVertex nextVersionToscaElementVertex = new GraphVertex();
1004 String uniqueId = IdBuilderUtils.generateUniqueId();
1005 Map<GraphPropertyEnum, Object> metadataProperties = new EnumMap<>(toscaElementVertex.getMetadataProperties());
1006 nextVersionToscaElementVertex.setMetadataProperties(metadataProperties);
1007 nextVersionToscaElementVertex.setUniqueId(uniqueId);
1008 nextVersionToscaElementVertex.setLabel(toscaElementVertex.getLabel());
1009 nextVersionToscaElementVertex.setType(toscaElementVertex.getType());
1011 nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.UNIQUE_ID, uniqueId);
1012 nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.COMPONENT_TYPE, nextVersionToscaElementVertex.getType().name());
1013 nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.VERSION, (majorVersion + 1) + VERSION_DELIMITER + "0");
1014 nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.STATE, LifecycleStateEnum.CERTIFIED.name());
1015 nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.IS_HIGHEST_VERSION, true);
1016 nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.CREATION_DATE, System.currentTimeMillis());
1017 nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, null);
1018 nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.USER_ID_CREATOR, modifierVertex.getUniqueId());
1019 nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.USER_ID_LAST_UPDATER, modifierVertex.getUniqueId());
1021 if (toscaElementVertex.getType() == ComponentTypeEnum.SERVICE) {
1022 nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.DISTRIBUTION_STATUS, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name());
1024 if (!MapUtils.isEmpty(toscaElementVertex.getMetadataJson())) {
1025 nextVersionToscaElementVertex.setMetadataJson(new HashMap<>(toscaElementVertex.getMetadataJson()));
1026 nextVersionToscaElementVertex.updateMetadataJsonWithCurrentMetadataProperties();
1028 if (!MapUtils.isEmpty(toscaElementVertex.getJson())) {
1029 nextVersionToscaElementVertex.setJson(new HashMap<String, ToscaDataDefinition>(toscaElementVertex.getJson()));
1031 return nextVersionToscaElementVertex;
1035 private Either<GraphVertex, StorageOperationStatus> checkinToscaELement(LifecycleStateEnum currState, GraphVertex toscaElementVertex, GraphVertex ownerVertex, GraphVertex modifierVertex, LifecycleStateEnum nextState) {
1036 Either<GraphVertex, StorageOperationStatus> updateRelationsRes;
1037 Either<GraphVertex, StorageOperationStatus> result = changeStateToCheckedIn(currState, toscaElementVertex, ownerVertex, modifierVertex);
1038 if (result.isLeft()) {
1039 toscaElementVertex.addMetadataProperty(GraphPropertyEnum.STATE, nextState.name());
1040 toscaElementVertex.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, System.currentTimeMillis());
1041 result = updateToscaElementVertexMetadataPropertiesAndJson(toscaElementVertex);
1043 if (result.isLeft()) {
1044 updateRelationsRes = updateLastModifierEdge(toscaElementVertex, ownerVertex, modifierVertex);
1045 if (updateRelationsRes.isRight()) {
1046 result = Either.right(updateRelationsRes.right().value());
1052 private Either<GraphVertex, StorageOperationStatus> updateToscaElementVertexMetadataPropertiesAndJson(GraphVertex toscaElementVertex) {
1054 Either<GraphVertex, StorageOperationStatus> result;
1056 Either<GraphVertex, JanusGraphOperationStatus> updateVertexRes = janusGraphDao.updateVertex(toscaElementVertex);
1057 if (updateVertexRes.isRight()) {
1058 JanusGraphOperationStatus titatStatus = updateVertexRes.right().value();
1059 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update state of tosca element vertex {} metadata. Status is {}", toscaElementVertex.getUniqueId(), titatStatus);
1060 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(titatStatus));
1062 result = Either.left(updateVertexRes.left().value());
1067 private Either<GraphVertex, StorageOperationStatus> changeStateToCheckedIn(LifecycleStateEnum currState, GraphVertex toscaElementVertex, GraphVertex ownerVertex, GraphVertex modifierVertex) {
1068 Either<GraphVertex, StorageOperationStatus> result = null;
1069 LifecycleStateEnum nextState = LifecycleStateEnum.NOT_CERTIFIED_CHECKIN;
1070 String faileToUpdateStateMsg = "Failed to update state of tosca element {}. Status is {}";
1072 // Remove CHECKOUT relation
1073 Either<Edge, JanusGraphOperationStatus> deleteEdgeResult = janusGraphDao
1074 .deleteEdge(ownerVertex, toscaElementVertex, EdgeLabelEnum.STATE);
1075 if (deleteEdgeResult.isRight()) {
1076 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, faileToUpdateStateMsg, toscaElementVertex.getUniqueId());
1077 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(deleteEdgeResult.right().value()));
1080 if (result == null) {
1081 // Create CHECKIN relation
1082 Map<EdgePropertyEnum, Object> edgeProperties = new EnumMap<>(EdgePropertyEnum.class);
1083 edgeProperties.put(EdgePropertyEnum.STATE, nextState);
1084 JanusGraphOperationStatus
1085 createEdgeRes = janusGraphDao
1086 .createEdge(modifierVertex.getVertex(), toscaElementVertex.getVertex(), EdgeLabelEnum.STATE, edgeProperties);
1087 if (createEdgeRes != JanusGraphOperationStatus.OK) {
1088 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, faileToUpdateStateMsg, toscaElementVertex.getUniqueId());
1089 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(createEdgeRes));
1092 if (result == null) {
1093 result = Either.left(toscaElementVertex);
1098 private Either<GraphVertex, StorageOperationStatus> updateLastModifierEdge(GraphVertex toscaElementVertex, GraphVertex ownerVertex, GraphVertex modifierVertex) {
1099 Either<GraphVertex, StorageOperationStatus> result = null;
1100 if (!modifierVertex.getMetadataProperties().get(GraphPropertyEnum.USERID).equals(ownerVertex.getMetadataProperties().get(GraphPropertyEnum.USERID))) {
1101 Either<Edge, JanusGraphOperationStatus> deleteEdgeRes = janusGraphDao
1102 .deleteEdge(ownerVertex, toscaElementVertex, EdgeLabelEnum.LAST_MODIFIER);
1103 if (deleteEdgeRes.isRight()) {
1104 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to delete last modifier {} to tosca element {}. Edge type is {}", ownerVertex.getUniqueId(), ownerVertex.getUniqueId(), EdgeLabelEnum.LAST_MODIFIER);
1105 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(deleteEdgeRes.right().value()));
1107 if (result == null) {
1108 JanusGraphOperationStatus createEdgeRes = janusGraphDao
1109 .createEdge(modifierVertex.getVertex(), toscaElementVertex.getVertex(), EdgeLabelEnum.LAST_MODIFIER, new HashMap<>());
1111 if (createEdgeRes != JanusGraphOperationStatus.OK) {
1112 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to associate user {} to component {}. Edge type is {}", modifierVertex.getUniqueId(), ownerVertex.getUniqueId(), EdgeLabelEnum.LAST_MODIFIER);
1113 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(createEdgeRes));
1115 result = Either.left(modifierVertex);
1119 result = Either.left(ownerVertex);
1124 private Map<String, ImmutablePair<GraphPropertyEnum, JsonParseFlagEnum>> prepareParametersToGetVerticesForCheckin(String toscaElementId, String modifierId, String ownerId) {
1125 Map<String, ImmutablePair<GraphPropertyEnum, JsonParseFlagEnum>> verticesToGetParameters = new HashMap<>();
1126 verticesToGetParameters.put(toscaElementId, new ImmutablePair<>(GraphPropertyEnum.UNIQUE_ID, JsonParseFlagEnum.ParseMetadata));
1127 verticesToGetParameters.put(modifierId, new ImmutablePair<>(GraphPropertyEnum.USERID, JsonParseFlagEnum.NoParse));
1128 verticesToGetParameters.put(ownerId, new ImmutablePair<>(GraphPropertyEnum.USERID, JsonParseFlagEnum.NoParse));
1129 return verticesToGetParameters;
1132 private Map<String, ImmutablePair<GraphPropertyEnum, JsonParseFlagEnum>> prepareParametersToGetVerticesForRequestCertification(String toscaElementId, String modifierId, String ownerId) {
1133 Map<String, ImmutablePair<GraphPropertyEnum, JsonParseFlagEnum>> verticesToGetParameters = new HashMap<>();
1134 verticesToGetParameters.put(toscaElementId, new ImmutablePair<>(GraphPropertyEnum.UNIQUE_ID, JsonParseFlagEnum.ParseAll));
1135 verticesToGetParameters.put(modifierId, new ImmutablePair<>(GraphPropertyEnum.USERID, JsonParseFlagEnum.NoParse));
1136 verticesToGetParameters.put(ownerId, new ImmutablePair<>(GraphPropertyEnum.USERID, JsonParseFlagEnum.NoParse));
1137 return verticesToGetParameters;
1140 private Map<String, ImmutablePair<GraphPropertyEnum, JsonParseFlagEnum>> prepareParametersToGetVerticesForCheckout(String toscaElementId, String modifierId, String ownerId) {
1141 //Implementation is currently identical
1142 return prepareParametersToGetVerticesForRequestCertification(toscaElementId,modifierId, ownerId);
1145 private String getNextCertifiedVersion(String version) {
1146 String[] versionParts = version.split(VERSION_DELIMITER_REGEXP);
1147 Integer nextMajorVersion = Integer.parseInt(versionParts[0]) + 1;
1148 return nextMajorVersion + VERSION_DELIMITER + "0";
1151 private String getNextVersion(String currVersion) {
1152 String[] versionParts = currVersion.split(VERSION_DELIMITER_REGEXP);
1153 Integer minorVersion = Integer.parseInt(versionParts[1]) + 1;
1154 return versionParts[0] + VERSION_DELIMITER + minorVersion;
1157 private Integer getMinorVersion(String version) {
1158 String[] versionParts = version.split(VERSION_DELIMITER_REGEXP);
1159 return Integer.parseInt(versionParts[1]);
1162 private Integer getMajorVersion(String version) {
1163 String[] versionParts = version.split(VERSION_DELIMITER_REGEXP);
1164 return Integer.parseInt(versionParts[0]);
1167 private boolean isFirstCheckoutAfterCertification(String version) {
1168 return (Integer.parseInt(version.split(VERSION_DELIMITER_REGEXP)[0]) != 0 && Integer.parseInt(version.split(VERSION_DELIMITER_REGEXP)[1]) == 1);
1171 public Either<ToscaElement, StorageOperationStatus> forceCerificationOfToscaElement(String toscaElementId, String modifierId, String ownerId, String currVersion) {
1172 Either<GraphVertex, StorageOperationStatus> resultUpdate = null;
1173 Either<ToscaElement, StorageOperationStatus> result = null;
1174 GraphVertex toscaElement = null;
1175 GraphVertex modifier = null;
1178 Either<Map<String, GraphVertex>, JanusGraphOperationStatus> getVerticesRes = janusGraphDao
1179 .getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForRequestCertification(toscaElementId, modifierId, ownerId));
1180 if (getVerticesRes.isRight()) {
1181 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId);
1182 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(getVerticesRes.right().value()));
1184 if (result == null) {
1185 toscaElement = getVerticesRes.left().value().get(toscaElementId);
1186 modifier = getVerticesRes.left().value().get(modifierId);
1187 owner = getVerticesRes.left().value().get(ownerId);
1189 StorageOperationStatus status = handleRelationsUponForceCertification(toscaElement, modifier, owner);
1190 if (status != StorageOperationStatus.OK) {
1191 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to handle relations on certification request for tosca element {}. Status is {}. ", toscaElement.getUniqueId(), status);
1194 if (result == null) {
1195 LifecycleStateEnum nextState = LifecycleStateEnum.CERTIFIED;
1197 toscaElement.addMetadataProperty(GraphPropertyEnum.STATE, LifecycleStateEnum.CERTIFIED.name());
1198 toscaElement.addMetadataProperty(GraphPropertyEnum.VERSION, getNextCertifiedVersion(currVersion));
1200 resultUpdate = updateToscaElementVertexMetadataPropertiesAndJson(toscaElement);
1201 if (resultUpdate.isRight()) {
1202 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to set lifecycle for tosca elememt {} to state {}, error: {}", toscaElement.getUniqueId(), nextState, resultUpdate.right().value());
1203 result = Either.right(resultUpdate.right().value());
1206 if (result == null) {
1207 ToscaElementOperation operation = getToscaElementOperation(toscaElement.getLabel());
1208 result = operation.getToscaElement(toscaElement.getUniqueId());
1212 } catch (Exception e) {
1213 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Exception occured during request certification tosca element {}. {}", toscaElementId, e.getMessage());
1218 private StorageOperationStatus handleRelationsUponForceCertification(GraphVertex toscaElement, GraphVertex modifier, GraphVertex owner) {
1220 StorageOperationStatus result = null;
1221 JanusGraphOperationStatus status = janusGraphDao
1222 .replaceEdgeLabel(owner.getVertex(), toscaElement.getVertex(), EdgeLabelEnum.STATE, EdgeLabelEnum.LAST_STATE);
1223 if (status != JanusGraphOperationStatus.OK) {
1224 result = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status);
1226 if (result == null) {
1227 Map<EdgePropertyEnum, Object> properties = new EnumMap<>(EdgePropertyEnum.class);
1228 properties.put(EdgePropertyEnum.STATE, LifecycleStateEnum.CERTIFIED);
1229 status = janusGraphDao
1230 .createEdge(modifier, toscaElement, EdgeLabelEnum.STATE, properties);
1231 if (status != JanusGraphOperationStatus.OK) {
1232 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "failed to create edge. Status is {}", status);
1233 result = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status);
1236 if (result == null) {
1237 result = StorageOperationStatus.OK;
1242 private StorageOperationStatus updateEdgeToCatalogRootByUndoCheckout(JanusGraphVertex preV, GraphVertex curV) {
1244 return updateEdgeToCatalogRoot(null, curV);
1246 String uniqueIdPreVer = (String) janusGraphDao
1247 .getProperty((JanusGraphVertex) preV, GraphPropertyEnum.UNIQUE_ID.getProperty());
1248 LifecycleStateEnum state = LifecycleStateEnum.findState((String) janusGraphDao
1249 .getProperty(preV, GraphPropertyEnum.STATE.getProperty()));
1250 if (state == LifecycleStateEnum.CERTIFIED) {
1251 return updateEdgeToCatalogRoot(null, curV);
1253 return janusGraphDao.getVertexById(uniqueIdPreVer)
1254 .either(l -> updateEdgeToCatalogRoot(l, curV),
1255 DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
1258 private StorageOperationStatus updateEdgeToCatalogRoot(GraphVertex newVersionV, GraphVertex prevVersionV) {
1259 Either<GraphVertex, JanusGraphOperationStatus> catalog = janusGraphDao.getVertexByLabel(VertexTypeEnum.CATALOG_ROOT);
1260 if (catalog.isRight()) {
1261 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to fetch catalog vertex. error {}", catalog.right().value());
1262 return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(catalog.right().value());
1264 GraphVertex catalogV = catalog.left().value();
1265 if (newVersionV != null) {
1266 Boolean isAbstract = (Boolean) newVersionV.getMetadataProperty(GraphPropertyEnum.IS_ABSTRACT);
1268 if ( isAbstract == null || !isAbstract ) {
1269 // create new vertex
1270 JanusGraphOperationStatus
1271 result = janusGraphDao
1272 .createEdge(catalogV, newVersionV, EdgeLabelEnum.CATALOG_ELEMENT, null);
1273 if (result != JanusGraphOperationStatus.OK) {
1274 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to create edge from {} to catalog vertex. error {}", newVersionV.getUniqueId(), result);
1275 return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(result);
1279 if (prevVersionV != null) {
1280 Boolean isAbstract = (Boolean) prevVersionV.getMetadataProperty(GraphPropertyEnum.IS_ABSTRACT);
1281 if (isAbstract == null || !isAbstract) {
1282 // if prev == null -> new resource was added
1283 Either<Edge, JanusGraphOperationStatus> deleteResult = janusGraphDao
1284 .deleteEdge(catalogV, prevVersionV, EdgeLabelEnum.CATALOG_ELEMENT);
1285 if (deleteResult.isRight()) {
1286 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to delete edge from {} to catalog vertex. error {}", prevVersionV.getUniqueId(), deleteResult.right().value());
1287 return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(deleteResult.right().value());
1291 return StorageOperationStatus.OK;