BUG-997: make sure we carry YANG text around
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / util / TextToASTTransformer.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
3  * This program and the accompanying materials are made available under the
4  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
5  * and is available at http://www.eclipse.org/legal/epl-v10.html
6  */
7 package org.opendaylight.yangtools.yang.parser.util;
8
9 import com.google.common.base.Charsets;
10 import com.google.common.base.Function;
11 import com.google.common.base.Preconditions;
12 import com.google.common.io.CharStreams;
13 import com.google.common.io.InputSupplier;
14 import com.google.common.util.concurrent.CheckedFuture;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListeningExecutorService;
17
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.util.concurrent.Callable;
21
22 import org.antlr.v4.runtime.tree.ParseTreeWalker;
23 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext;
24 import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
25 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
26 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
27 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformationException;
28 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformer;
29 import org.opendaylight.yangtools.yang.parser.impl.YangModelBasicValidationListener;
30 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 /**
35  * A {@link SchemaSourceTransformer} which handles translation of models from
36  * {@link YangTextSchemaSource} representation into {@link ASTSchemaSource}.
37  *
38  * While this class is currently used explicitly, its long-term purpose is to
39  * be registered with a {@link org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry}
40  * and be invoked on demand when the processing pipeline requests the
41  * ASTSchemaSource representation.
42  */
43 public final class TextToASTTransformer implements SchemaSourceTransformer<YangTextSchemaSource, ASTSchemaSource> {
44     private static final Logger LOG = LoggerFactory.getLogger(TextToASTTransformer.class);
45     private static final Function<Exception, SchemaSourceTransformationException> MAPPER = new ExceptionMapper<SchemaSourceTransformationException>("Source transformation", SchemaSourceTransformationException.class) {
46         @Override
47         protected SchemaSourceTransformationException newWithCause(final String message, final Throwable cause) {
48             return new SchemaSourceTransformationException(message, cause);
49         }
50     };
51
52     private final ListeningExecutorService executor;
53
54     private TextToASTTransformer(final ListeningExecutorService executor) {
55         this.executor = Preconditions.checkNotNull(executor);
56     }
57
58     public static final TextToASTTransformer create(final ListeningExecutorService executor) {
59         return new TextToASTTransformer(executor);
60     }
61
62     @Override
63     public Class<YangTextSchemaSource> getInputRepresentation() {
64         return YangTextSchemaSource.class;
65     }
66
67     @Override
68     public Class<ASTSchemaSource> getOutputRepresentation() {
69         return ASTSchemaSource.class;
70     }
71
72     @Override
73     public CheckedFuture<ASTSchemaSource, SchemaSourceTransformationException> transformSchemaSource(final YangTextSchemaSource source) {
74         return Futures.makeChecked(executor.submit(new Callable<ASTSchemaSource>() {
75             @Override
76             public ASTSchemaSource call() throws IOException, YangSyntaxErrorException {
77                 try (InputStream is = source.openStream()) {
78                     final YangContext ctx = YangParserImpl.parseYangSource(is);
79                     LOG.debug("Model {} parsed successfully", source);
80
81                     final ParseTreeWalker walker = new ParseTreeWalker();
82                     final YangModelBasicValidationListener validator = new YangModelBasicValidationListener();
83                     walker.walk(validator, ctx);
84                     LOG.debug("Model {} validated successfully", source);
85
86                     // Backwards compatibility
87                     final String text = CharStreams.toString(
88                             CharStreams.newReaderSupplier(new InputSupplier<InputStream>() {
89                                 @Override
90                                 public InputStream getInput() throws IOException {
91                                     return source.openStream();
92                                 }
93                             }, Charsets.UTF_8));
94
95                     return ASTSchemaSource.create(source.getIdentifier().getName(), ctx, text);
96                 }
97             }
98         }), MAPPER);
99     }
100
101     @Override
102     public int getCost() {
103         // We perform a direct translation, so the cost is 1.
104         return 1;
105     }
106 }