0763ad970bfc186ba4b994beeb525078ac6cfc3f
[sdc.git] /
1 /*
2  * Copyright © 2016-2018 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.openecomp.sdc.versioning.impl;
18
19 import java.util.Collection;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.stream.Collectors;
26 import org.openecomp.sdc.common.errors.CoreException;
27 import org.openecomp.sdc.common.errors.ErrorCategory;
28 import org.openecomp.sdc.common.errors.ErrorCode;
29 import org.openecomp.sdc.datatypes.error.ErrorLevel;
30 import org.openecomp.sdc.logging.api.Logger;
31 import org.openecomp.sdc.logging.api.LoggerFactory;
32 import org.openecomp.sdc.versioning.ActionVersioningManager;
33 import org.openecomp.sdc.versioning.AsdcItemManager;
34 import org.openecomp.sdc.versioning.VersionCalculator;
35 import org.openecomp.sdc.versioning.dao.VersionDao;
36 import org.openecomp.sdc.versioning.dao.VersionInfoDao;
37 import org.openecomp.sdc.versioning.dao.VersionInfoDeletedDao;
38 import org.openecomp.sdc.versioning.dao.VersionableEntityDaoFactory;
39 import org.openecomp.sdc.versioning.dao.types.Revision;
40 import org.openecomp.sdc.versioning.dao.types.SynchronizationState;
41 import org.openecomp.sdc.versioning.dao.types.UserCandidateVersion;
42 import org.openecomp.sdc.versioning.dao.types.Version;
43 import org.openecomp.sdc.versioning.dao.types.VersionInfoDeletedEntity;
44 import org.openecomp.sdc.versioning.dao.types.VersionInfoEntity;
45 import org.openecomp.sdc.versioning.dao.types.VersionStatus;
46 import org.openecomp.sdc.versioning.errors.CheckinOnEntityLockedByOtherErrorBuilder;
47 import org.openecomp.sdc.versioning.errors.CheckinOnUnlockedEntityErrorBuilder;
48 import org.openecomp.sdc.versioning.errors.CheckoutOnLockedEntityErrorBuilder;
49 import org.openecomp.sdc.versioning.errors.DeleteOnLockedEntityErrorBuilder;
50 import org.openecomp.sdc.versioning.errors.EditOnEntityLockedByOtherErrorBuilder;
51 import org.openecomp.sdc.versioning.errors.EditOnUnlockedEntityErrorBuilder;
52 import org.openecomp.sdc.versioning.errors.EntityAlreadyExistErrorBuilder;
53 import org.openecomp.sdc.versioning.errors.EntityAlreadyFinalizedErrorBuilder;
54 import org.openecomp.sdc.versioning.errors.EntityNotExistErrorBuilder;
55 import org.openecomp.sdc.versioning.errors.SubmitLockedEntityNotAllowedErrorBuilder;
56 import org.openecomp.sdc.versioning.errors.UndoCheckoutOnEntityLockedByOtherErrorBuilder;
57 import org.openecomp.sdc.versioning.errors.UndoCheckoutOnUnlockedEntityErrorBuilder;
58 import org.openecomp.sdc.versioning.types.VersionCreationMethod;
59 import org.openecomp.sdc.versioning.types.VersionInfo;
60 import org.openecomp.sdc.versioning.types.VersionableEntityAction;
61 import org.openecomp.sdc.versioning.types.VersionableEntityMetadata;
62 import org.slf4j.MDC;
63
64 public class ActionVersioningManagerImpl implements ActionVersioningManager {
65   private static final Logger LOGGER = LoggerFactory.getLogger(ActionVersioningManagerImpl.class);
66   private static final Version INITIAL_ACTIVE_VERSION = new Version(0, 0);
67   private static final Map<String, Set<VersionableEntityMetadata>> VERSIONABLE_ENTITIES =
68       new HashMap<>();
69
70   private final VersionInfoDao versionInfoDao;
71   private final VersionInfoDeletedDao versionInfoDeletedDao;
72   private VersionDao versionDao;
73   private VersionCalculator versionCalculator;
74   private AsdcItemManager asdcItemManager;
75
76   public ActionVersioningManagerImpl(VersionInfoDao versionInfoDao,
77                                      VersionInfoDeletedDao versionInfoDeletedDao,
78                                      VersionDao versionDao,
79                                      VersionCalculator versionCalculator,
80                                      AsdcItemManager asdcItemManager) {
81     this.versionInfoDao = versionInfoDao;
82     this.versionInfoDeletedDao = versionInfoDeletedDao;
83     this.versionDao = versionDao;
84     this.versionCalculator = versionCalculator;
85     this.asdcItemManager = asdcItemManager;
86   }
87
88   private static VersionInfo getVersionInfo(VersionInfoEntity versionInfoEntity, String user,
89                                             VersionableEntityAction action) {
90     return getVersionInfo(versionInfoEntity.getEntityId(),
91         versionInfoEntity.getEntityType(),
92         versionInfoEntity.getActiveVersion(),
93         versionInfoEntity.getCandidate(),
94         versionInfoEntity.getStatus(),
95         versionInfoEntity.getLatestFinalVersion(),
96         versionInfoEntity.getViewableVersions(),
97         action,
98         user);
99   }
100
101   private static VersionInfo getVersionInfo(VersionInfoDeletedEntity versionInfoEntity, String user,
102                                             VersionableEntityAction action) {
103     return getVersionInfo(versionInfoEntity.getEntityId(),
104         versionInfoEntity.getEntityType(),
105         versionInfoEntity.getActiveVersion(),
106         versionInfoEntity.getCandidate(),
107         versionInfoEntity.getStatus(),
108         versionInfoEntity.getLatestFinalVersion(),
109         versionInfoEntity.getViewableVersions(),
110         action,
111         user);
112   }
113
114   private static VersionInfo getVersionInfo(String entityId, String entityType, Version activeVer,
115                                             UserCandidateVersion candidate, VersionStatus status,
116                                             Version latestFinalVersion,
117                                             Set<Version> viewableVersions,
118                                             VersionableEntityAction action, String user) {
119     Version activeVersion;
120
121     if (action == VersionableEntityAction.Write) {
122       if (candidate != null) {
123         if (user.equals(candidate.getUser())) {
124           activeVersion = candidate.getVersion();
125         } else {
126           throw new CoreException(
127               new EditOnEntityLockedByOtherErrorBuilder(entityType, entityId, candidate.getUser())
128                   .build());
129         }
130       } else {
131         throw new CoreException(new EditOnUnlockedEntityErrorBuilder(entityType, entityId).build());
132       }
133     } else {
134       if (candidate != null && user.equals(candidate.getUser())) {
135         activeVersion = candidate.getVersion();
136       } else {
137         activeVersion = activeVer;
138       }
139     }
140
141     VersionInfo versionInfo = new VersionInfo();
142     versionInfo.setStatus(status);
143     activeVersion.setStatus(status);
144     if (latestFinalVersion != null) {
145       latestFinalVersion.setStatus(status);
146     }
147     if (viewableVersions != null) {
148       viewableVersions.forEach(version -> version.setStatus(status));
149     }
150     versionInfo.setActiveVersion(activeVersion);
151     versionInfo.setLatestFinalVersion(latestFinalVersion);
152     versionInfo.setViewableVersions(toSortedList(viewableVersions));
153     versionInfo.setFinalVersions(getFinalVersions(viewableVersions));
154     if (candidate != null) {
155       candidate.getVersion().setStatus(status);
156       versionInfo.setLockingUser(candidate.getUser());
157       if (user.equals(candidate.getUser())) {
158         versionInfo.getViewableVersions().add(candidate.getVersion());
159       }
160     }
161     return versionInfo;
162   }
163
164   private static List<Version> toSortedList(
165       Set<Version> versions) { // changing the Set to List in DB will require migration...
166     return versions.stream().sorted((o1, o2) -> o1.getMajor() > o2.getMajor() ? 1
167         : o1.getMajor() == o2.getMajor() ? (o1.getMinor() > o2.getMinor() ? 1
168             : o1.getMinor() == o2.getMinor() ? 0 : -1) : -1).collect(Collectors.toList());
169   }
170
171   private static List<Version> getFinalVersions(Set<Version> versions) {
172     return versions.stream().filter(Version::isFinal).collect(Collectors.toList());
173   }
174
175   @Override
176   public void register(String entityType, VersionableEntityMetadata entityMetadata) {
177     Set<VersionableEntityMetadata> entitiesMetadata =
178         VERSIONABLE_ENTITIES.computeIfAbsent(entityType, k -> new HashSet<>());
179     entitiesMetadata.add(entityMetadata);
180   }
181
182   @Override
183   public Version create(String entityType, String entityId, String user) {
184     VersionInfoEntity
185         versionInfoEntity = versionInfoDao.get(new VersionInfoEntity(entityType, entityId));
186     if (versionInfoEntity != null) {
187       throw new CoreException(new EntityAlreadyExistErrorBuilder(entityType, entityId).build());
188     }
189
190     versionInfoEntity = new VersionInfoEntity(entityType, entityId);
191     versionInfoEntity.setActiveVersion(INITIAL_ACTIVE_VERSION);
192     markAsCheckedOut(versionInfoEntity, user);
193     versionInfoDao.create(versionInfoEntity);
194
195     return versionInfoEntity.getCandidate().getVersion();
196   }
197
198   @Override
199   public void delete(String entityType, String entityId, String user) {
200     VersionInfoEntity versionInfoEntity =
201         versionInfoDao.get(new VersionInfoEntity(entityType, entityId));
202     if (versionInfoEntity == null) {
203       throw new CoreException(new EntityNotExistErrorBuilder(entityType, entityId).build());
204     }
205
206     switch (versionInfoEntity.getStatus()) {
207       case Locked:
208         throw new CoreException(new DeleteOnLockedEntityErrorBuilder(entityType, entityId,
209             versionInfoEntity.getCandidate().getUser()).build());
210       default:
211         //do nothing
212         break;
213     }
214
215     doDelete(versionInfoEntity);
216   }
217
218   @Override
219   public void undoDelete(String entityType, String entityId, String user) {
220     VersionInfoDeletedEntity versionInfoDeletedEntity =
221         versionInfoDeletedDao.get(new VersionInfoDeletedEntity(entityType, entityId));
222     if (versionInfoDeletedEntity == null) {
223     throw new CoreException(new EntityNotExistErrorBuilder(entityType, entityId).build());
224   }
225
226   doUndoDelete(versionInfoDeletedEntity);
227 }
228
229   @Override
230   public Version checkout(String entityType, String entityId, String user) {
231     VersionInfoEntity versionInfoEntity =
232         versionInfoDao.get(new VersionInfoEntity(entityType, entityId));
233     if (versionInfoEntity == null) {
234       throw new CoreException(new EntityNotExistErrorBuilder(entityType, entityId).build());
235     }
236
237     Version checkoutVersion = null;
238     switch (versionInfoEntity.getStatus()) {
239       case Locked:
240         throw new CoreException(new CheckoutOnLockedEntityErrorBuilder(entityType, entityId,
241             versionInfoEntity.getCandidate().getUser()).build());
242       case Certified:
243       case Draft:
244         checkoutVersion = doCheckout(versionInfoEntity, user);
245         break;
246       default:
247         //do nothing
248         break;
249     }
250
251     return checkoutVersion;
252   }
253
254   @Override
255   public Version undoCheckout(String entityType, String entityId, String user) {
256     VersionInfoEntity versionInfoEntity =
257         versionInfoDao.get(new VersionInfoEntity(entityType, entityId));
258     if (versionInfoEntity == null) {
259       throw new CoreException(new EntityNotExistErrorBuilder(entityType, entityId).build());
260     }
261
262     Version activeVersion = null;
263     switch (versionInfoEntity.getStatus()) {
264       case Locked:
265         if (!user.equals(versionInfoEntity.getCandidate().getUser())) {
266           throw new CoreException(
267               new UndoCheckoutOnEntityLockedByOtherErrorBuilder(entityType, entityId,
268                   versionInfoEntity.getCandidate().getUser()).build());
269         }
270         activeVersion = undoCheckout(versionInfoEntity);
271         break;
272       case Certified:
273       case Draft:
274         throw new CoreException(
275             new UndoCheckoutOnUnlockedEntityErrorBuilder(entityType, entityId).build());
276       default:
277         //do nothing
278         break;
279     }
280
281     return activeVersion;
282   }
283
284   private Version undoCheckout(VersionInfoEntity versionInfoEntity) {
285     deleteVersionFromEntity(versionInfoEntity.getEntityType(), versionInfoEntity.getEntityId(),
286         versionInfoEntity.getCandidate().getVersion(), versionInfoEntity.getActiveVersion());
287
288     versionInfoEntity
289         .setStatus(versionInfoEntity.getActiveVersion().isFinal() ? VersionStatus.Certified
290             : VersionStatus.Draft);
291     versionInfoEntity.setCandidate(null);
292     versionInfoDao.update(versionInfoEntity);
293     return versionInfoEntity.getActiveVersion();
294   }
295
296   @Override
297   public Version checkin(String entityType, String entityId, String user,
298                          String checkinDescription) {
299     VersionInfoEntity versionInfoEntity =
300         versionInfoDao.get(new VersionInfoEntity(entityType, entityId));
301     if (versionInfoEntity == null) {
302       throw new CoreException(new EntityNotExistErrorBuilder(entityType, entityId).build());
303     }
304
305     Version checkedInVersion = null;
306     switch (versionInfoEntity.getStatus()) {
307       case Draft:
308       case Certified:
309         throw new CoreException(
310             new CheckinOnUnlockedEntityErrorBuilder(entityType, entityId).build());
311       case Locked:
312         if (!user.equals(versionInfoEntity.getCandidate().getUser())) {
313           throw new CoreException(new CheckinOnEntityLockedByOtherErrorBuilder(entityType, entityId,
314               versionInfoEntity.getCandidate().getUser()).build());
315         }
316         checkedInVersion = doCheckin(versionInfoEntity, checkinDescription);
317         break;
318       default:
319         //do nothing
320         break;
321     }
322
323     return checkedInVersion;
324   }
325
326   @Override
327   public Version submit(String entityType, String entityId, String user, String submitDescription) {
328     VersionInfoEntity versionInfoEntity =
329         versionInfoDao.get(new VersionInfoEntity(entityType, entityId));
330     if (versionInfoEntity == null) {
331       throw new CoreException(new EntityNotExistErrorBuilder(entityType, entityId).build());
332     }
333
334     Version submitVersion = null;
335     switch (versionInfoEntity.getStatus()) {
336       case Certified:
337         throw new CoreException(
338             new EntityAlreadyFinalizedErrorBuilder(entityType, entityId).build());
339       case Locked:
340         throw new CoreException(new SubmitLockedEntityNotAllowedErrorBuilder(entityType, entityId,
341             versionInfoEntity.getCandidate().getUser()).build());
342       case Draft:
343         submitVersion = doSubmit(versionInfoEntity, user, submitDescription);
344         break;
345       default:
346         //do nothing
347         break;
348     }
349
350     return submitVersion;
351   }
352
353   @Override
354   public VersionInfo getEntityVersionInfo(String entityType, String entityId, String user,
355                                           VersionableEntityAction action) {
356     VersionInfoEntity versionInfoEntity =
357         versionInfoDao.get(new VersionInfoEntity(entityType, entityId));
358     if (versionInfoEntity == null) {
359       throw new CoreException(new EntityNotExistErrorBuilder(entityType, entityId).build());
360     }
361     return getVersionInfo(versionInfoEntity, user, action);
362   }
363
364   @Override
365   public Map<String, VersionInfo> listEntitiesVersionInfo(String entityType, String user,
366                                                           VersionableEntityAction action) {
367     Collection<VersionInfoEntity> versionInfoEntities =
368         versionInfoDao.list(new VersionInfoEntity(entityType, null));
369     Map<String, VersionInfo> activeVersions = new HashMap<>();
370     for (VersionInfoEntity versionInfoEntity : versionInfoEntities) {
371       activeVersions
372           .put(versionInfoEntity.getEntityId(), getVersionInfo(versionInfoEntity, user, action));
373     }
374     return activeVersions;
375   }
376
377   @Override
378   public Map<String, VersionInfo> listDeletedEntitiesVersionInfo(String entityType, String user,
379                                                                  VersionableEntityAction action) {
380     Collection<VersionInfoDeletedEntity> versionInfoDeletedEntities =
381         versionInfoDeletedDao.list(new VersionInfoDeletedEntity(entityType, null));
382     Map<String, VersionInfo> activeVersions = new HashMap<>();
383
384
385     for (VersionInfoDeletedEntity versionInfoDeletedEntity : versionInfoDeletedEntities) {
386       activeVersions.put(versionInfoDeletedEntity.getEntityId(),
387           getVersionInfo(versionInfoDeletedEntity, user, action));
388     }
389     return activeVersions;
390   }
391
392   @Override
393   public List<Version> list(String itemId) {
394
395     List<Version> versions = versionDao.list(itemId);
396     Set<String> versionsNames = versions.stream().map(Version::getName).collect(Collectors.toSet());
397     versions.forEach(version -> {
398       version.setAdditionalInfo(new HashMap<>());
399       versionCalculator.injectAdditionalInfo(version, versionsNames);
400     });
401     return versions;
402   }
403
404   @Override
405   public Version get(String itemId, Version version) {
406     return versionDao.get(itemId, version)
407         .map(retrievedVersion -> getUpdateRetrievedVersion(itemId, retrievedVersion))
408         .orElseGet(() -> getSyncedVersion(itemId, version));
409   }
410
411   private Version getUpdateRetrievedVersion(String itemId, Version version) {
412     if (version.getStatus() == VersionStatus.Certified &&
413         (version.getState().getSynchronizationState() == SynchronizationState.OutOfSync ||
414             version.getState().isDirty())) {
415       forceSync(itemId, version);
416       LOGGER.info("Item Id {}, version Id {}: Force sync is done", itemId, version.getId());
417       version = versionDao.get(itemId, version)
418           .orElseThrow(() -> new IllegalStateException(
419               "Get version after a successful force sync must return the version"));
420     }
421     return version;
422   }
423
424   private Version getSyncedVersion(String itemId, Version version) {
425     sync(itemId, version);
426     LOGGER.info("Item Id {}, version Id {}: First time sync is done", itemId, version.getId());
427     return versionDao.get(itemId, version)
428         .orElseThrow(() -> new IllegalStateException(
429             "Get version after a successful sync must return the version"));
430   }
431
432   @Override
433   public Version create(String itemId, Version version, VersionCreationMethod creationMethod) {
434     String baseVersionName = null;
435     if (version.getBaseId() == null) {
436       version.setDescription("Initial version");
437     } else {
438       baseVersionName = get(itemId, new Version(version.getBaseId())).getName();
439     }
440     String versionName = versionCalculator.calculate(baseVersionName, creationMethod);
441     validateVersionName(itemId, versionName);
442     version.setName(versionName);
443
444     versionDao.create(itemId, version);
445     asdcItemManager.updateVersionStatus(itemId, VersionStatus.Draft, null);
446
447     publish(itemId, version, String.format("Create version: %s", version.getName()));
448     return version;
449   }
450
451   private void validateVersionName(String itemId, String versionName) {
452     if (versionDao.list(itemId).stream()
453         .anyMatch(version -> versionName.equals(version.getName()))) {
454       String errorDescription = String
455           .format("Item %s: create version failed, a version with the name %s already exist",
456               itemId, versionName);
457       throw new CoreException(new ErrorCode.ErrorCodeBuilder()
458           .withCategory(ErrorCategory.APPLICATION)
459           .withId("VERSION_NAME_ALREADY_EXIST")
460           .withMessage(errorDescription)
461           .build());
462     }
463   }
464
465   @Override
466   public void submit(String itemId, Version version, String submitDescription) {
467     version = get(itemId, version);
468
469     validateSubmit(itemId, version);
470
471     version.setStatus(VersionStatus.Certified);
472     versionDao.update(itemId, version);
473
474     publish(itemId, version, submitDescription);
475
476     asdcItemManager.updateVersionStatus(itemId, VersionStatus.Certified, VersionStatus.Draft);
477   }
478
479   private void validateSubmit(String itemId, Version version) {
480     if (version.getStatus() == VersionStatus.Certified) {
481       String errorDescription = String
482           .format("Item %s: submit version failed, version %s is already Certified", itemId,
483               version.getId());
484       throw new CoreException(new ErrorCode.ErrorCodeBuilder()
485           .withCategory(ErrorCategory.APPLICATION)
486           .withId("VERSION_ALREADY_CERTIFIED")
487           .withMessage(errorDescription)
488           .build());
489     }
490   }
491
492   @Override
493   public void publish(String itemId, Version version, String message) {
494     versionDao.publish(itemId, version, message);
495   }
496
497
498   @Override
499   public void sync(String itemId, Version version) {
500     versionDao.sync(itemId, version);
501   }
502
503   @Override
504   public void forceSync(String itemId, Version version) {
505     versionDao.forceSync(itemId, version);
506   }
507
508   @Override
509   public void revert(String itemId, Version version, String revisionId) {
510     versionDao.revert(itemId, version, revisionId);
511   }
512
513   @Override
514   public List<Revision> listRevisions(String itemId, Version version) {
515     return versionDao.listRevisions(itemId, version);
516   }
517
518   private void markAsCheckedOut(VersionInfoEntity versionInfoEntity, String checkingOutUser) {
519     versionInfoEntity.setStatus(VersionStatus.Locked);
520     versionInfoEntity.setCandidate(new UserCandidateVersion(checkingOutUser,
521         versionInfoEntity.getActiveVersion().calculateNextCandidate()));
522   }
523
524   private Version doCheckout(VersionInfoEntity versionInfoEntity, String user) {
525     markAsCheckedOut(versionInfoEntity, user);
526     versionInfoDao.update(versionInfoEntity);
527
528     initVersionOnEntity(versionInfoEntity.getEntityType(), versionInfoEntity.getEntityId(),
529         versionInfoEntity.getActiveVersion(), versionInfoEntity.getCandidate().getVersion());
530
531     return versionInfoEntity.getCandidate().getVersion();
532   }
533
534   private void doDelete(VersionInfoEntity versionInfoEntity) {
535     VersionInfoDeletedEntity versionInfoDeletedEntity = new VersionInfoDeletedEntity();
536     versionInfoDeletedEntity.setStatus(versionInfoEntity.getStatus());
537     versionInfoDeletedEntity.setViewableVersions(versionInfoEntity.getViewableVersions());
538     versionInfoDeletedEntity.setActiveVersion(versionInfoEntity.getActiveVersion());
539     versionInfoDeletedEntity.setCandidate(versionInfoEntity.getCandidate());
540     versionInfoDeletedEntity.setEntityId(versionInfoEntity.getEntityId());
541     versionInfoDeletedEntity.setEntityType(versionInfoEntity.getEntityType());
542     versionInfoDeletedEntity.setLatestFinalVersion(versionInfoEntity.getLatestFinalVersion());
543     versionInfoDeletedDao.create(versionInfoDeletedEntity);
544     versionInfoDao.delete(versionInfoEntity);
545   }
546
547   private void doUndoDelete(VersionInfoDeletedEntity versionInfoDeletedEntity) {
548     VersionInfoEntity versionInfoEntity = new VersionInfoEntity();
549     versionInfoEntity.setStatus(versionInfoDeletedEntity.getStatus());
550     versionInfoEntity.setViewableVersions(versionInfoDeletedEntity.getViewableVersions());
551     versionInfoEntity.setActiveVersion(versionInfoDeletedEntity.getActiveVersion());
552     versionInfoEntity.setCandidate(versionInfoDeletedEntity.getCandidate());
553     versionInfoEntity.setEntityId(versionInfoDeletedEntity.getEntityId());
554     versionInfoEntity.setEntityType(versionInfoDeletedEntity.getEntityType());
555     versionInfoEntity.setLatestFinalVersion(versionInfoDeletedEntity.getLatestFinalVersion());
556     versionInfoDao.create(versionInfoEntity);
557     versionInfoDeletedDao.delete(versionInfoDeletedEntity);
558   }
559
560   private Version doCheckin(VersionInfoEntity versionInfoEntity, String checkinDescription) {
561     UserCandidateVersion userCandidateVersion = versionInfoEntity.getCandidate();
562     versionInfoEntity.setCandidate(null);
563     versionInfoEntity.setActiveVersion(userCandidateVersion.getVersion());
564     versionInfoEntity.getViewableVersions().add(versionInfoEntity.getActiveVersion());
565     versionInfoEntity.setStatus(VersionStatus.Draft);
566
567     closeVersionOnEntity(versionInfoEntity.getEntityType(), versionInfoEntity.getEntityId(),
568         versionInfoEntity.getActiveVersion());
569
570     versionInfoDao.update(versionInfoEntity);
571
572     return versionInfoEntity.getActiveVersion();
573   }
574
575   private Version doSubmit(VersionInfoEntity versionInfoEntity, String submittingUser,
576                            String submitDescription) {
577     Version finalVersion = versionInfoEntity.getActiveVersion().calculateNextFinal();
578     initVersionOnEntity(versionInfoEntity.getEntityType(), versionInfoEntity.getEntityId(),
579         versionInfoEntity.getActiveVersion(), finalVersion);
580     closeVersionOnEntity(versionInfoEntity.getEntityType(), versionInfoEntity.getEntityId(),
581         finalVersion);
582
583     Set<Version> viewableVersions = new HashSet<>();
584     for (Version version : versionInfoEntity.getViewableVersions()) {
585       if (version.isFinal()) {
586         viewableVersions.add(version);
587       }
588     }
589     viewableVersions.add(finalVersion);
590     versionInfoEntity.setViewableVersions(viewableVersions);
591     versionInfoEntity.setActiveVersion(finalVersion);
592     versionInfoEntity.setLatestFinalVersion(finalVersion);
593     versionInfoEntity.setStatus(VersionStatus.Certified);
594     versionInfoDao.update(versionInfoEntity);
595
596     return finalVersion;
597   }
598
599   private void initVersionOnEntity(String entityType, String entityId, Version baseVersion,
600                                    Version newVersion) {
601     Set<VersionableEntityMetadata> entityMetadatas = VERSIONABLE_ENTITIES.get(entityType);
602     if (entityMetadatas != null) {
603       for (VersionableEntityMetadata entityMetadata : entityMetadatas) {
604         VersionableEntityDaoFactory.getInstance().createInterface(entityMetadata.getStoreType())
605             .initVersion(entityMetadata, entityId, baseVersion, newVersion);
606       }
607     }
608   }
609
610   private void deleteVersionFromEntity(String entityType, String entityId,
611                                        Version versionToDelete, Version backToVersion) {
612     Set<VersionableEntityMetadata> entityMetadatas = VERSIONABLE_ENTITIES.get(entityType);
613     if (entityMetadatas != null) {
614       for (VersionableEntityMetadata entityMetadata : entityMetadatas) {
615         VersionableEntityDaoFactory.getInstance().createInterface(entityMetadata.getStoreType())
616             .deleteVersion(entityMetadata, entityId, versionToDelete, backToVersion);
617       }
618     }
619   }
620
621   private void closeVersionOnEntity(String entityType, String entityId, Version versionToClose) {
622     Set<VersionableEntityMetadata> entityMetadatas = VERSIONABLE_ENTITIES.get(entityType);
623     if (entityMetadatas != null) {
624       for (VersionableEntityMetadata entityMetadata : entityMetadatas) {
625         VersionableEntityDaoFactory.getInstance().createInterface(entityMetadata.getStoreType())
626             .closeVersion(entityMetadata, entityId, versionToClose);
627       }
628     }
629   }
630 }