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 java.io.IOException;
11 import java.io.InputStream;
13 import java.util.List;
14 import java.util.Map.Entry;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
19 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
20 import org.opendaylight.yangtools.concepts.Identifiable;
21 import org.opendaylight.yangtools.concepts.Registration;
22 import org.opendaylight.yangtools.yang.model.api.Module;
23 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
24 import org.opendaylight.yangtools.yang.model.util.repo.AdvancedSchemaSourceProvider;
25 import org.opendaylight.yangtools.yang.model.util.repo.SourceIdentifier;
26 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
30 import com.google.common.base.Optional;
31 import com.google.common.collect.ImmutableMap;
32 import com.google.common.collect.ImmutableMap.Builder;
34 import static com.google.common.base.Preconditions.checkArgument;
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 Registration<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;
96 public SourceIdentifier getIdentifier() {
101 protected void removeRegistration() {
105 public YangModelDependencyInfo getDependencyInfo() {
106 return dependencyInfo;
110 private void removeSource(SourceContext sourceContext) {
111 boolean removed = availableSources.remove(sourceContext.getIdentifier(), sourceContext);
113 tryToUpdateSchemaContext();
117 public synchronized Optional<SchemaContext> tryToUpdateSchemaContext() {
118 if(availableSources.isEmpty()) {
119 return Optional.absent();
121 ImmutableMap<SourceIdentifier, SourceContext> actualSources = ImmutableMap.copyOf(availableSources);
122 Builder<SourceIdentifier, YangModelDependencyInfo> builder = ImmutableMap.<SourceIdentifier, YangModelDependencyInfo> builder();
123 for(Entry<SourceIdentifier, SourceContext> entry : actualSources.entrySet()) {
124 builder.put(entry.getKey(), entry.getValue().getDependencyInfo());
126 ImmutableMap<SourceIdentifier, YangModelDependencyInfo> sourcesMap = builder.build();
127 YangSourceContext context = YangSourceContext.createFrom(sourcesMap);
128 LOG.debug("Trying to create schema context from {}",sourcesMap.keySet());
130 if (context.getMissingDependencies().size() != 0) {
131 LOG.debug("Omitting {} because of unresolved dependencies", context.getMissingDependencies().keySet());
132 LOG.debug("Missing model sources for {}", context.getMissingSources());
136 if(currentSourceContext == null || !context.getValidSources().equals(currentSourceContext.getValidSources())) {
137 List<InputStream> streams = YangSourceContext.getValidInputStreams(context, this);
138 YangParserImpl parser = new YangParserImpl();
139 Set<Module> modules = parser.parseYangModelsFromStreams(streams);
140 SchemaContext schemaContext = parser.resolveSchemaContext(modules);
141 currentSchemaContext = Optional.of(schemaContext);
142 currentSourceContext = context;
143 return currentSchemaContext;
145 currentSourceContext = context;
146 } catch (Exception e) {
147 LOG.error("Could not create schema context for {} ",context.getValidSources());
149 return Optional.absent();