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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.apex.model.policymodel.handling;
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;
40 * Helper class used to merge information from two policy models together into a single policy
43 * @author Liam Fallon (liam.fallon@ericsson.com)
45 public final class PolicyModelMerger {
46 private static final XLogger LOGGER = XLoggerFactory.getXLogger(PolicyModelMerger.class);
49 * Private constructor used to prevent sub class instantiation.
51 private PolicyModelMerger() {
55 * Get a merged policy model with information from two policy models merged into a larger policy
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
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);
73 * Get a merged policy model with information from two policy models merged into a larger policy
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
85 public static AxPolicyModel getMergedPolicyModel(final AxPolicyModel leftPolicyModel,
86 final AxPolicyModel rightPolicyModel, final boolean useLeftOnMatches, final boolean ignoreInvalidSource,
87 final boolean failOnDuplicateKeys) throws ApexModelException {
89 if (!ignoreInvalidSource) {
90 validateModels(leftPolicyModel, "left");
91 validateModels(rightPolicyModel, "right");
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));
98 // The Compared to policy model is the unfavoured side
99 final AxPolicyModel copyFromPolicyModel =
100 (useLeftOnMatches ? new AxPolicyModel(rightPolicyModel) : new AxPolicyModel(leftPolicyModel));
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();
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();
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());
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);
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);
143 // That's it, return the model
144 return mergedPolicyModel;
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());
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
162 if (item.equals(entry.getValue())) {
163 LOGGER.info("Same {} - {} is used by multiple policies.", itemType, entry.getKey().getId());
165 errorMessage.append("\n Same " + itemType + " - ").append(entry.getKey().getId())
166 .append(" with different definitions used in different policies");
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);