2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2016-2018 Ericsson. All rights reserved.
4 * Modifications Copyright (C) 2019 Nordix Foundation.
5 * Modifications Copyright (C) 2020-2021 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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 * SPDX-License-Identifier: Apache-2.0
20 * ============LICENSE_END=========================================================
23 package org.onap.policy.apex.model.policymodel.handling;
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;
41 * Helper class used to merge information from two policy models together into a single policy
44 * @author Liam Fallon (liam.fallon@ericsson.com)
46 public final class PolicyModelMerger {
47 private static final XLogger LOGGER = XLoggerFactory.getXLogger(PolicyModelMerger.class);
50 * Private constructor used to prevent sub class instantiation.
52 private PolicyModelMerger() {
56 * Get a merged policy model with information from two policy models merged into a larger policy
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
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);
74 * Get a merged policy model with information from two policy models merged into a larger policy
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
86 public static AxPolicyModel getMergedPolicyModel(final AxPolicyModel leftPolicyModel,
87 final AxPolicyModel rightPolicyModel, final boolean useLeftOnMatches, final boolean ignoreInvalidSource,
88 final boolean failOnDuplicateKeys) throws ApexModelException {
90 if (!ignoreInvalidSource) {
91 validateModels(leftPolicyModel, "left");
92 validateModels(rightPolicyModel, "right");
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));
99 // The Compared to policy model is the unfavoured side
100 final AxPolicyModel copyFromPolicyModel =
101 (useLeftOnMatches ? new AxPolicyModel(rightPolicyModel) : new AxPolicyModel(leftPolicyModel));
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();
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();
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());
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);
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);
144 // That's it, return the model
145 return mergedPolicyModel;
149 * Method to check for duplicate items.
151 * @param <V> the concept type
152 * @param mergedItemsMap the map to which items are copied
153 * @param copyOverItemsMap the map from where items are copied
154 * @param errorMessage error message in case of any duplicate concepts
155 * @param itemType the type of concept to specify distinguished error messages
157 public static <V> void checkForDuplicateItem(Map<AxArtifactKey, V> mergedItemsMap,
158 Map<AxArtifactKey, V> copyOverItemsMap, StringBuilder errorMessage, String itemType) {
159 for (Entry<AxArtifactKey, V> entry : copyOverItemsMap.entrySet()) {
160 V item = mergedItemsMap.get(entry.getKey());
161 // same item with different definitions cannot occur in multiple policies
163 if (item.equals(entry.getValue())) {
164 LOGGER.info("Same {} - {} is used by multiple policies.", itemType, entry.getKey().getId());
166 errorMessage.append("\n Same " + itemType + " - ").append(entry.getKey().getId())
167 .append(" with different definitions used in different policies");
173 private static void validateModels(AxPolicyModel policyModel, String position) throws ApexModelException {
174 // Validate the model
175 final AxValidationResult validationResult = new AxValidationResult();
176 policyModel.validate(validationResult);
177 if (!validationResult.isValid()) {
178 String message = position + " model is invalid: " + validationResult.toString();
179 LOGGER.warn(message);
180 throw new ApexModelException(message);