57ebcf6822d39d3e23fd549198ee3507a97657fe
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / tosca / ComponentCache.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2020 AT&T Intellectual Property. 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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  * ============LICENSE_END=========================================================
19  */
20 package org.openecomp.sdc.be.tosca;
21
22 import static org.openecomp.sdc.be.utils.CommonBeUtils.compareAsdcComponentVersions;
23
24 import io.vavr.collection.HashMap;
25 import io.vavr.collection.Map;
26 import io.vavr.collection.Stream;
27 import java.util.function.BiConsumer;
28 import java.util.function.BinaryOperator;
29 import lombok.EqualsAndHashCode;
30 import org.apache.commons.lang3.tuple.ImmutableTriple;
31 import org.openecomp.sdc.be.model.Component;
32
33 /**
34  * Provides caching abilities for components
35  */
36 public final class ComponentCache {
37     // TODO: Make this final whenever possible. The current code using the class
38
39     private final BinaryOperator<CacheEntry> merge;
40     // does not allow this.
41     private Map<String, CacheEntry> entries = HashMap.empty();
42
43     private ComponentCache(BinaryOperator<CacheEntry> merge) {
44         this.merge = merge;
45     }
46
47     /**
48      * Creates an overwritable cache based on a merging strategy
49      *
50      * @param merge The strategy used to merge two values which keys are the same
51      */
52     public static ComponentCache overwritable(BinaryOperator<CacheEntry> merge) {
53         return new ComponentCache(merge);
54     }
55
56     /**
57      * Creates a cached entry
58      *
59      * @param id        The id of the entry
60      * @param fileName  the filename of the entry
61      * @param component the cached component
62      */
63     public static CacheEntry entry(String id, String fileName, Component component) {
64         return new CacheEntry(id, fileName, component);
65     }
66
67     /**
68      * Decorate the cache with a listener called whenever a value is merged
69      *
70      * @param bc the consumer called when a value is merged
71      */
72     public ComponentCache onMerge(BiConsumer<CacheEntry, CacheEntry> bc) {
73         return new ComponentCache((oldValue, newValue) -> {
74             CacheEntry value = merge.apply(oldValue, newValue);
75             if (value.equals(newValue)) {
76                 bc.accept(oldValue, newValue);
77             }
78             return value;
79         });
80     }
81
82     // For now we'll keep this as is, to prevent the refactoring to be too big
83     public Iterable<ImmutableTriple<String, String, Component>> iterable() {
84         return all().map(e -> new ImmutableTriple<>(e.id, e.fileName, e.component));
85     }
86
87     /**
88      * Streams all the entries stored in the cache
89      */
90     public Stream<CacheEntry> all() {
91         return entries.values().toStream();
92     }
93     // TODO: Encapsulate the cache and expose functions to interact with it
94
95     /**
96      * Tells if an entry has been cached for a specific key
97      *
98      * @param key The key used to index the entry
99      */
100     public boolean notCached(String key) {
101         return !entries.get(key).isDefined();
102     }
103
104     /**
105      * Store an entry in the cache. Keep in mind that currently this mutates the cache and does not work in a referentially transparent way (This
106      * should be fixed whenever possible).
107      *
108      * @param id        The id of the entry
109      * @param fileName  the filename of the entry
110      * @param component the cached component
111      */
112     public ComponentCache put(String id, String fileName, Component component) {
113         String uuid = component.getInvariantUUID();
114         CacheEntry entry = new CacheEntry(id, fileName, component);
115         // TODO: Make the entries final whenever possible. The current code using the class does not allow this
116         entries = entries.put(uuid, entry, merge);
117         return this;
118     }
119
120     public interface MergeStrategy {
121
122         /**
123          * A strategy designed to favour the latest component version when merging two cached entries
124          */
125         static BinaryOperator<CacheEntry> overwriteIfSameVersions() {
126             return (oldValue, newValue) -> compareAsdcComponentVersions(newValue.getComponentVersion(), oldValue.getComponentVersion()) ? newValue
127                 : oldValue;
128         }
129     }
130
131     /**
132      * Entry stored by the cache
133      */
134     @EqualsAndHashCode
135     public static final class CacheEntry {
136
137         final String id;
138         final String fileName;
139         final Component component;
140
141         CacheEntry(String id, String fileName, Component component) {
142             this.id = id;
143             this.fileName = fileName;
144             this.component = component;
145         }
146
147         public String getComponentVersion() {
148             return component.getVersion();
149         }
150     }
151 }