Refactor typedef implementations
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / typedef / TypedefEffectiveStatementImpl.java
1 /*
2  * Copyright (c) 2015 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.rfc7950.stmt.typedef;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.collect.ImmutableList;
13 import java.util.Collection;
14 import java.util.Map;
15 import java.util.Optional;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
19 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
20 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
22 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
23 import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
24 import org.opendaylight.yangtools.yang.model.api.stmt.DefaultEffectiveStatement;
25 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement;
26 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement;
27 import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
28 import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
29 import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement;
30 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
31 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement;
32 import org.opendaylight.yangtools.yang.model.api.stmt.UnitsEffectiveStatement;
33 import org.opendaylight.yangtools.yang.model.util.type.DerivedTypeBuilder;
34 import org.opendaylight.yangtools.yang.model.util.type.DerivedTypes;
35 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractDeclaredEffectiveStatement.Default;
36 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.SchemaNodeMixin;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 final class TypedefEffectiveStatementImpl extends Default<QName, TypedefStatement>
41         implements TypedefEffectiveStatement, SchemaNodeMixin<QName, TypedefStatement> {
42     private static final Logger LOG = LoggerFactory.getLogger(TypedefEffectiveStatementImpl.class);
43
44     private final @NonNull Object substatements;
45     private final @NonNull SchemaPath path;
46     private final int flags;
47
48     private volatile TypeDefinition<?> typeDefinition;
49     private volatile TypeEffectiveStatement<TypeStatement> typeStatement;
50
51     TypedefEffectiveStatementImpl(final TypedefStatement declared, final SchemaPath path, final int flags,
52             final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
53         super(declared);
54         this.path = requireNonNull(path);
55         this.flags = flags;
56         this.substatements = maskList(substatements);
57     }
58
59     @Override
60     public int flags() {
61         return flags;
62     }
63
64     @Override
65     public SchemaPath getPath() {
66         return path;
67     }
68
69     @Override
70     public @NonNull QName argument() {
71         return getQName();
72     }
73
74     @Override
75     public ImmutableList<? extends EffectiveStatement<?, ?>> effectiveSubstatements() {
76         return unmaskList(substatements);
77     }
78
79     @Override
80     public TypeDefinition<?> getTypeDefinition() {
81         final TypeDefinition<?> existing = typeDefinition;
82         return existing != null ? existing : loadTypeDefinition();
83     }
84
85     @Override
86     public TypeEffectiveStatement<TypeStatement> asTypeEffectiveStatement() {
87         final TypeEffectiveStatement<TypeStatement> local = typeStatement;
88         return local != null ? local : loadTypeStatement();
89     }
90
91     private synchronized @NonNull TypeDefinition<?> loadTypeDefinition() {
92         final TypeDefinition<?> existing = typeDefinition;
93         if (existing != null) {
94             return existing;
95         }
96
97         final TypeEffectiveStatement<?> type = findFirstEffectiveSubstatement(TypeEffectiveStatement.class).get();
98         final DerivedTypeBuilder<?> builder = DerivedTypes.derivedTypeBuilder(type.getTypeDefinition(), path);
99
100         for (final EffectiveStatement<?, ?> stmt : effectiveSubstatements()) {
101             if (stmt instanceof DefaultEffectiveStatement) {
102                 builder.setDefaultValue(((DefaultEffectiveStatement) stmt).argument());
103             } else if (stmt instanceof DescriptionEffectiveStatement) {
104                 builder.setDescription(((DescriptionEffectiveStatement)stmt).argument());
105             } else if (stmt instanceof ReferenceEffectiveStatement) {
106                 builder.setReference(((ReferenceEffectiveStatement)stmt).argument());
107             } else if (stmt instanceof StatusEffectiveStatement) {
108                 builder.setStatus(((StatusEffectiveStatement)stmt).argument());
109             } else if (stmt instanceof UnitsEffectiveStatement) {
110                 builder.setUnits(((UnitsEffectiveStatement)stmt).argument());
111             } else if (stmt instanceof UnknownSchemaNode) {
112                 // FIXME: should not directly implement, I think
113                 builder.addUnknownSchemaNode((UnknownSchemaNode)stmt);
114             } else if (!(stmt instanceof TypeEffectiveStatement)) {
115                 LOG.debug("Ignoring statement {}", stmt);
116             }
117         }
118
119         final TypeDefinition<?> ret = builder.build();
120         typeDefinition = ret;
121         return ret;
122     }
123
124     private synchronized @NonNull TypeEffectiveStatement<TypeStatement> loadTypeStatement() {
125         TypeEffectiveStatement<TypeStatement> ret = typeStatement;
126         if (ret == null) {
127             typeStatement = ret = new ProxyTypeEffectiveStatement();
128         }
129         return ret;
130     }
131
132     private final class ProxyTypeEffectiveStatement implements TypeEffectiveStatement<TypeStatement> {
133         @Override
134         public TypeStatement getDeclared() {
135             return null;
136         }
137
138         @Override
139         public <K, V, N extends IdentifierNamespace<K, V>> Optional<? extends V> get(final Class<N> namespace,
140                 final K identifier) {
141             return TypedefEffectiveStatementImpl.this.get(namespace, identifier);
142         }
143
144         @Override
145         public <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAll(final Class<N> namespace) {
146             return TypedefEffectiveStatementImpl.this.getAll(namespace);
147         }
148
149         @Override
150         public Collection<? extends EffectiveStatement<?, ?>> effectiveSubstatements() {
151             return TypedefEffectiveStatementImpl.this.effectiveSubstatements();
152         }
153
154         @Override
155         public String argument() {
156             return getQName().getLocalName();
157         }
158
159         @Override
160         public StatementSource getStatementSource() {
161             return StatementSource.CONTEXT;
162         }
163
164         @Override
165         public TypeDefinition<?> getTypeDefinition() {
166             return TypedefEffectiveStatementImpl.this.getTypeDefinition();
167         }
168     }
169 }