90d5b7fd25adfac85cf61c823c05f00f7b1fc054
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2019 Nordix Foundation.
5  *  Modifications Copyright (C) 2020 Bell Canada. 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  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.apex.model.policymodel.handling;
24
25 import java.util.Map;
26 import java.util.Map.Entry;
27 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
28 import org.onap.policy.apex.model.basicmodel.concepts.AxKeyInfo;
29 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult;
30 import org.onap.policy.apex.model.basicmodel.handling.ApexModelException;
31 import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
32 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchema;
33 import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
34 import org.onap.policy.apex.model.policymodel.concepts.AxPolicy;
35 import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
36 import org.onap.policy.apex.model.policymodel.concepts.AxTask;
37 import org.slf4j.ext.XLogger;
38 import org.slf4j.ext.XLoggerFactory;
39
40 /**
41  * Helper class used to merge information from two policy models together into a single policy
42  * model.
43  *
44  * @author Liam Fallon (liam.fallon@ericsson.com)
45  */
46 public final class PolicyModelMerger {
47     private static final XLogger LOGGER = XLoggerFactory.getXLogger(PolicyModelMerger.class);
48
49     /**
50      * Private constructor used to prevent sub class instantiation.
51      */
52     private PolicyModelMerger() {
53     }
54
55     /**
56      * Get a merged policy model with information from two policy models merged into a larger policy
57      * model.
58      *
59      * @param leftPolicyModel the source Apex Model
60      * @param rightPolicyModel the policies to include in sub policy model
61      * @param useLeftOnMatches if true, uses concepts from the left model if concepts with common
62      *        keys are found, if false it uses the concepts from the right model
63      * @param failOnDuplicateKeys whether to fail or not on the occurence of duplicate concept keys
64      * @return the new Destination Model
65      * @throws ApexModelException on model transfer errors
66      */
67     public static AxPolicyModel getMergedPolicyModel(final AxPolicyModel leftPolicyModel,
68         final AxPolicyModel rightPolicyModel, final boolean useLeftOnMatches, final boolean failOnDuplicateKeys)
69         throws ApexModelException {
70         return getMergedPolicyModel(leftPolicyModel, rightPolicyModel, useLeftOnMatches, false, failOnDuplicateKeys);
71     }
72
73     /**
74      * Get a merged policy model with information from two policy models merged into a larger policy
75      * model.
76      *
77      * @param leftPolicyModel the source Apex Model
78      * @param rightPolicyModel the policies to include in sub policy model
79      * @param useLeftOnMatches if true, uses concepts from the left model if concepts with common
80      *        keys are found, if false it uses the concepts from the right model
81      * @param ignoreInvalidSource Ignore errors on the source model, do the best you can
82      * @param failOnDuplicateKeys whether to fail or not on the occurence of duplicate concept keys
83      * @return the new Destination Model
84      * @throws ApexModelException on model transfer errors
85      */
86     public static AxPolicyModel getMergedPolicyModel(final AxPolicyModel leftPolicyModel,
87         final AxPolicyModel rightPolicyModel, final boolean useLeftOnMatches, final boolean ignoreInvalidSource,
88         final boolean failOnDuplicateKeys) throws ApexModelException {
89
90         if (!ignoreInvalidSource) {
91             validateModels(leftPolicyModel, "left");
92             validateModels(rightPolicyModel, "right");
93         }
94
95         // The new policy model uses the favoured copy side as its base
96         final AxPolicyModel mergedPolicyModel =
97             (useLeftOnMatches ? new AxPolicyModel(leftPolicyModel) : new AxPolicyModel(rightPolicyModel));
98
99         // The Compared to policy model is the unfavoured side
100         final AxPolicyModel copyFromPolicyModel =
101             (useLeftOnMatches ? new AxPolicyModel(rightPolicyModel) : new AxPolicyModel(leftPolicyModel));
102
103         Map<AxArtifactKey, AxKeyInfo> mergedKeyInfoMap = mergedPolicyModel.getKeyInformation().getKeyInfoMap();
104         Map<AxArtifactKey, AxContextSchema> mergedSchemasMap = mergedPolicyModel.getSchemas().getSchemasMap();
105         Map<AxArtifactKey, AxEvent> mergedEventMap = mergedPolicyModel.getEvents().getEventMap();
106         Map<AxArtifactKey, AxContextAlbum> mergedAlbumsMap = mergedPolicyModel.getAlbums().getAlbumsMap();
107         Map<AxArtifactKey, AxTask> mergedTaskMap = mergedPolicyModel.getTasks().getTaskMap();
108         Map<AxArtifactKey, AxPolicy> mergedPolicyMap = mergedPolicyModel.getPolicies().getPolicyMap();
109
110         Map<AxArtifactKey, AxKeyInfo> copyOverKeyInfoMap = copyFromPolicyModel.getKeyInformation().getKeyInfoMap();
111         Map<AxArtifactKey, AxContextSchema> copyOverSchemasMap = copyFromPolicyModel.getSchemas().getSchemasMap();
112         Map<AxArtifactKey, AxEvent> copyOverEventMap = copyFromPolicyModel.getEvents().getEventMap();
113         Map<AxArtifactKey, AxContextAlbum> copyOverAlbumsMap = copyFromPolicyModel.getAlbums().getAlbumsMap();
114         Map<AxArtifactKey, AxTask> copyOverTaskMap = copyFromPolicyModel.getTasks().getTaskMap();
115         Map<AxArtifactKey, AxPolicy> copyOverPolicyMap = copyFromPolicyModel.getPolicies().getPolicyMap();
116
117         if (failOnDuplicateKeys) {
118             StringBuilder errorMessage = new StringBuilder();
119             checkForDuplicateItem(mergedSchemasMap, copyOverSchemasMap, errorMessage, "schema");
120             checkForDuplicateItem(mergedEventMap, copyOverEventMap, errorMessage, "event");
121             checkForDuplicateItem(mergedAlbumsMap, copyOverAlbumsMap, errorMessage, "album");
122             checkForDuplicateItem(mergedTaskMap, copyOverTaskMap, errorMessage, "task");
123             checkForDuplicateItem(mergedPolicyMap, copyOverPolicyMap, errorMessage, "policy");
124             if (errorMessage.length() > 0) {
125                 throw new ApexModelException(errorMessage.toString());
126             }
127         } else {
128             //  Remove entries that already exist
129             copyOverKeyInfoMap.keySet().removeIf(mergedKeyInfoMap::containsKey);
130             copyOverSchemasMap.keySet().removeIf(mergedSchemasMap::containsKey);
131             copyOverEventMap.keySet().removeIf(mergedEventMap::containsKey);
132             copyOverAlbumsMap.keySet().removeIf(mergedAlbumsMap::containsKey);
133             copyOverTaskMap.keySet().removeIf(mergedTaskMap::containsKey);
134             copyOverPolicyMap.keySet().removeIf(mergedPolicyMap::containsKey);
135         }
136         // Now add all the concepts that must be copied over
137         mergedKeyInfoMap.putAll(copyOverKeyInfoMap);
138         mergedSchemasMap.putAll(copyOverSchemasMap);
139         mergedEventMap.putAll(copyOverEventMap);
140         mergedAlbumsMap.putAll(copyOverAlbumsMap);
141         mergedTaskMap.putAll(copyOverTaskMap);
142         mergedPolicyMap.putAll(copyOverPolicyMap);
143
144         // That's it, return the model
145         return mergedPolicyModel;
146     }
147
148     private static <V> void checkForDuplicateItem(Map<AxArtifactKey, V> mergedItemsMap,
149         Map<AxArtifactKey, V> copyOverItemsMap, StringBuilder errorMessage, String itemType) {
150         for (Entry<AxArtifactKey, V> entry : copyOverItemsMap.entrySet()) {
151             V item = mergedItemsMap.get(entry.getKey());
152             // same item with different definitions cannot occur in multiple policies
153             if (null != item) {
154                 if (item.equals(entry.getValue())) {
155                     LOGGER.info("Same {} - {} is used by multiple policies.", itemType, entry.getKey().getId());
156                 } else {
157                     errorMessage.append("\n Same " + itemType + " - ").append(entry.getKey().getId())
158                         .append(" with different definitions used in different policies");
159                 }
160             }
161         }
162     }
163
164     private static void validateModels(AxPolicyModel policyModel, String position) throws ApexModelException {
165         // Validate the model
166         final AxValidationResult validationResult = new AxValidationResult();
167         policyModel.validate(validationResult);
168         if (!validationResult.isValid()) {
169             String message = position + " model is invalid: " + validationResult.toString();
170             LOGGER.warn(message);
171             throw new ApexModelException(message);
172         }
173     }
174 }