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