2dd3882c91184a54e479fee1242196d9d4c1a07c
[netconf.git] / netconf / tools / netconf-testtool / src / main / java / org / opendaylight / netconf / test / tool / schemacache / SchemaSourceCache.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netconf.test.tool.schemacache;
9
10 import com.google.common.util.concurrent.Futures;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.util.AbstractMap;
13 import java.util.HashSet;
14 import java.util.Map;
15 import java.util.Set;
16 import java.util.stream.Collectors;
17 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
18 import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
19 import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
20 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
21 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
22 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
23 import org.opendaylight.yangtools.yang.model.repo.spi.AbstractSchemaSourceCache;
24 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource.Costs;
25 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * Cache implementation that stores schemas in form of files under provided folder.
31  */
32 public final class SchemaSourceCache<T extends SchemaSourceRepresentation> extends AbstractSchemaSourceCache<T> {
33
34     private static final Logger LOG = LoggerFactory.getLogger(SchemaSourceCache.class);
35
36     private final Class<T> representation;
37     private Map<SourceIdentifier, YangModuleInfo> cachedSchemas;
38
39     public SchemaSourceCache(final SchemaSourceRegistry consumer,
40                              final Class<T> representation,
41                              final Set<YangModuleInfo> moduleList) {
42         super(consumer, representation, Costs.LOCAL_IO);
43         this.representation = representation;
44         initializeCachedSchemas(moduleList);
45     }
46
47     /**
48      * Restore cache state using input set of modules. Cached schemas are filled with dependencies of input modules too.
49      *
50      * @param moduleList Set of modules information.
51      */
52     private void initializeCachedSchemas(final Set<YangModuleInfo> moduleList) {
53         // searching for all dependencies
54         final Set<YangModuleInfo> allModulesInfo = new HashSet<>(moduleList);
55         allModulesInfo.addAll(moduleList.stream()
56                 .flatMap(yangModuleInfo -> collectYangModuleInfoDependencies(yangModuleInfo, moduleList).stream())
57                 .collect(Collectors.toSet()));
58
59         // creation of source identifiers for all yang module info
60         cachedSchemas = allModulesInfo.stream()
61                 .map(yangModuleInfo -> {
62                     final RevisionSourceIdentifier revisionSourceIdentifier = RevisionSourceIdentifier.create(
63                             yangModuleInfo.getName().getLocalName(),
64                             yangModuleInfo.getName().getRevision());
65                     return new AbstractMap.SimpleEntry<>(revisionSourceIdentifier, yangModuleInfo);
66                 })
67                 .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
68         cachedSchemas.keySet().forEach(this::register);
69     }
70
71     /**
72      * Collection of all direct and indirect dependencies of input YANG module info.
73      *
74      * @param yangModuleInfo       Input YANG module info for which this method collects dependencies.
75      * @param collectedModulesInfo Already collected module information.
76      * @return Already collected module information union found direct and indirect dependencies.
77      */
78     private static Set<YangModuleInfo> collectYangModuleInfoDependencies(
79             final YangModuleInfo yangModuleInfo, final Set<YangModuleInfo> collectedModulesInfo) {
80         // resolution of direct dependencies that haven't already been collected
81         final Set<YangModuleInfo> allDependencies = new HashSet<>(collectedModulesInfo);
82         final Set<YangModuleInfo> directDependencies = yangModuleInfo.getImportedModules().stream()
83                 .filter(importedYangModuleInfo -> !collectedModulesInfo.contains(importedYangModuleInfo))
84                 .collect(Collectors.toSet());
85         allDependencies.addAll(directDependencies);
86
87         // resolution of indirect dependencies through recursion
88         final Set<YangModuleInfo> indirectDependencies = directDependencies.stream()
89                 .flatMap(importedYangModuleInfo ->
90                         collectYangModuleInfoDependencies(importedYangModuleInfo, allDependencies).stream())
91                 .collect(Collectors.toSet());
92         allDependencies.addAll(indirectDependencies);
93         return allDependencies;
94     }
95
96     @Override
97     public synchronized ListenableFuture<? extends T> getSource(final SourceIdentifier sourceIdentifier) {
98         final YangModuleInfo yangModuleInfo = cachedSchemas.get(sourceIdentifier);
99         if (yangModuleInfo != null) {
100             final YangTextSchemaSource yangTextSchemaSource = YangTextSchemaSource.delegateForByteSource(
101                     sourceIdentifier, yangModuleInfo.getYangTextByteSource());
102             return Futures.immediateFuture(representation.cast(yangTextSchemaSource));
103         }
104
105         LOG.debug("Source {} not found in cache", sourceIdentifier);
106         return Futures.immediateFailedFuture(new MissingSchemaSourceException("Source not found", sourceIdentifier));
107     }
108
109     @Override
110     protected synchronized void offer(final T source) {
111         LOG.trace("Source {} offered to cache", source.getIdentifier());
112     }
113 }