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