Changes for checkstyle 8.32
[policy/apex-pdp.git] / context / context-management / src / main / java / org / onap / policy / apex / context / impl / ContextAlbumImpl.java
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.context.impl;
23
24 import java.util.AbstractMap.SimpleEntry;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.HashSet;
28 import java.util.Map;
29 import java.util.Set;
30 import org.onap.policy.apex.context.ContextAlbum;
31 import org.onap.policy.apex.context.ContextException;
32 import org.onap.policy.apex.context.ContextRuntimeException;
33 import org.onap.policy.apex.context.Distributor;
34 import org.onap.policy.apex.context.SchemaHelper;
35 import org.onap.policy.apex.context.impl.schema.SchemaHelperFactory;
36 import org.onap.policy.apex.context.monitoring.ContextMonitor;
37 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
38 import org.onap.policy.apex.model.basicmodel.concepts.AxConcept;
39 import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
40 import org.onap.policy.common.utils.validation.Assertions;
41 import org.slf4j.ext.XLogger;
42 import org.slf4j.ext.XLoggerFactory;
43
44 /**
45  * The Class ContextAlbumImpl implements the methods on the {@link ContextAlbum} interface. It implements the getters
46  * and setters on the {@link Map} and uses the {@link Distributor} to handle distribution and locking.
47  *
48  * @author Liam Fallon (liam.fallon@ericsson.com)
49  */
50 public final class ContextAlbumImpl implements ContextAlbum, Comparable<ContextAlbumImpl> {
51     // Logger for this class
52     private static final XLogger LOGGER = XLoggerFactory.getXLogger(ContextAlbumImpl.class);
53
54     // Recurring string constants
55     private static final String NULL_VALUES_ILLEGAL = "null values are illegal on method parameter \"key\"";
56     private static final String ALBUM = "album \"";
57
58     // The definition of this context album
59     private final AxContextAlbum albumDefinition;
60
61     /// The map holding the items and their values for this context album
62     private final Map<String, Object> albumMap;
63
64     // The artifact stack of the artifacts currently using the context album
65     private AxConcept[] userArtifactStack = null;
66
67     // The context distributor we are using
68     private final Distributor distributor;
69
70     // The schema helper that handles translations of Java objects for this album
71     private SchemaHelper schemaHelper;
72
73     // The context monitor for this context album
74     private ContextMonitor monitor = null;
75
76     /**
77      * Constructor, instantiate the context album.
78      *
79      * @param albumDefinition The model definition of this context album
80      * @param distributor The context distributor passed to us to distribute context across ContextAlbum instances
81      * @param albumMap the album map
82      * @throws ContextException on errors creating context albums
83      */
84     public ContextAlbumImpl(final AxContextAlbum albumDefinition, final Distributor distributor,
85             final Map<String, Object> albumMap) throws ContextException {
86         Assertions.argumentNotNull(albumDefinition, "Context album definition may not be null");
87         Assertions.argumentNotNull(distributor, "Distributor may not be null");
88         Assertions.argumentNotNull(albumMap, "Album map may not be null");
89
90         this.albumDefinition = albumDefinition;
91
92         // Use the context distributor passed to us
93         this.distributor = distributor;
94
95         // The map to use to store objects
96         this.albumMap = albumMap;
97
98         try {
99             // Get a schema helper to manage the translations between objects on the album map for this album
100             schemaHelper = new SchemaHelperFactory().createSchemaHelper(albumDefinition.getKey(),
101                     albumDefinition.getItemSchema());
102         } catch (final ContextRuntimeException e) {
103             final String resultString = "could not initiate schema management for context album " + albumDefinition;
104             LOGGER.warn(resultString, e);
105             throw new ContextException(resultString, e);
106         }
107
108         // Create the context monitor
109         monitor = new ContextMonitor();
110
111     }
112
113     /**
114      * {@inheritDoc}.
115      */
116     @Override
117     public AxArtifactKey getKey() {
118         return albumDefinition.getKey();
119     }
120
121     /**
122      * {@inheritDoc}.
123      */
124     @Override
125     public String getName() {
126         return albumDefinition.getKey().getName();
127     }
128
129     /**
130      * {@inheritDoc}.
131      */
132     @Override
133     public AxContextAlbum getAlbumDefinition() {
134         return albumDefinition;
135     }
136
137     /**
138      * {@inheritDoc}.
139      */
140     @Override
141     public SchemaHelper getSchemaHelper() {
142         return schemaHelper;
143     }
144
145     /**
146      * {@inheritDoc}.
147      */
148     @Override
149     public void lockForReading(final String keyOnAlbum) throws ContextException {
150         distributor.lockForReading(albumDefinition.getKey(), keyOnAlbum);
151         monitor.monitorReadLock(albumDefinition.getKey(), albumDefinition.getItemSchema(), keyOnAlbum,
152                 userArtifactStack);
153     }
154
155     /**
156      * {@inheritDoc}.
157      */
158     @Override
159     public void lockForWriting(final String keyOnAlbum) throws ContextException {
160         distributor.lockForWriting(albumDefinition.getKey(), keyOnAlbum);
161         monitor.monitorWriteLock(albumDefinition.getKey(), albumDefinition.getItemSchema(), keyOnAlbum,
162                 userArtifactStack);
163     }
164
165     /**
166      * {@inheritDoc}.
167      */
168     @Override
169     public void unlockForReading(final String keyOnAlbum) throws ContextException {
170         distributor.unlockForReading(albumDefinition.getKey(), keyOnAlbum);
171         monitor.monitorReadUnlock(albumDefinition.getKey(), albumDefinition.getItemSchema(), keyOnAlbum,
172                 userArtifactStack);
173     }
174
175     /**
176      * {@inheritDoc}.
177      */
178     @Override
179     public void unlockForWriting(final String keyOnAlbum) throws ContextException {
180         distributor.unlockForWriting(albumDefinition.getKey(), keyOnAlbum);
181         monitor.monitorWriteUnlock(albumDefinition.getKey(), albumDefinition.getItemSchema(), keyOnAlbum,
182                 userArtifactStack);
183     }
184
185     /**
186      * {@inheritDoc}.
187      */
188     @Override
189     public AxConcept[] getUserArtifactStack() {
190         return userArtifactStack;
191     }
192
193     /**
194      * {@inheritDoc}.
195      */
196     @Override
197     public void setUserArtifactStack(final AxConcept[] userArtifactStack) {
198         this.userArtifactStack = userArtifactStack;
199     }
200
201     /**
202      * {@inheritDoc}.
203      */
204     @Override
205     public void flush() throws ContextException {
206         distributor.flushContextAlbum(this);
207     }
208
209     /*
210      * The Map interface
211      */
212
213     /**
214      * {@inheritDoc}.
215      */
216     @Override
217     public int size() {
218         return albumMap.size();
219     }
220
221     /**
222      * {@inheritDoc}.
223      */
224     @Override
225     public boolean isEmpty() {
226         return albumMap.isEmpty();
227     }
228
229     /**
230      * {@inheritDoc}.
231      */
232     @Override
233     public boolean containsKey(final Object key) {
234         if (key == null) {
235             LOGGER.warn(NULL_VALUES_ILLEGAL);
236             throw new ContextRuntimeException(NULL_VALUES_ILLEGAL);
237         }
238
239         return albumMap.containsKey(key);
240     }
241
242     /**
243      * {@inheritDoc}.
244      */
245     @Override
246     public boolean containsValue(final Object value) {
247         if (value == null) {
248             LOGGER.warn("null values are illegal on method parameter \"value\"");
249             throw new ContextRuntimeException("null values are illegal on method parameter \"value\"");
250         }
251
252         return albumMap.containsValue(value);
253     }
254
255     /**
256      * {@inheritDoc}.
257      */
258     @Override
259     public Object get(final Object key) {
260         if (key == null) {
261             final String returnString =
262                     ALBUM + albumDefinition.getId() + "\" null keys are illegal on keys for get()";
263             LOGGER.warn(returnString);
264             throw new ContextRuntimeException(returnString);
265         }
266
267         final Object item = albumMap.get(key);
268         if (item == null) {
269             return null;
270         }
271
272         // Get the context value and monitor it
273         monitor.monitorGet(albumDefinition.getKey(), albumDefinition.getItemSchema(), key.toString(), item,
274                 userArtifactStack);
275         return item;
276     }
277
278     /**
279      * {@inheritDoc}.
280      */
281     @Override
282     public Set<String> keySet() {
283         return albumMap.keySet();
284     }
285
286     /**
287      * {@inheritDoc}.
288      */
289     @Override
290     public Collection<Object> values() {
291         // Build the key set and return it
292         final ArrayList<Object> valueList = new ArrayList<>();
293
294         for (final Entry<String, Object> contextAlbumEntry : albumMap.entrySet()) {
295             final Object item = contextAlbumEntry.getValue();
296             monitor.monitorGet(albumDefinition.getKey(), albumDefinition.getItemSchema(), contextAlbumEntry.getKey(),
297                     item, userArtifactStack);
298             valueList.add(contextAlbumEntry.getValue());
299         }
300
301         return valueList;
302     }
303
304     /**
305      * {@inheritDoc}.
306      */
307     @Override
308     public Set<Entry<String, Object>> entrySet() {
309         // Build the entry set and return it
310         final Set<Entry<String, Object>> entrySet = new HashSet<>();
311
312         for (final Entry<String, Object> contextAlbumEntry : albumMap.entrySet()) {
313             final Object item = contextAlbumEntry.getValue();
314             monitor.monitorGet(albumDefinition.getKey(), albumDefinition.getItemSchema(), contextAlbumEntry.getKey(),
315                     item, userArtifactStack);
316             entrySet.add(new SimpleEntry<>(contextAlbumEntry.getKey(), contextAlbumEntry.getValue()));
317         }
318
319         return entrySet;
320     }
321
322     /**
323      * {@inheritDoc}.
324      */
325     @Override
326     public Object put(final String key, final Object incomingValue) {
327         if (key == null) {
328             final String returnString =
329                     ALBUM + albumDefinition.getId() + "\" null keys are illegal on keys for put()";
330             LOGGER.warn(returnString);
331             throw new ContextRuntimeException(returnString);
332         }
333
334         if (incomingValue == null) {
335             final String returnString = ALBUM + albumDefinition.getId() + "\" null values are illegal on key \""
336                     + key + "\" for put()";
337             LOGGER.warn(returnString);
338             throw new ContextRuntimeException(returnString);
339         }
340
341         if (!albumDefinition.isWritable()) {
342             final String returnString = ALBUM + albumDefinition.getId()
343                     + "\" put() not allowed on read only albums for key=\"" + key + "\", value=\"" + incomingValue;
344             LOGGER.warn(returnString);
345             throw new ContextRuntimeException(returnString);
346         }
347
348         try {
349             // Translate the object to a schema object
350             final Object valueToPut = schemaHelper.unmarshal(incomingValue);
351
352             // Check if the key is already in the map
353             if (albumMap.containsKey(key)) {
354                 // Update the value in the context item and in the context value map
355                 monitor.monitorSet(albumDefinition.getKey(), albumDefinition.getItemSchema(), key, incomingValue,
356                         userArtifactStack);
357             } else {
358                 // Update the value in the context item and in the context value map
359                 monitor.monitorInit(albumDefinition.getKey(), albumDefinition.getItemSchema(), key, incomingValue,
360                         userArtifactStack);
361             }
362
363             // Put the translated value on the map and return the old map value
364             return albumMap.put(key, valueToPut);
365         } catch (final ContextRuntimeException e) {
366             final String returnString = "Failed to set context value for key \"" + key + "\" in album \""
367                     + albumDefinition.getId() + "\": " + e.getMessage();
368             LOGGER.warn(returnString);
369             throw new ContextRuntimeException(returnString, e);
370         }
371     }
372
373     /**
374      * {@inheritDoc}.
375      */
376     @Override
377     public void putAll(final Map<? extends String, ? extends Object> incomingContextAlbum) {
378         if (!albumDefinition.isWritable()) {
379             final String returnString =
380                     ALBUM + albumDefinition.getId() + "\" putAll() not allowed on read only albums";
381             LOGGER.warn(returnString);
382             throw new ContextRuntimeException(returnString);
383         }
384
385         // Sanity check on incoming context
386         Assertions.argumentOfClassNotNull(incomingContextAlbum, ContextRuntimeException.class,
387                 "cannot update context, context album is null");
388
389         // Iterate over the incoming context
390         for (final Entry<String, Object> entry : albumMap.entrySet()) {
391             synchronized (albumDefinition) {
392                 // Get the key for the incoming name
393                 final Object incomingDataItem = incomingContextAlbum.get(entry.getKey());
394                 if (incomingDataItem != null) {
395                     // Update the value the context album
396                     put(entry.getKey(), incomingDataItem);
397                 }
398             }
399         }
400
401         // Put all the objects on the context album
402         for (final Entry<? extends String, ? extends Object> incomingMapEntry : incomingContextAlbum.entrySet()) {
403             // Put the entry on the map
404             this.put(incomingMapEntry.getKey(), incomingMapEntry.getValue());
405         }
406     }
407
408     /**
409      * {@inheritDoc}.
410      */
411     @Override
412     public Object remove(final Object key) {
413         if (!albumDefinition.isWritable()) {
414             final String returnString = ALBUM + albumDefinition.getId()
415                     + "\" remove() not allowed on read only albums for key=\"" + key + "\"";
416             LOGGER.warn(returnString);
417             throw new ContextRuntimeException(returnString);
418         }
419
420         if (key == null) {
421             LOGGER.warn(NULL_VALUES_ILLEGAL);
422             throw new ContextRuntimeException("null values are illegal on method parameter \"keyID\"");
423         }
424
425         // Delete the item
426         final Object removedValue = albumMap.remove(key);
427         monitor.monitorDelete(albumDefinition.getKey(), albumDefinition.getItemSchema(), key.toString(), removedValue,
428                 userArtifactStack);
429
430         // Return the value of the deleted item
431         return removedValue;
432     }
433
434     /**
435      * {@inheritDoc}.
436      */
437     @Override
438     public void clear() {
439         if (!albumDefinition.isWritable()) {
440             final String returnString =
441                     ALBUM + albumDefinition.getId() + "\" clear() not allowed on read only albums";
442             LOGGER.warn(returnString);
443             throw new ContextRuntimeException(returnString);
444         }
445
446         // Monitor deletion of each item
447         for (final Entry<String, Object> contextAlbumEntry : albumMap.entrySet()) {
448             final Object item = contextAlbumEntry.getValue();
449             monitor.monitorDelete(albumDefinition.getKey(), albumDefinition.getItemSchema(), contextAlbumEntry.getKey(),
450                     item, userArtifactStack);
451         }
452
453         // Clear the map
454         albumMap.clear();
455     }
456
457     /**
458      * {@inheritDoc}.
459      */
460     @Override
461     public int compareTo(ContextAlbumImpl otherContextAlbumImpl) {
462         return (equals(otherContextAlbumImpl) ? 0 : 1);
463     }
464
465     /**
466      * {@inheritDoc}.
467      */
468     @Override
469     public int hashCode() {
470         final int prime = 31;
471         int result = 1;
472         result = prime * result + albumDefinition.hashCode();
473         result = prime * result + albumMap.hashCode();
474         return result;
475     }
476
477     /**
478      * {@inheritDoc}.
479      */
480     @Override
481     public boolean equals(Object obj) {
482         if (this == obj) {
483             return true;
484         }
485         if (obj == null) {
486             return false;
487         }
488         if (!(obj instanceof ContextAlbumImpl)) {
489             return false;
490         }
491         ContextAlbumImpl other = (ContextAlbumImpl) obj;
492         if (!albumDefinition.equals(other.albumDefinition)) {
493             return false;
494         }
495         return albumMap.equals(other.albumMap);
496     }
497 }