1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
|
/*-
* ============LICENSE_START=======================================================
* Copyright (C) 2016-2018 Ericsson. All rights reserved.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* ============LICENSE_END=========================================================
*/
package org.onap.policy.apex.core.engine.context;
import com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
import org.onap.policy.apex.context.ContextAlbum;
import org.onap.policy.apex.context.ContextException;
import org.onap.policy.apex.context.Distributor;
import org.onap.policy.apex.context.impl.distribution.DistributorFactory;
import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
import org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetter;
import org.onap.policy.apex.model.basicmodel.concepts.AxConceptGetterImpl;
import org.onap.policy.apex.model.basicmodel.service.ModelService;
import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbums;
import org.onap.policy.apex.model.contextmodel.handling.ContextComparer;
import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
import org.onap.policy.apex.model.utilities.comparison.KeyedMapDifference;
/**
* This class manages the internal context for an Apex engine. This class is not thread safe and need not be because
* each Context object is owned by one and only one ApexEngine, which runs in a single thread and only runs one policy
* at a time. Therefore there is only ever one policy using a Context object at a time. The currentPolicyContextAlbum is
* set on the Context object by the StateMachineExecutor each time a policy is triggered.
*
* @author Liam Fallon
*/
public class ApexInternalContext implements AxConceptGetter<ContextAlbum> {
// The key of the currently running Apex model
private AxArtifactKey key;
// The context albums being used in this engine
private final NavigableMap<AxArtifactKey, ContextAlbum> contextAlbums =
Maps.synchronizedNavigableMap(new TreeMap<AxArtifactKey, ContextAlbum>());
// The internal context uses a context distributor to handle distribution of context across multiple instances
private Distributor contextDistributor = null;
// The key of the current policy, used to return the correct policy context album to the user
private AxArtifactKey currentPolicyKey = null;
/**
* Constructor, instantiate the context object from the Apex model.
*
* @param apexPolicyModel the apex model
* @throws ContextException On errors on context setting
*/
public ApexInternalContext(final AxPolicyModel apexPolicyModel) throws ContextException {
if (apexPolicyModel == null) {
throw new ContextException("internal context update failed, supplied model is null");
}
apexPolicyModel.register();
// The context distributor used to distribute context across policy engine instances
contextDistributor = new DistributorFactory().getDistributor(apexPolicyModel.getKey());
// Set up the context albums for this engine
for (final AxArtifactKey contextAlbumKey : ModelService.getModel(AxContextAlbums.class).getAlbumsMap()
.keySet()) {
contextAlbums.put(contextAlbumKey, contextDistributor.createContextAlbum(contextAlbumKey));
}
// Record the key of the current model
key = apexPolicyModel.getKey();
}
/**
* Get the key of the internal context, which is the same as the key of the engine.
*
* @return the key
*/
public AxArtifactKey getKey() {
return key;
}
/**
* Get the context albums of the engine.
*
* @return the context albums
*/
public Map<AxArtifactKey, ContextAlbum> getContextAlbums() {
return contextAlbums;
}
/**
* Update the current context so that it aligns with this incoming model, transferring context values if they exist
* in the new model.
*
* @param newPolicyModel The new incoming Apex model to use for context
* @throws ContextException On errors on context setting
*/
public void update(final AxPolicyModel newPolicyModel) throws ContextException {
if (newPolicyModel == null) {
throw new ContextException("internal context update failed, supplied model is null");
}
// Get the differences between the existing context and the new context
final KeyedMapDifference<AxArtifactKey, AxContextAlbum> contextDifference =
new ContextComparer().compare(ModelService.getModel(AxContextAlbums.class), newPolicyModel.getAlbums());
// Handle the updated maps
for (final Entry<AxArtifactKey, List<AxContextAlbum>> contextAlbumEntry : contextDifference.getDifferentValues()
.entrySet()) {
// Compare the updated maps
final AxContextAlbum currentContextAlbum = contextAlbumEntry.getValue().get(0);
final AxContextAlbum newContextAlbum = contextAlbumEntry.getValue().get(1);
// Check that the schemas are the same on the old and new context albums
if (!currentContextAlbum.getItemSchema().equals(newContextAlbum.getItemSchema())) {
// The schema is different, throw an exception because the schema should not change if the key of the
// album has not changed
throw new ContextException("internal context update failed on context album \""
+ contextAlbumEntry.getKey().getId() + "\" in model \"" + key.getId() + "\", schema \""
+ currentContextAlbum.getItemSchema().getId()
+ "\" on existing context model does not equal schema \""
+ newContextAlbum.getItemSchema().getId() + "\" on incoming model");
}
}
// Remove maps that are no longer used
for (final Entry<AxArtifactKey, AxContextAlbum> removedContextAlbumEntry : contextDifference.getLeftOnly()
.entrySet()) {
contextDistributor.removeContextAlbum(removedContextAlbumEntry.getValue());
contextAlbums.remove(removedContextAlbumEntry.getKey());
}
// We switch over to the new Apex model
newPolicyModel.register();
// Set up the new context albums
for (final AxArtifactKey contextAlbumKey : contextDifference.getRightOnly().keySet()) {
contextAlbums.put(contextAlbumKey, contextDistributor.createContextAlbum(contextAlbumKey));
}
// Record the key of the current model
key = newPolicyModel.getKey();
}
/**
* Clear the internal context.
*
* @throws ContextException on clearing errors
*/
public void clear() throws ContextException {
// Clear all context in the distributor
contextDistributor.clear();
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "ApexInternalContext [contextAlbums=" + contextAlbums + ", contextDistributor=" + contextDistributor
+ ", currentPolicyKey=" + currentPolicyKey + "]";
}
/*
* (non-Javadoc)
*
* @see
* org.onap.policy.apex.core.basicmodel.concepts.AxConceptGetter#get(org.onap.policy.apex.core.basicmodel.concepts.
* AxArtifactKey)
*/
@Override
public ContextAlbum get(final AxArtifactKey conceptKey) {
return new AxConceptGetterImpl<>(contextAlbums).get(conceptKey);
}
/*
* (non-Javadoc)
*
* @see org.onap.policy.apex.core.basicmodel.concepts.AxConceptGetter#get(java.lang.String)
*/
@Override
public ContextAlbum get(final String conceptKeyName) {
return new AxConceptGetterImpl<>(contextAlbums).get(conceptKeyName);
}
/*
* (non-Javadoc)
*
* @see org.onap.policy.apex.core.basicmodel.concepts.AxConceptGetter#get(java.lang.String, java.lang.String)
*/
@Override
public ContextAlbum get(final String conceptKeyName, final String conceptKeyVersion) {
return new AxConceptGetterImpl<>(contextAlbums).get(conceptKeyName, conceptKeyVersion);
}
/*
* (non-Javadoc)
*
* @see org.onap.policy.apex.core.basicmodel.concepts.AxConceptGetter#getAll(java.lang.String)
*/
@Override
public Set<ContextAlbum> getAll(final String conceptKeyName) {
return new AxConceptGetterImpl<>(contextAlbums).getAll(conceptKeyName);
}
/*
* (non-Javadoc)
*
* @see org.onap.policy.apex.core.basicmodel.concepts.AxConceptGetter#getAll(java.lang.String, java.lang.String)
*/
@Override
public Set<ContextAlbum> getAll(final String conceptKeyName, final String conceptKeyVersion) {
return new AxConceptGetterImpl<>(contextAlbums).getAll(conceptKeyName, conceptKeyVersion);
}
}
|