2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.parser.impl.util;
10 import static com.google.common.base.Preconditions.checkArgument;
12 import java.io.IOException;
13 import java.io.InputStream;
15 import java.util.List;
16 import java.util.Map.Entry;
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.ConcurrentMap;
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;
32 import com.google.common.base.Optional;
33 import com.google.common.collect.ImmutableMap;
34 import com.google.common.collect.ImmutableMap.Builder;
36 public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<InputStream> {
38 private static final Logger LOG = LoggerFactory.getLogger(URLSchemaContextResolver.class);
39 private final ConcurrentMap<SourceIdentifier, SourceContext> availableSources = new ConcurrentHashMap<>();
41 private YangSourceContext currentSourceContext;
42 private Optional<SchemaContext> currentSchemaContext = Optional.absent();
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);
55 public Optional<SchemaContext> getSchemaContext() {
56 return currentSchemaContext;
60 public Optional<InputStream> getSchemaSource(SourceIdentifier key) {
61 SourceContext ctx = availableSources.get(key);
63 InputStream stream = getInputStream(ctx.getInstance());
64 return Optional.fromNullable(stream);
66 return Optional.absent();
70 public Optional<InputStream> getSchemaSource(String name, Optional<String> version) {
71 return getSchemaSource(SourceIdentifier.create(name, version));
74 private InputStream getInputStream(URL source) {
77 stream = source.openStream();
78 } catch (IOException e) {
79 throw new IllegalArgumentException("Supplied stream: " + source + " is not available", e);
84 private final class SourceContext extends AbstractObjectRegistration<URL> //
85 implements Identifiable<SourceIdentifier> {
87 final SourceIdentifier identifier;
88 final YangModelDependencyInfo dependencyInfo;
90 public SourceContext(URL instance, SourceIdentifier identifier, YangModelDependencyInfo modelInfo) {
92 this.identifier = identifier;
93 this.dependencyInfo = modelInfo;
97 public SourceIdentifier getIdentifier() {
102 protected void removeRegistration() {
106 public YangModelDependencyInfo getDependencyInfo() {
107 return dependencyInfo;
111 private void removeSource(SourceContext sourceContext) {
112 boolean removed = availableSources.remove(sourceContext.getIdentifier(), sourceContext);
114 tryToUpdateSchemaContext();
118 public synchronized Optional<SchemaContext> tryToUpdateSchemaContext() {
119 if(availableSources.isEmpty()) {
120 return Optional.absent();
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());
127 ImmutableMap<SourceIdentifier, YangModelDependencyInfo> sourcesMap = builder.build();
128 YangSourceContext context = YangSourceContext.createFrom(sourcesMap);
129 LOG.debug("Trying to create schema context from {}",sourcesMap.keySet());
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());
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;
146 currentSourceContext = context;
147 } catch (Exception e) {
148 LOG.error("Could not create schema context for {} ", context.getValidSources(), e);
150 return Optional.absent();