252a782e1567eea80aad6ed7365df494decb9bd4
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / util / URLSchemaContextResolver.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.yangtools.yang.parser.impl.util;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11
12 import com.google.common.base.Optional;
13 import com.google.common.collect.ImmutableMap;
14 import com.google.common.collect.ImmutableMap.Builder;
15 import com.google.common.io.ByteSource;
16
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.net.URL;
20 import java.util.Collection;
21 import java.util.Map.Entry;
22 import java.util.concurrent.ConcurrentHashMap;
23 import java.util.concurrent.ConcurrentMap;
24
25 import javax.annotation.concurrent.GuardedBy;
26 import javax.annotation.concurrent.ThreadSafe;
27
28 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
29 import org.opendaylight.yangtools.concepts.Identifiable;
30 import org.opendaylight.yangtools.concepts.ObjectRegistration;
31 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
32 import org.opendaylight.yangtools.yang.model.util.repo.AdvancedSchemaSourceProvider;
33 import org.opendaylight.yangtools.yang.model.util.repo.SourceIdentifier;
34 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 /**
39  * @deprecated Use {@link org.opendaylight.yangtools.yang.parser.repo.URLSchemaContextResolver}
40  * instead.
41  */
42 @Deprecated
43 @ThreadSafe
44 public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<InputStream> {
45
46     private static final Logger LOG = LoggerFactory.getLogger(URLSchemaContextResolver.class);
47
48     @GuardedBy("this")
49     private final ConcurrentMap<SourceIdentifier, SourceContext> availableSources = new ConcurrentHashMap<>();
50     @GuardedBy("this")
51     private YangSourceContext currentSourceContext;
52     @GuardedBy("this")
53     private Optional<SchemaContext> currentSchemaContext = Optional.absent();
54
55     /**
56      * Register new yang schema when it appears.
57      */
58     public synchronized ObjectRegistration<URL> registerSource(final URL source) {
59         checkArgument(source != null, "Supplied source must not be null");
60         InputStream yangStream = getInputStream(source);
61         YangModelDependencyInfo modelInfo = YangModelDependencyInfo.fromInputStream(yangStream);
62         SourceIdentifier identifier = SourceIdentifier.create(modelInfo.getName(),
63                 Optional.of(modelInfo.getFormattedRevision()));
64         SourceContext sourceContext = new SourceContext(source, identifier, modelInfo);
65         availableSources.putIfAbsent(identifier, sourceContext);
66         return sourceContext;
67     }
68
69     public synchronized Optional<SchemaContext> getSchemaContext() {
70         return currentSchemaContext;
71     }
72
73     @Override
74     public synchronized Optional<InputStream> getSchemaSource(final SourceIdentifier key) {
75         SourceContext ctx = availableSources.get(key);
76         if (ctx != null) {
77             InputStream stream = getInputStream(ctx.getInstance());
78             return Optional.fromNullable(stream);
79         }
80         return Optional.absent();
81     }
82
83     @Override
84     public Optional<InputStream> getSchemaSource(final String name, final Optional<String> version) {
85         return getSchemaSource(SourceIdentifier.create(name, version));
86     }
87
88     private static InputStream getInputStream(final URL source) {
89         InputStream stream;
90         try {
91             stream = source.openStream();
92         } catch (IOException e) {
93             throw new IllegalArgumentException("Supplied stream: " + source + " is not available", e);
94         }
95         return stream;
96     }
97
98     private final class SourceContext extends AbstractObjectRegistration<URL> //
99             implements Identifiable<SourceIdentifier> {
100
101         final SourceIdentifier identifier;
102         final YangModelDependencyInfo dependencyInfo;
103
104         public SourceContext(final URL instance, final SourceIdentifier identifier, final YangModelDependencyInfo modelInfo) {
105             super(instance);
106             this.identifier = identifier;
107             this.dependencyInfo = modelInfo;
108         }
109
110         @Override
111         public SourceIdentifier getIdentifier() {
112             return identifier;
113         }
114
115         @Override
116         protected void removeRegistration() {
117             removeSource(this);
118         }
119
120         public YangModelDependencyInfo getDependencyInfo() {
121             return dependencyInfo;
122         }
123     }
124
125     private synchronized void removeSource(final SourceContext sourceContext) {
126         boolean removed = availableSources.remove(sourceContext.getIdentifier(), sourceContext);
127         if (removed) {
128             tryToUpdateSchemaContext();
129         }
130     }
131
132     /**
133      * Try to parse all currently available yang files and build new schema context.
134      * @return new schema context iif there is at least 1 yang file registered and new schema context was successfully built.
135      */
136     public synchronized Optional<SchemaContext> tryToUpdateSchemaContext() {
137         if (availableSources.isEmpty()) {
138             return Optional.absent();
139         }
140         ImmutableMap<SourceIdentifier, SourceContext> actualSources = ImmutableMap.copyOf(availableSources);
141         Builder<SourceIdentifier, YangModelDependencyInfo> builder = ImmutableMap.<SourceIdentifier, YangModelDependencyInfo>builder();
142         for (Entry<SourceIdentifier, SourceContext> entry : actualSources.entrySet()) {
143             builder.put(entry.getKey(), entry.getValue().getDependencyInfo());
144         }
145         ImmutableMap<SourceIdentifier, YangModelDependencyInfo> sourcesMap = builder.build();
146         YangSourceContext yangSourceContext = YangSourceContext.createFrom(sourcesMap, this);
147         LOG.debug("Trying to create schema context from {}", sourcesMap.keySet());
148
149         if (yangSourceContext.getMissingDependencies().size() != 0) {
150             LOG.debug("Omitting {} because of unresolved dependencies", yangSourceContext.getMissingDependencies().keySet());
151             LOG.debug("Missing model sources for {}", yangSourceContext.getMissingSources());
152         }
153         if (currentSourceContext == null || !yangSourceContext.getValidSources().equals(currentSourceContext.getValidSources())) {
154             try {
155                 Collection<ByteSource> byteSources = yangSourceContext.getValidByteSources();
156                 YangParserImpl parser = YangParserImpl.getInstance();
157                 SchemaContext schemaContext = parser.parseSources(byteSources);
158                 currentSchemaContext = Optional.of(schemaContext);
159                 currentSourceContext = yangSourceContext;
160                 return Optional.of(schemaContext);
161             } catch (Exception e) {
162                 LOG.error("Could not create schema context for {} ", yangSourceContext.getValidSources(), e);
163                 return Optional.absent();
164             }
165         } else {
166             currentSourceContext = yangSourceContext;
167             return Optional.absent();
168         }
169     }
170 }