[SDC-29] rebase continue work to align source
[sdc.git] / asdctool / src / main / java / org / openecomp / sdc / asdctool / impl / migration / v1707 / jsonmodel / ResourcesCategoriesMigration.java
1 package org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel;
2
3 import fj.data.Either;
4 import org.openecomp.sdc.asdctool.impl.migration.MigrationMsg;
5 import org.openecomp.sdc.asdctool.impl.migration.Migration1707Task;
6 import org.openecomp.sdc.asdctool.impl.migration.v1707.MigrationUtils;
7 import org.openecomp.sdc.be.dao.api.ActionStatus;
8 import org.openecomp.sdc.be.dao.jsongraph.TitanDao;
9 import org.openecomp.sdc.be.datatypes.category.CategoryDataDefinition;
10 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
11 import org.openecomp.sdc.be.model.category.CategoryDefinition;
12 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
13 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
14 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
15
16 import javax.annotation.Resource;
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.stream.Collectors;
21
22 import static org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.CategoriesUtils.filterOldCategories;
23 import static org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.CategoriesUtils.filterOldSubCategories;
24
25
26 public class ResourcesCategoriesMigration implements Migration1707Task {
27
28     @Resource(name = "element-operation")
29     private IElementOperation elementOperation;
30
31     @Resource(name = "element-operation-migration")
32     private IElementOperation elementOperationMigration;
33
34     @Resource(name = "titan-dao")
35     TitanDao titanDao;
36
37     @Override
38     public String description() {
39         return "migrate resource categories";
40     }
41
42     @Override
43     public boolean migrate() {
44         return getCategoriesToMigrate().either(this::migrateCategories,
45                                                errorStatus -> MigrationUtils.handleError(MigrationMsg.FAILED_TO_RETRIEVE_CATEGORIES.getMessage(errorStatus.name())));
46     }
47
48     private Either<List<CategoryDefinition>, ActionStatus> getCategoriesToMigrate() {
49         return elementOperation.getAllCategories(NodeTypeEnum.ResourceNewCategory, false);
50     }
51
52     private boolean migrateCategories(List<CategoryDefinition> categoryDefinitions) {
53         List<CategoryDefinition> categoriesToMigrate = filterOldCategoriesAndSubCategories(categoryDefinitions);
54         for (CategoryDefinition categoryDefinition : categoriesToMigrate) {
55             boolean isMigrated = migrateCategoryIfNotExists(categoryDefinition);
56             if (!isMigrated) {
57                 titanDao.rollback();
58                 return false;
59             }
60             titanDao.commit();
61         }
62         return true;
63     }
64
65
66     //since production was malformed we need to fixed it by removing wrong categories and sub categories
67     private List<CategoryDefinition> filterOldCategoriesAndSubCategories(List<CategoryDefinition> categoryDefinitions) {
68         Map<String, List<CategoryDefinition>> categoriesByNormalName = categoryDefinitions.stream().collect(Collectors.groupingBy(CategoryDataDefinition::getNormalizedName));
69         List<CategoryDefinition> categoriesToMigrate = filterOldCategories(categoryDefinitions);
70         for (CategoryDefinition categoryDefinition : categoriesToMigrate) {
71             List<SubCategoryDefinition> newSubCategories = getAllDistinctSubCategories(categoriesByNormalName.get(categoryDefinition.getNormalizedName()));
72             categoryDefinition.setSubcategories(newSubCategories);
73         }
74         return categoriesToMigrate;
75     }
76
77     private List<SubCategoryDefinition> getAllDistinctSubCategories (List<CategoryDefinition> categoriesDefinitions) {
78         Map<String, List<SubCategoryDefinition>> subCategoriesByNormalName = categoriesDefinitions.stream()
79                 .filter(ct -> ct.getSubcategories()!=null)
80                 .flatMap(ct -> ct.getSubcategories().stream())
81                 .collect(Collectors.groupingBy(SubCategoryDefinition::getNormalizedName));
82         return getDistinctSubCategories(subCategoriesByNormalName);
83     }
84
85     private List<SubCategoryDefinition> getDistinctSubCategories(Map<String, List<SubCategoryDefinition>> subCategoriesByNormalName) {
86         List<SubCategoryDefinition> allSubCategories = new ArrayList<>();
87         for (List<SubCategoryDefinition> subCategoryDefinitions : subCategoriesByNormalName.values()) {
88             if (subCategoryDefinitions.size() == 1) {
89                 allSubCategories.addAll(subCategoryDefinitions);
90             } else {
91                 allSubCategories.addAll(filterOldSubCategories(subCategoryDefinitions));
92             }
93         }
94         return allSubCategories;
95     }
96
97     private boolean migrateCategoryIfNotExists(CategoryDefinition categoryDefinition) {
98         return isExists(categoryDefinition).either(isExist -> isExist ? migrateSubCategories(categoryDefinition) : migrateCategoryAndSubCategories(categoryDefinition),
99                                                    error -> MigrationUtils.handleError(MigrationMsg.FAILED_TO_RETRIEVE_CATEGORY.getMessage(categoryDefinition.getName(), error.name())));
100     }
101
102     private boolean migrateCategoryAndSubCategories(CategoryDefinition resourceCategory) {
103         return elementOperationMigration.createCategory(resourceCategory, NodeTypeEnum.ResourceNewCategory)
104                 .either(createdCategory -> this.migrateSubCategories(resourceCategory),
105                         status -> MigrationUtils.handleError(MigrationMsg.FAILED_TO_CREATE_CATEGORY.getMessage(resourceCategory.getName(), status.name())));
106     }
107
108     private boolean migrateSubCategories(CategoryDefinition categoryDefinition) {
109         for (SubCategoryDefinition subCategory : categoryDefinition.getSubcategories()) {
110             boolean isMigrated = migrateSubcategoryIfNotExists(categoryDefinition, subCategory);
111             if (!isMigrated) {
112                 return false;
113             }
114         }
115         return true;
116     }
117
118     private boolean migrateSubcategoryIfNotExists(CategoryDefinition parentCategory, SubCategoryDefinition subCategory) {
119         return isExists(parentCategory, subCategory).either(isExists -> isExists || migrateSubCategory(parentCategory, subCategory),
120                                             status -> MigrationUtils.handleError(MigrationMsg.FAILED_TO_RETRIEVE_CATEGORY.getMessage(subCategory.getName(), status.name())));
121     }
122
123     private boolean migrateSubCategory(CategoryDefinition categoryDefinition, SubCategoryDefinition subCategory) {
124         return elementOperationMigration.createSubCategory(categoryDefinition.getUniqueId(), subCategory, NodeTypeEnum.ResourceSubcategory)
125                 .either(createdSubCategory -> true,
126                         errorStatus -> MigrationUtils.handleError(MigrationMsg.FAILED_TO_CREATE_SUB_CATEGORY.getMessage(subCategory.getName(), categoryDefinition.getName(), errorStatus.name())));
127
128     }
129
130     private Either<Boolean, ActionStatus> isExists(CategoryDefinition category) {
131         Either<CategoryDefinition, ActionStatus> byId = getCategoryById(category);
132         return byId.either(existingVal -> Either.left(true),
133                            this::getEitherNotExistOrErrorStatus);
134     }
135
136     private Either<Boolean, ActionStatus> isExists(CategoryDefinition parentCategory, SubCategoryDefinition subCategory) {
137         return getSubCategoryById(parentCategory, subCategory).either(existingVal -> Either.left(true),
138                                                this::getEitherNotExistOrErrorStatus);
139     }
140
141     private Either<Boolean, ActionStatus> getEitherNotExistOrErrorStatus(ActionStatus status) {
142         return status == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND ? Either.left(false) : Either.right(status);
143     }
144
145     private Either<CategoryDefinition, ActionStatus> getCategoryById(CategoryDefinition category) {
146         return elementOperationMigration.getCategory(NodeTypeEnum.ResourceNewCategory, category.getUniqueId());
147     }
148
149     private Either<SubCategoryDefinition, ActionStatus> getSubCategoryById(CategoryDefinition parentCategory, SubCategoryDefinition subCategory) {
150         String subCategoryUid = getExpectedSubCategoryId(parentCategory, subCategory);
151         return elementOperationMigration.getSubCategory(NodeTypeEnum.ResourceSubcategory, subCategoryUid);
152     }
153
154     //since a sub category might belong to a different category in old graph its new graph id is different than its old graph id
155     private String getExpectedSubCategoryId(CategoryDefinition parentCategory, SubCategoryDefinition subCategory) {
156         String parentId = UniqueIdBuilder.buildCategoryUid(parentCategory.getNormalizedName(), NodeTypeEnum.ResourceNewCategory);
157         return UniqueIdBuilder.buildSubCategoryUid(parentId, subCategory.getNormalizedName());
158     }
159
160
161 }