Upgrade SDC from Titan to Janus Graph
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / cache / ComponentCache.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 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
21 package org.openecomp.sdc.be.model.cache;
22
23 import fj.data.Either;
24 import org.apache.commons.lang3.tuple.ImmutablePair;
25 import org.apache.commons.lang3.tuple.ImmutableTriple;
26 import org.openecomp.sdc.be.config.BeEcompErrorManager;
27 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
28 import org.openecomp.sdc.be.config.Configuration;
29 import org.openecomp.sdc.be.config.Configuration.ApplicationL1CacheCatalogInfo;
30 import org.openecomp.sdc.be.config.Configuration.ApplicationL2CacheConfig;
31 import org.openecomp.sdc.be.config.ConfigurationManager;
32 import org.openecomp.sdc.be.dao.api.ActionStatus;
33 import org.openecomp.sdc.be.dao.cassandra.CassandraOperationStatus;
34 import org.openecomp.sdc.be.dao.cassandra.ComponentCassandraDao;
35 import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition;
36 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
37 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
38 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
39 import org.openecomp.sdc.be.model.*;
40 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
41 import org.openecomp.sdc.be.resources.data.ComponentCacheData;
42 import org.openecomp.sdc.common.log.wrappers.Logger;
43 import org.openecomp.sdc.common.util.SerializationUtils;
44 import org.openecomp.sdc.common.util.ZipUtil;
45 import org.springframework.beans.factory.annotation.Autowired;
46
47 import javax.annotation.PostConstruct;
48 import java.io.IOException;
49 import java.util.*;
50 import java.util.concurrent.locks.Lock;
51 import java.util.concurrent.locks.ReentrantReadWriteLock;
52 import java.util.function.Function;
53 import java.util.stream.Collectors;
54 import java.util.List;
55 import java.util.Map;
56 import java.util.Set;
57
58 @org.springframework.stereotype.Component("component-cache")
59 public class ComponentCache {
60
61     private static final String COMPONENT_CACHE_IS_DISABLED = "Component Cache is disabled";
62
63         private static final Logger log = Logger.getLogger(ComponentCache.class);
64
65     @Autowired
66     ComponentCassandraDao componentCassandraDao;
67
68     @Autowired
69     ToscaOperationFacade toscaOperationFacade;
70
71     private Map<ComponentTypeEnum, Map<String, Component>> catalogInMemoryCache = new HashMap<>();
72     private final ReentrantReadWriteLock rwCatalogLock = new ReentrantReadWriteLock();
73     private final Lock rCatalogLock = rwCatalogLock.readLock();
74     private final Lock wCatalogLock = rwCatalogLock.writeLock();
75
76     boolean enabled = true;
77     int catalogInMemorySizePerResource = 300;
78     int catalogInMemorySizePerService = 200;
79     int catalogInMemorySizePerProduct = 100;
80     boolean catalogInMemoryEnabled = true;
81     Map<ComponentTypeEnum, Integer> limitMemoryCatalogSizePerType = new HashMap<>();
82
83     @PostConstruct
84     public void init() {
85
86         Configuration configuration = ConfigurationManager.getConfigurationManager().getConfiguration();
87         if (configuration != null) {
88             ApplicationL2CacheConfig applicationL2Cache = configuration.getApplicationL2Cache();
89             if (applicationL2Cache != null) {
90                 this.enabled = applicationL2Cache.isEnabled();
91
92                 ApplicationL1CacheCatalogInfo catalog = applicationL2Cache.getCatalogL1Cache();
93                 if (catalog != null) {
94                     catalogInMemoryEnabled = catalog.getEnabled();
95                     catalogInMemorySizePerResource = catalog.getResourcesSizeInCache();
96                     catalogInMemorySizePerService = catalog.getServicesSizeInCache();
97                     catalogInMemorySizePerProduct = catalog.getProductsSizeInCache();
98                 }
99             }
100         }
101
102         ComponentTypeEnum[] typesForCache = { ComponentTypeEnum.RESOURCE, ComponentTypeEnum.SERVICE,
103                 ComponentTypeEnum.PRODUCT };
104         for (ComponentTypeEnum typeEnum : typesForCache) {
105             Map<String, Component> map = new HashMap<>();
106             catalogInMemoryCache.put(typeEnum, map);
107         }
108
109         limitMemoryCatalogSizePerType.put(ComponentTypeEnum.RESOURCE, catalogInMemorySizePerResource);
110         limitMemoryCatalogSizePerType.put(ComponentTypeEnum.SERVICE, catalogInMemorySizePerService);
111         limitMemoryCatalogSizePerType.put(ComponentTypeEnum.PRODUCT, catalogInMemorySizePerProduct);
112     }
113
114     public boolean isEnabled() {
115         return enabled;
116     }
117
118     public void setEnabled(boolean enabled) {
119         this.enabled = enabled;
120     }
121
122     public Either<Component, ActionStatus> getComponent(String componentUid, Long lastModificationTime,
123             Function<Component, Component> filterFieldsFunc) {
124
125         Either<ImmutablePair<Component, ComponentCacheData>, ActionStatus> componentFromCache = getComponentFromCache(
126                 componentUid, lastModificationTime, filterFieldsFunc);
127
128         if (componentFromCache.isRight()) {
129             return Either.right(componentFromCache.right().value());
130         }
131
132         return Either.left(componentFromCache.left().value().left);
133
134     }
135
136     public Either<List<ComponentCacheData>, ActionStatus> getAllComponentIdTimeAndType() {
137         if (!isEnabled()) {
138             return Either.right(ActionStatus.NOT_ALLOWED);
139         }
140
141         return componentCassandraDao
142                 .getAllComponentIdTimeAndType();
143
144     }
145
146     /**
147      * get components for catalog
148      *
149      * @param components
150      * @param componentTypeEnum
151      * @return
152      */
153     @Deprecated
154     public Either<ImmutableTriple<List<Component>, List<Component>, Set<String>>, ActionStatus> getComponentsForCatalog(
155             Set<String> components, ComponentTypeEnum componentTypeEnum) {
156
157         if (!isEnabled()) {
158             log.debug("In getComponentsForCatalog for type {}. Cache is disabled.",
159                     componentTypeEnum.name().toLowerCase());
160             return Either.right(ActionStatus.NOT_ALLOWED);
161         }
162         log.debug("In getComponentsForCatalog for type {}", componentTypeEnum.name().toLowerCase());
163
164         Function<List<Component>, List<Component>> filterFieldsFunc = this::filterForCatalog;
165
166         Set<String> leftComponentsForSearch = new HashSet<>();
167         leftComponentsForSearch.addAll(components);
168
169         // get components from inmemory cache
170         List<Component> componentsFromMemory = null;
171         if (catalogInMemoryEnabled) {
172             componentsFromMemory = getDataFromInMemoryCache(components, componentTypeEnum);
173             log.debug("The number of components of type {} fetched from memory is {}",
174                     componentTypeEnum.name().toLowerCase(),
175                     componentsFromMemory == null ? 0 : componentsFromMemory.size());
176             if (componentsFromMemory != null) {
177                 componentsFromMemory.forEach(p -> leftComponentsForSearch.remove(p.getUniqueId()));
178             }
179         } else {
180             log.debug("Catalog InMemory cache is disabled");
181         }
182
183         log.debug("Number of components from type {} needed to fetch is {}", componentTypeEnum.name().toLowerCase(),
184                 leftComponentsForSearch.size());
185
186         // get components from cassandra cache and filter each component
187         Either<ImmutableTriple<List<Component>, List<Component>, Set<String>>, ActionStatus> result = getComponents(
188                 leftComponentsForSearch, filterFieldsFunc);
189
190         if (result.isLeft()) {
191             // add inmemory components to the valid components(not dirty)
192             List<Component> foundComponents = result.left().value().getLeft();
193             if (componentsFromMemory != null) {
194                 foundComponents.addAll(componentsFromMemory);
195             }
196             if (catalogInMemoryEnabled) {
197                 updateCatalogInMemoryCacheWithCertified(foundComponents, componentTypeEnum);
198             }
199         }
200
201         return result;
202     }
203
204     /**
205      * @param foundComponents
206      * @param componentTypeEnum
207      */
208     private void updateCatalogInMemoryCacheWithCertified(List<Component> foundComponents,
209             ComponentTypeEnum componentTypeEnum) {
210
211         try {
212             wCatalogLock.lock();
213
214             long start = System.currentTimeMillis();
215             Map<String, Component> map = catalogInMemoryCache.get(componentTypeEnum);
216             int mapSizeBefore = map.size();
217             map.clear();
218             Map<String, Component> collect = foundComponents.stream()
219                     .filter(p -> p.getLifecycleState() == LifecycleStateEnum.CERTIFIED)
220                     .limit(limitMemoryCatalogSizePerType.get(componentTypeEnum))
221                     .collect(Collectors.toMap(Component::getUniqueId, p -> p));
222             map.putAll(collect);
223             log.debug(
224                     "Size of in memory cache for catalog {}(certified only): Before {}, After {}. Replacement Time is {} ms.",
225                     componentTypeEnum.name().toLowerCase(), mapSizeBefore, map.size(),
226                     System.currentTimeMillis() - start);
227         } finally {
228             wCatalogLock.unlock();
229         }
230
231     }
232
233     private List<Component> getDataFromInMemoryCache(Set<String> components, ComponentTypeEnum componentTypeEnum) {
234         List<Component> foundComponents = new ArrayList<>();
235
236         try {
237
238             rCatalogLock.lock();
239
240             Map<String, Component> map = catalogInMemoryCache.get(componentTypeEnum);
241             for (String compUid : components) {
242                 Component component = map.get(compUid);
243                 if (component != null) {
244                     foundComponents.add(component);
245                 }
246             }
247
248         } finally {
249             rCatalogLock.unlock();
250         }
251
252         return foundComponents;
253     }
254
255     /**
256      *
257      * get full components from cassandra. On each component apply filter
258      * function in order to remove unused members
259      *
260      * @param components
261      * @param filterFieldsFunc
262      * @return <found components, found dirty components, not found components
263      *         list> or Error
264      */
265     public Either<ImmutableTriple<List<Component>, List<Component>, Set<String>>, ActionStatus> getComponents(
266             Set<String> components, Function<List<Component>, List<Component>> filterFieldsFunc) {
267
268         if (!isEnabled()) {
269             log.debug(COMPONENT_CACHE_IS_DISABLED);
270             return Either.right(ActionStatus.NOT_ALLOWED);
271         }
272
273         Either<ImmutableTriple<List<Component>, List<Component>, Set<String>>, ActionStatus> componentsFull = getComponentsFull(
274                 components);
275
276         if (componentsFull.isRight()) {
277             return Either.right(componentsFull.right().value());
278         }
279
280         ImmutableTriple<List<Component>, List<Component>, Set<String>> immutableTriple = componentsFull.left().value();
281         List<Component> foundResources = immutableTriple.left;
282         List<Component> foundDirtyResources = immutableTriple.middle;
283         Set<String> notFoundResources = immutableTriple.right;
284
285         List<Component> filterdFoundResources = filterFieldsFunc.apply(foundResources);
286         List<Component> filterdFoundDirtyResources = filterFieldsFunc.apply(foundDirtyResources);
287
288         ImmutableTriple<List<Component>, List<Component>, Set<String>> result = new ImmutableTriple<>(
289                 filterdFoundResources, filterdFoundDirtyResources, notFoundResources);
290
291         return Either.left(result);
292
293     }
294
295     public Either<ImmutableTriple<List<Component>, List<Component>, Set<String>>, ActionStatus> getComponentsForLeftPanel(
296             ComponentTypeEnum componentTypeEnum, String internalComponentType, Set<String> filteredResources) {
297
298         log.debug("In getComponentsForLeftPanel componentTypeEnum = {}, internalComponentType = {}",
299                 componentTypeEnum, internalComponentType);
300
301         Function<List<Component>, List<Component>> filterFieldsFunc = this::filterForLeftPanel;
302
303         return getComponents(filteredResources, filterFieldsFunc);
304
305     }
306
307     private List<Component> filterForLeftPanel(List<Component> components) {
308
309         List<Component> result = new ArrayList<>();
310         if (components != null) {
311             components.forEach(p -> result.add(filterFieldsForLeftPanel(p)));
312         }
313
314         return result;
315     }
316
317     private List<Component> filterForCatalog(List<Component> components) {
318
319         List<Component> result = new ArrayList<>();
320         if (components != null) {
321             components.forEach(p -> result.add(filterFieldsForCatalog(p)));
322         }
323
324         return result;
325     }
326
327     private Component filterFieldsForLeftPanel(Component component) {
328
329         Component result = null;
330         ComponentTypeEnum componentTypeEnum = component.getComponentType();
331         switch (componentTypeEnum) {
332         case RESOURCE:
333             result = new Resource();
334             copyFieldsForLeftPanel(component, result);
335             break;
336         case SERVICE:
337             result = new Service();
338             copyFieldsForLeftPanel(component, result);
339             break;
340         default:
341             break;
342         }
343
344         return result;
345     }
346
347     private Component filterFieldsForCatalog(Component component) {
348
349         Component result = null;
350         ComponentTypeEnum componentTypeEnum = component.getComponentType();
351         switch (componentTypeEnum) {
352         case RESOURCE:
353             result = new Resource();
354             copyFieldsForCatalog(component, result);
355             break;
356         case SERVICE:
357             result = new Service();
358             copyFieldsForCatalog(component, result);
359             break;
360         case PRODUCT:
361             result = new Product();
362             copyFieldsForCatalog(component, result);
363             break;
364         default:
365             break;
366         }
367
368         return result;
369     }
370
371     /**
372      * Copy relevant fields to the filtered component for left panel
373      *
374      * @param component
375      * @param filteredComponent
376      */
377     private void copyFieldsForLeftPanel(Component component, Component filteredComponent) {
378
379         ComponentTypeEnum componentTypeEnum = component.getComponentType();
380         filteredComponent.setCategories(component.getCategories());
381         filteredComponent.setComponentType(component.getComponentType());
382         if (ComponentTypeEnum.RESOURCE.equals(component.getComponentType())
383                 && ResourceTypeEnum.VL.equals(((ResourceMetadataDataDefinition) component
384                         .getComponentMetadataDefinition().getMetadataDataDefinition()).getResourceType())) {
385             filteredComponent.setCapabilities(component.getCapabilities());
386             filteredComponent.setRequirements(component.getRequirements());
387         }
388         filteredComponent.setVersion(component.getVersion());
389         filteredComponent.setDescription(component.getDescription());
390         filteredComponent.setUniqueId(component.getUniqueId());
391         filteredComponent.setIcon(component.getIcon());
392         filteredComponent.setTags(component.getTags());
393         filteredComponent.setLifecycleState(component.getLifecycleState());
394         filteredComponent.setInvariantUUID(component.getInvariantUUID());
395         filteredComponent.setUUID(component.getUUID());
396         filteredComponent.setSystemName(component.getSystemName());
397         filteredComponent.setName(component.getName());
398
399         if (componentTypeEnum == ComponentTypeEnum.RESOURCE) {
400             Resource resource = (Resource) component;
401             Resource filteredResource = (Resource) filteredComponent;
402             filteredResource.setToscaResourceName(resource.getToscaResourceName());
403             filteredResource.setResourceType(resource.getResourceType());
404         }
405     }
406
407     private void copyFieldsForCatalog(Component component, Component filteredComponent) {
408
409         ComponentTypeEnum componentTypeEnum = component.getComponentType();
410         filteredComponent.setCategories(component.getCategories());
411         filteredComponent.setComponentType(component.getComponentType());
412         filteredComponent.setVersion(component.getVersion());
413         filteredComponent.setDescription(component.getDescription());
414         filteredComponent.setUniqueId(component.getUniqueId());
415         filteredComponent.setIcon(component.getIcon());
416         filteredComponent.setTags(component.getTags());
417         filteredComponent.setLifecycleState(component.getLifecycleState());
418         filteredComponent.setSystemName(component.getSystemName());
419         filteredComponent.setName(component.getName());
420         filteredComponent.setLastUpdateDate(component.getLastUpdateDate());
421
422         if (componentTypeEnum == ComponentTypeEnum.RESOURCE) {
423             Resource resource = (Resource) component;
424             Resource filteredResource = (Resource) filteredComponent;
425             filteredResource.setToscaResourceName(resource.getToscaResourceName());
426             filteredResource.setResourceType(resource.getResourceType());
427         } else if (componentTypeEnum == ComponentTypeEnum.SERVICE) {
428             Service service = (Service) component;
429             Service filteredService = (Service) filteredComponent;
430             filteredService.setDistributionStatus(service.getDistributionStatus());
431         }
432     }
433
434     /**
435      * get components from cache of a given list ou unique ids.
436      *
437      * for each component data from cassandra, unzip the data if needed and
438      * deserialize the unzipped data to java object(Component).
439      *
440      * @param filteredResources
441      * @return ImmutableTripple or ActionStatus. | |-- components |-- dirty
442      *         components - components with dirty flag = true. |-- set of non
443      *         cached components
444      *
445      */
446     private Either<ImmutableTriple<List<Component>, List<Component>, Set<String>>, ActionStatus> getComponentsFull(
447             Set<String> filteredResources) {
448
449         if (!isEnabled()) {
450             log.debug(COMPONENT_CACHE_IS_DISABLED);
451             return Either.right(ActionStatus.NOT_ALLOWED);
452         }
453
454         List<Component> foundResources = new LinkedList<>();
455         List<Component> foundDirtyResources = new LinkedList<>();
456         Set<String> notFoundResources = new HashSet<>();
457         ImmutableTriple<List<Component>, List<Component>, Set<String>> result = new ImmutableTriple<>(
458                 foundResources, foundDirtyResources, notFoundResources);
459
460         long cassandraFetchStart = System.currentTimeMillis();
461         List<String> uidsList = new ArrayList<>();
462         uidsList.addAll(filteredResources);
463         Either<List<ComponentCacheData>, ActionStatus> componentsFromCache = componentCassandraDao
464                 .getComponents(uidsList);
465
466         long cassandraFetchEnd = System.currentTimeMillis();
467         log.debug("Fetch time from cassandara of all components took {} ms",
468                 (cassandraFetchEnd - cassandraFetchStart));
469         if (componentsFromCache.isRight()) {
470             BeEcompErrorManager.getInstance().logInternalFlowError("FetchFromCache",
471                     "Failed to fetch components from cache", ErrorSeverity.ERROR);
472             return Either.right(componentsFromCache.right().value());
473         }
474
475         List<ComponentCacheData> list = componentsFromCache.left().value();
476         log.debug("Number of components fetched from cassandra is {}", (list == null ? 0 : list.size()));
477         if (list != null && !list.isEmpty()) {
478
479             List<ComponentCacheData> filteredData = list.stream().filter(p -> filteredResources.contains(p.getId()))
480                     .collect(Collectors.toList());
481             log.debug("Number of components filterd is {}", filteredData == null ? 0 : filteredData.size());
482
483             if (filteredData != null) {
484                 long desStart = System.currentTimeMillis();
485
486                 for (ComponentCacheData componentCacheData : filteredData) {
487
488                     log.debug("Process uid {} from cache", componentCacheData.getId());
489
490                     String compUid = componentCacheData.getId();
491
492                     Either<? extends Component, Boolean> deserializeExt = convertComponentCacheToComponent(
493                             componentCacheData);
494
495                     if (deserializeExt.isLeft()) {
496                         Component component = deserializeExt.left().value();
497                         if (!componentCacheData.getIsDirty()) {
498                             foundResources.add(component);
499                         } else {
500                             foundDirtyResources.add(component);
501                         }
502                     } else {
503                         notFoundResources.add(compUid);
504                     }
505
506                 }
507                 long desEnd = System.currentTimeMillis();
508                 log.debug("Deserialization and unzip of {} components took {} ms", filteredData.size(),
509                         (desEnd - desStart));
510             }
511         }
512         List<String> foundResourcesUid = foundResources.stream().map(Component::getUniqueId).collect(Collectors.toList());
513         List<String> foundDirtyResourcesUid = foundDirtyResources.stream().map(Component::getUniqueId)
514                 .collect(Collectors.toList());
515         log.debug("Number of processed components from cache is {}",
516                 (foundResourcesUid.size() + foundDirtyResourcesUid.size()));
517         Set<String> notCachedResources = filteredResources.stream()
518                 .filter(p -> !foundResourcesUid.contains(p) && !foundDirtyResourcesUid.contains(p))
519                 .collect(Collectors.toSet());
520         notFoundResources.addAll(notCachedResources);
521
522         if (log.isDebugEnabled()) {
523             log.debug("Number of components fetched is {}", foundResources.size());
524             log.debug("Number of components fetched dirty is {}", foundDirtyResources.size());
525             log.debug("Number of components non cached is {}", notCachedResources.size());
526         }
527
528         return Either.left(result);
529     }
530
531     private Either<? extends Component, Boolean> convertComponentCacheToComponent(
532             ComponentCacheData componentCacheData) {
533
534         String compUid = componentCacheData.getId();
535
536         byte[] dataAsArray = componentCacheData.getDataAsArray();
537
538         if (componentCacheData.getIsZipped()) {
539             long startUnzip = System.nanoTime();
540             dataAsArray = ZipUtil.unzip(dataAsArray);
541             long endUnzip = System.nanoTime();
542             log.trace("Unzip component {} took {} microsecond", compUid, (endUnzip - startUnzip) / 1000);
543         }
544
545         long startDes = System.nanoTime();
546
547         Either<? extends Component, Boolean> deserializeExt = deserializeComponent(componentCacheData, dataAsArray);
548
549         long endDes = System.nanoTime();
550         log.trace("Deserialize component {} took {} microsecond", compUid, (endDes - startDes) / 1000);
551         return deserializeExt;
552     }
553
554     private Either<? extends Component, Boolean> deserializeComponent(ComponentCacheData componentCacheData,
555             byte[] dataAsArray) {
556         String type = componentCacheData.getType();
557         NodeTypeEnum typeEnum = NodeTypeEnum.getByNameIgnoreCase(type);
558
559         Either<? extends Component, Boolean> deserializeExt = Either.right(false);
560         switch (typeEnum) {
561         case Resource:
562             deserializeExt = SerializationUtils.deserializeExt(dataAsArray, Resource.class, componentCacheData.getId());
563             break;
564         case Service:
565             deserializeExt = SerializationUtils.deserializeExt(dataAsArray, Service.class, componentCacheData.getId());
566             break;
567         case Product:
568             deserializeExt = SerializationUtils.deserializeExt(dataAsArray, Product.class, componentCacheData.getId());
569             break;
570         default:
571             break;
572         }
573         return deserializeExt;
574     }
575
576     public Either<Component, ActionStatus> getComponent(String componentUid) {
577
578         return getComponent(componentUid, null, Function.identity());
579
580     }
581
582     private boolean saveComponent(String componentUid, Long lastModificationTime, NodeTypeEnum nodeTypeEnum,
583             Component component) {
584
585         log.trace("Going to save component {} of type {} in cache", componentUid, nodeTypeEnum.name().toLowerCase());
586
587         boolean result = false;
588
589         Either<byte[], Boolean> serializeExt = SerializationUtils.serializeExt(component);
590         if (serializeExt.isLeft()) {
591             byte[] serializedData = serializeExt.left().value();
592             byte[] zipBytes;
593             try {
594                 zipBytes = ZipUtil.zipBytes(serializedData);
595                 ComponentCacheData componentCacheData = new ComponentCacheData();
596                 componentCacheData.setDataAsArray(zipBytes);
597                 componentCacheData.setIsZipped(true);
598                 componentCacheData.setId(componentUid);
599                 componentCacheData.setModificationTime(new Date(lastModificationTime));
600                 componentCacheData.setType(component.getComponentType().name().toLowerCase());
601
602                 CassandraOperationStatus status = componentCassandraDao.saveComponent(componentCacheData);
603
604                 if (status == CassandraOperationStatus.OK) {
605                     result = true;
606                 }
607
608             } catch (IOException e) {
609                 log.debug("Failed to prepare component {} of type {} for cache", componentUid,
610                         nodeTypeEnum.name().toLowerCase());
611                 if (log.isTraceEnabled()) {
612                     log.trace("Failed to prepare component {} of type {} for cache",componentUid,nodeTypeEnum.name().toLowerCase());
613                 }
614             }
615         } else {
616             log.debug("Failed to serialize component {} of type {} for cache", componentUid,
617                     nodeTypeEnum.name().toLowerCase());
618         }
619         return result;
620     }
621
622     public boolean setComponent(Component component, NodeTypeEnum nodeTypeEnum) {
623
624         boolean result = false;
625
626         if (!isEnabled()) {
627             log.debug(COMPONENT_CACHE_IS_DISABLED);
628             return false;
629         }
630
631         String componentUid = component.getUniqueId();
632         Long lastUpdateDate = component.getLastUpdateDate();
633
634         result = saveComponent(componentUid, lastUpdateDate, nodeTypeEnum, component);
635
636         return result;
637
638     }
639
640     /**
641      * get components from cache of a given list ou unique ids.
642      *
643      * for each component data from cassandra, unzip the data if needed and
644      * deserialize the unzipped data to java object(Component).
645      *
646      * @param filteredResources
647      * @return ImmutableTripple or ActionStatus. | |-- components |-- set of non
648      *         cached components
649      *
650      */
651     private Either<ImmutablePair<List<Component>, Set<String>>, ActionStatus> getComponentsFull(
652             Map<String, Long> filteredResources) {
653
654         if (!isEnabled()) {
655             log.debug(COMPONENT_CACHE_IS_DISABLED);
656             return Either.right(ActionStatus.NOT_ALLOWED);
657         }
658
659         List<Component> foundResources = new LinkedList<>();
660         Set<String> notFoundResources = new HashSet<>();
661         ImmutablePair<List<Component>, Set<String>> result = new ImmutablePair<>(
662                 foundResources, notFoundResources);
663
664         long cassandraFetchStart = System.currentTimeMillis();
665
666         Either<ImmutablePair<List<ComponentCacheData>, Set<String>>, ActionStatus> componentsFromCache = componentCassandraDao
667                 .getComponents(filteredResources);
668
669         long cassandraFetchEnd = System.currentTimeMillis();
670         log.debug("Fetch time from cassandara of all components took {} ms",
671                 (cassandraFetchEnd - cassandraFetchStart));
672         if (componentsFromCache.isRight()) {
673             BeEcompErrorManager.getInstance().logInternalFlowError("FetchFromCache",
674                     "Failed to fetch components from cache", ErrorSeverity.ERROR);
675             return Either.right(componentsFromCache.right().value());
676         }
677
678         ImmutablePair<List<ComponentCacheData>, Set<String>> immutablePair = componentsFromCache.left().value();
679         List<ComponentCacheData> list = immutablePair.getLeft();
680         log.debug("Number of components fetched from cassandra is {}", (list == null ? 0 : list.size()));
681         if (list != null && !list.isEmpty()) {
682
683             log.debug("Number of components filterd is {}", list == null ? 0 : list.size());
684
685             if (list != null) {
686                 long desStart = System.currentTimeMillis();
687
688                 for (ComponentCacheData componentCacheData : list) {
689
690                     log.debug("Process uid {} from cache", componentCacheData.getId());
691
692                     String compUid = componentCacheData.getId();
693
694                     Either<? extends Component, Boolean> deserializeExt = convertComponentCacheToComponent(
695                             componentCacheData);
696
697                     if (deserializeExt.isLeft()) {
698                         Component component = deserializeExt.left().value();
699                         foundResources.add(component);
700                     } else {
701                         notFoundResources.add(compUid);
702                     }
703
704                 }
705                 long desEnd = System.currentTimeMillis();
706                 log.debug("Deserialization and unzip of {} components took {} ms", list.size(), (desEnd - desStart));
707             }
708         }
709         log.debug("Number of processed components from cache is {}", foundResources.size());
710
711         Set<String> notFoundInCache = immutablePair.getRight();
712         notFoundResources.addAll(notFoundInCache);
713
714         if (log.isDebugEnabled()) {
715             log.debug("Number of components fetched is {}", foundResources.size());
716             log.debug("Number of components non cached is {}", notFoundResources.size());
717         }
718
719         return Either.left(result);
720     }
721
722     /**
723      * get components for catalog
724      *
725      * @param components
726      * @param componentTypeEnum
727      * @return
728      */
729     public Either<ImmutablePair<List<Component>, Set<String>>, ActionStatus> getComponentsForCatalog(
730             Map<String, Long> components, ComponentTypeEnum componentTypeEnum) {
731
732         if (!isEnabled()) {
733             log.debug("In getComponentsForCatalog for type {}. Cache is disabled.",
734                     componentTypeEnum.name().toLowerCase());
735             return Either.right(ActionStatus.NOT_ALLOWED);
736         }
737         log.debug("In getComponentsForCatalog for type {}", componentTypeEnum.name().toLowerCase());
738
739         Function<List<Component>, List<Component>> filterFieldsFunc = this::filterForCatalog;
740
741         Map<String, Long> leftComponentsForSearch = new HashMap<>();
742         leftComponentsForSearch.putAll(components);
743
744         // get components from inmemory cache
745         List<Component> componentsFromMemory = null;
746         if (catalogInMemoryEnabled) {
747             componentsFromMemory = getDataFromInMemoryCache(components.keySet(), componentTypeEnum);
748             log.debug("The number of components of type {} fetched from memory is {}",
749                     componentTypeEnum.name().toLowerCase(),
750                     componentsFromMemory == null ? 0 : componentsFromMemory.size());
751             if (componentsFromMemory != null) {
752                 List<String> ignoredComponents = new ArrayList<>();
753                 for (Component componentFromMem : componentsFromMemory) {
754                     if (componentFromMem.getLastUpdateDate().longValue() != components
755                             .get(componentFromMem.getUniqueId()).longValue()) {
756                         // Ignore the component from memory
757                         ignoredComponents.add(componentFromMem.getUniqueId());
758                     }
759                 }
760
761                 log.debug("Number of components from type {} ignored from memory cache is {}",
762                         componentTypeEnum.name().toLowerCase(), ignoredComponents.size());
763                 // remove from memory result the components which are not valid
764                 componentsFromMemory = componentsFromMemory.stream()
765                                                            .filter(p -> !ignoredComponents.contains(p.getUniqueId())).collect(Collectors.toList());
766                 // Remove from leftComponentsForSearch the valid components from
767                 // memory
768                 componentsFromMemory.forEach(p -> leftComponentsForSearch.remove(p.getUniqueId()));
769
770             }
771         } else {
772             log.debug("Catalog InMemory cache is disabled");
773         }
774
775         log.debug("Number of components from type {} needed to fetch is {}", componentTypeEnum.name().toLowerCase(),
776                 leftComponentsForSearch.size());
777
778         // get components from cassandra cache and filter each component
779         Either<ImmutablePair<List<Component>, Set<String>>, ActionStatus> result = getComponents(
780                 leftComponentsForSearch, filterFieldsFunc);
781
782         if (result.isLeft()) {
783             // add inmemory components to the valid components(not dirty)
784             List<Component> foundComponents = result.left().value().getLeft();
785             if (componentsFromMemory != null) {
786                 foundComponents.addAll(componentsFromMemory);
787             }
788             if (catalogInMemoryEnabled) {
789                 updateCatalogInMemoryCacheWithCertified(foundComponents, componentTypeEnum);
790             }
791         }
792
793         return result;
794     }
795
796     /**
797      * @param components
798      *            - Map of <componentUniqueId, last update date>
799      * @param filterFieldsFunc
800      * @return
801      */
802     public Either<ImmutablePair<List<Component>, Set<String>>, ActionStatus> getComponents(Map<String, Long> components,
803             Function<List<Component>, List<Component>> filterFieldsFunc) {
804
805         if (!isEnabled()) {
806             log.debug(COMPONENT_CACHE_IS_DISABLED);
807             return Either.right(ActionStatus.NOT_ALLOWED);
808         }
809
810         Either<ImmutablePair<List<Component>, Set<String>>, ActionStatus> componentsFull = getComponentsFull(
811                 components);
812
813         if (componentsFull.isRight()) {
814             return Either.right(componentsFull.right().value());
815         }
816
817         ImmutablePair<List<Component>, Set<String>> immutablePair = componentsFull.left().value();
818         List<Component> foundResources = immutablePair.left;
819         Set<String> notFoundResources = immutablePair.right;
820
821         List<Component> filterdFoundResources = filterFieldsFunc.apply(foundResources);
822
823         ImmutablePair<List<Component>, Set<String>> result = new ImmutablePair<>(
824                 filterdFoundResources, notFoundResources);
825
826         return Either.left(result);
827
828     }
829
830     /**
831      * get the component and its modification time from cache
832      *
833      * @param componentUid
834      * @param filterFieldsFunc
835      * @return
836      */
837     public Either<ImmutablePair<Component, Long>, ActionStatus> getComponentAndTime(String componentUid,
838             Function<Component, Component> filterFieldsFunc) {
839
840         Either<ImmutablePair<Component, ComponentCacheData>, ActionStatus> componentFromCache = getComponentFromCache(
841                 componentUid, null, filterFieldsFunc);
842
843         if (componentFromCache.isRight()) {
844             return Either.right(componentFromCache.right().value());
845         }
846
847         ImmutablePair<Component, ComponentCacheData> immutablePair = componentFromCache.left().value();
848
849         ImmutablePair<Component, Long> result = new ImmutablePair<>(immutablePair.left,
850                 immutablePair.right.getModificationTime().getTime());
851
852         return Either.left(result);
853     }
854
855     private Either<ImmutablePair<Component, ComponentCacheData>, ActionStatus> getComponentFromCache(
856             String componentUid, Long lastModificationTime, Function<Component, Component> filterFieldsFunc) {
857         if (!isEnabled()) {
858             return Either.right(ActionStatus.NOT_ALLOWED);
859         }
860
861         Either<ComponentCacheData, ActionStatus> componentRes = componentCassandraDao.getComponent(componentUid);
862
863         if (componentRes.isRight()) {
864             return Either.right(componentRes.right().value());
865         }
866
867         ComponentCacheData componentCacheData = componentRes.left().value();
868
869         if (lastModificationTime != null) {
870             long cacheCompModificationTime = componentCacheData.getModificationTime().getTime();
871             if (lastModificationTime != cacheCompModificationTime) {
872                 log.debug(
873                         "Component {} found in cache but its modification time {} does not match to the timestamp in cache {}.",
874                         componentUid, lastModificationTime, cacheCompModificationTime);
875                 return Either.right(ActionStatus.INVALID_CONTENT);
876             }
877         }
878
879         Either<? extends Component, Boolean> convertRes = convertComponentCacheToComponent(componentCacheData);
880         if (convertRes.isRight()) {
881             return Either.right(ActionStatus.CONVERT_COMPONENT_ERROR);
882         }
883
884         Component component = convertRes.left().value();
885
886         Component filteredComponent = component;
887         if (filterFieldsFunc != null) {
888             filteredComponent = filterFieldsFunc.apply(component);
889         }
890
891         ImmutablePair<Component, ComponentCacheData> result = new ImmutablePair<>(
892                 filteredComponent, componentCacheData);
893
894         return Either.left(result);
895     }
896
897     public ActionStatus deleteComponentFromCache(String id) {
898         if (!isEnabled()) {
899             return ActionStatus.NOT_ALLOWED;
900         }
901         CassandraOperationStatus status = this.componentCassandraDao.deleteComponent(id);
902         if (CassandraOperationStatus.OK.equals(status)) {
903             return ActionStatus.OK;
904         } else {
905             log.debug("delete component failed with error {}", status);
906             return ActionStatus.GENERAL_ERROR;
907         }
908     }
909
910 }