f605d8c3faadca507ae8e04add8f073fe1905c54
[sdc.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel;
22
23 import fj.data.Either;
24 import org.openecomp.sdc.asdctool.impl.migration.MigrationMsg;
25 import org.openecomp.sdc.asdctool.impl.migration.Migration1707Task;
26 import org.openecomp.sdc.asdctool.impl.migration.v1707.MigrationUtils;
27 import org.openecomp.sdc.be.dao.api.ActionStatus;
28 import org.openecomp.sdc.be.dao.jsongraph.TitanDao;
29 import org.openecomp.sdc.be.datatypes.category.CategoryDataDefinition;
30 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
31 import org.openecomp.sdc.be.model.category.CategoryDefinition;
32 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
33 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
34 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
35
36 import javax.annotation.Resource;
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.stream.Collectors;
41
42 import static org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.CategoriesUtils.filterOldCategories;
43 import static org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.CategoriesUtils.filterOldSubCategories;
44
45
46 public class ResourcesCategoriesMigration implements Migration1707Task {
47
48     @Resource(name = "element-operation")
49     private IElementOperation elementOperation;
50
51     @Resource(name = "element-operation-migration")
52     private IElementOperation elementOperationMigration;
53
54     @Resource(name = "titan-dao")
55     TitanDao titanDao;
56
57     @Override
58     public String description() {
59         return "migrate resource categories";
60     }
61
62     @Override
63     public boolean migrate() {
64         return getCategoriesToMigrate().either(this::migrateCategories,
65                                                errorStatus -> MigrationUtils.handleError(MigrationMsg.FAILED_TO_RETRIEVE_CATEGORIES.getMessage(errorStatus.name())));
66     }
67
68     private Either<List<CategoryDefinition>, ActionStatus> getCategoriesToMigrate() {
69         return elementOperation.getAllCategories(NodeTypeEnum.ResourceNewCategory, false);
70     }
71
72     private boolean migrateCategories(List<CategoryDefinition> categoryDefinitions) {
73         List<CategoryDefinition> categoriesToMigrate = filterOldCategoriesAndSubCategories(categoryDefinitions);
74         for (CategoryDefinition categoryDefinition : categoriesToMigrate) {
75             boolean isMigrated = migrateCategoryIfNotExists(categoryDefinition);
76             if (!isMigrated) {
77                 titanDao.rollback();
78                 return false;
79             }
80             titanDao.commit();
81         }
82         return true;
83     }
84
85
86     //since production was malformed we need to fixed it by removing wrong categories and sub categories
87     private List<CategoryDefinition> filterOldCategoriesAndSubCategories(List<CategoryDefinition> categoryDefinitions) {
88         Map<String, List<CategoryDefinition>> categoriesByNormalName = categoryDefinitions.stream().collect(Collectors.groupingBy(CategoryDataDefinition::getNormalizedName));
89         List<CategoryDefinition> categoriesToMigrate = filterOldCategories(categoryDefinitions);
90         for (CategoryDefinition categoryDefinition : categoriesToMigrate) {
91             List<SubCategoryDefinition> newSubCategories = getAllDistinctSubCategories(categoriesByNormalName.get(categoryDefinition.getNormalizedName()));
92             categoryDefinition.setSubcategories(newSubCategories);
93         }
94         return categoriesToMigrate;
95     }
96
97     private List<SubCategoryDefinition> getAllDistinctSubCategories (List<CategoryDefinition> categoriesDefinitions) {
98         Map<String, List<SubCategoryDefinition>> subCategoriesByNormalName = categoriesDefinitions.stream()
99                 .filter(ct -> ct.getSubcategories()!=null)
100                 .flatMap(ct -> ct.getSubcategories().stream())
101                 .collect(Collectors.groupingBy(SubCategoryDefinition::getNormalizedName));
102         return getDistinctSubCategories(subCategoriesByNormalName);
103     }
104
105     private List<SubCategoryDefinition> getDistinctSubCategories(Map<String, List<SubCategoryDefinition>> subCategoriesByNormalName) {
106         List<SubCategoryDefinition> allSubCategories = new ArrayList<>();
107         for (List<SubCategoryDefinition> subCategoryDefinitions : subCategoriesByNormalName.values()) {
108             if (subCategoryDefinitions.size() == 1) {
109                 allSubCategories.addAll(subCategoryDefinitions);
110             } else {
111                 allSubCategories.addAll(filterOldSubCategories(subCategoryDefinitions));
112             }
113         }
114         return allSubCategories;
115     }
116
117     private boolean migrateCategoryIfNotExists(CategoryDefinition categoryDefinition) {
118         return isExists(categoryDefinition).either(isExist -> isExist ? migrateSubCategories(categoryDefinition) : migrateCategoryAndSubCategories(categoryDefinition),
119                                                    error -> MigrationUtils.handleError(MigrationMsg.FAILED_TO_RETRIEVE_CATEGORY.getMessage(categoryDefinition.getName(), error.name())));
120     }
121
122     private boolean migrateCategoryAndSubCategories(CategoryDefinition resourceCategory) {
123         return elementOperationMigration.createCategory(resourceCategory, NodeTypeEnum.ResourceNewCategory)
124                 .either(createdCategory -> this.migrateSubCategories(resourceCategory),
125                         status -> MigrationUtils.handleError(MigrationMsg.FAILED_TO_CREATE_CATEGORY.getMessage(resourceCategory.getName(), status.name())));
126     }
127
128     private boolean migrateSubCategories(CategoryDefinition categoryDefinition) {
129         for (SubCategoryDefinition subCategory : categoryDefinition.getSubcategories()) {
130             boolean isMigrated = migrateSubcategoryIfNotExists(categoryDefinition, subCategory);
131             if (!isMigrated) {
132                 return false;
133             }
134         }
135         return true;
136     }
137
138     private boolean migrateSubcategoryIfNotExists(CategoryDefinition parentCategory, SubCategoryDefinition subCategory) {
139         return isExists(parentCategory, subCategory).either(isExists -> isExists || migrateSubCategory(parentCategory, subCategory),
140                                             status -> MigrationUtils.handleError(MigrationMsg.FAILED_TO_RETRIEVE_CATEGORY.getMessage(subCategory.getName(), status.name())));
141     }
142
143     private boolean migrateSubCategory(CategoryDefinition categoryDefinition, SubCategoryDefinition subCategory) {
144         return elementOperationMigration.createSubCategory(categoryDefinition.getUniqueId(), subCategory, NodeTypeEnum.ResourceSubcategory)
145                 .either(createdSubCategory -> true,
146                         errorStatus -> MigrationUtils.handleError(MigrationMsg.FAILED_TO_CREATE_SUB_CATEGORY.getMessage(subCategory.getName(), categoryDefinition.getName(), errorStatus.name())));
147
148     }
149
150     private Either<Boolean, ActionStatus> isExists(CategoryDefinition category) {
151         Either<CategoryDefinition, ActionStatus> byId = getCategoryById(category);
152         return byId.either(existingVal -> Either.left(true),
153                            this::getEitherNotExistOrErrorStatus);
154     }
155
156     private Either<Boolean, ActionStatus> isExists(CategoryDefinition parentCategory, SubCategoryDefinition subCategory) {
157         return getSubCategoryById(parentCategory, subCategory).either(existingVal -> Either.left(true),
158                                                this::getEitherNotExistOrErrorStatus);
159     }
160
161     private Either<Boolean, ActionStatus> getEitherNotExistOrErrorStatus(ActionStatus status) {
162         return status == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND ? Either.left(false) : Either.right(status);
163     }
164
165     private Either<CategoryDefinition, ActionStatus> getCategoryById(CategoryDefinition category) {
166         return elementOperationMigration.getCategory(NodeTypeEnum.ResourceNewCategory, category.getUniqueId());
167     }
168
169     private Either<SubCategoryDefinition, ActionStatus> getSubCategoryById(CategoryDefinition parentCategory, SubCategoryDefinition subCategory) {
170         String subCategoryUid = getExpectedSubCategoryId(parentCategory, subCategory);
171         return elementOperationMigration.getSubCategory(NodeTypeEnum.ResourceSubcategory, subCategoryUid);
172     }
173
174     //since a sub category might belong to a different category in old graph its new graph id is different than its old graph id
175     private String getExpectedSubCategoryId(CategoryDefinition parentCategory, SubCategoryDefinition subCategory) {
176         String parentId = UniqueIdBuilder.buildCategoryUid(parentCategory.getNormalizedName(), NodeTypeEnum.ResourceNewCategory);
177         return UniqueIdBuilder.buildSubCategoryUid(parentId, subCategory.getNormalizedName());
178     }
179
180
181 }