Add OrderedByAwareEffectiveStatement
[yangtools.git] / model / yang-model-ri / src / main / java / org / opendaylight / yangtools / yang / model / ri / stmt / impl / eff / 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.model.ri.stmt.impl.eff;
9
10 import com.google.common.collect.ImmutableList;
11 import java.lang.invoke.MethodHandles;
12 import java.lang.invoke.MethodHandles.Lookup;
13 import java.lang.invoke.VarHandle;
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.TypeDefinition;
19 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
20 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
21 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
22 import org.opendaylight.yangtools.yang.model.api.stmt.DefaultEffectiveStatement;
23 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement;
24 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement;
25 import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
26 import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
27 import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement;
28 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
29 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement;
30 import org.opendaylight.yangtools.yang.model.api.stmt.UnitsEffectiveStatement;
31 import org.opendaylight.yangtools.yang.model.ri.type.DerivedTypeBuilder;
32 import org.opendaylight.yangtools.yang.model.ri.type.DerivedTypes;
33 import org.opendaylight.yangtools.yang.model.spi.meta.AbstractDeclaredEffectiveStatement.DefaultArgument.WithSubstatements;
34 import org.opendaylight.yangtools.yang.model.spi.meta.EffectiveStatementMixins.SchemaNodeMixin;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 public final class TypedefEffectiveStatementImpl extends WithSubstatements<QName, TypedefStatement>
39         implements TypedefEffectiveStatement, SchemaNodeMixin<TypedefStatement> {
40     private static final Logger LOG = LoggerFactory.getLogger(TypedefEffectiveStatementImpl.class);
41
42     private static final VarHandle TYPE_DEFINITION;
43     private static final VarHandle TYPE_STATEMENT;
44
45     static {
46         final Lookup lookup = MethodHandles.lookup();
47         try {
48             TYPE_DEFINITION = lookup.findVarHandle(TypedefEffectiveStatementImpl.class, "typeDefinition",
49                 TypeDefinition.class);
50             TYPE_STATEMENT = lookup.findVarHandle(TypedefEffectiveStatementImpl.class, "typeStatement",
51                 ProxyTypeEffectiveStatement.class);
52         } catch (NoSuchFieldException | IllegalAccessException e) {
53             throw new ExceptionInInitializerError(e);
54         }
55     }
56
57     private final int flags;
58
59     // Accessed via TYPE_DEFINITION
60     @SuppressWarnings("unused")
61     private volatile TypeDefinition<?> typeDefinition;
62     // Accessed via TYPE_STATEMENT
63     @SuppressWarnings("unused")
64     private volatile ProxyTypeEffectiveStatement typeStatement;
65
66     public TypedefEffectiveStatementImpl(final TypedefStatement declared, final int flags,
67             final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
68         super(declared, substatements);
69         this.flags = flags;
70     }
71
72     @Override
73     public int flags() {
74         return flags;
75     }
76
77     @Override
78     public TypeDefinition<?> getTypeDefinition() {
79         final TypeDefinition<?> existing = (TypeDefinition<?>) TYPE_DEFINITION.getAcquire(this);
80         return existing != null ? existing : loadTypeDefinition();
81     }
82
83     @Override
84     public TypeEffectiveStatement<TypeStatement> asTypeEffectiveStatement() {
85         final ProxyTypeEffectiveStatement local = (ProxyTypeEffectiveStatement) TYPE_STATEMENT.getAcquire(this);
86         return local != null ? local : loadTypeStatement();
87     }
88
89     private @NonNull TypeDefinition<?> loadTypeDefinition() {
90         final TypeEffectiveStatement<?> type = findFirstEffectiveSubstatement(TypeEffectiveStatement.class).get();
91         final DerivedTypeBuilder<?> builder = DerivedTypes.derivedTypeBuilder(type.getTypeDefinition(), argument());
92
93         for (final EffectiveStatement<?, ?> stmt : effectiveSubstatements()) {
94             if (stmt instanceof DefaultEffectiveStatement) {
95                 builder.setDefaultValue(((DefaultEffectiveStatement) stmt).argument());
96             } else if (stmt instanceof DescriptionEffectiveStatement) {
97                 builder.setDescription(((DescriptionEffectiveStatement)stmt).argument());
98             } else if (stmt instanceof ReferenceEffectiveStatement) {
99                 builder.setReference(((ReferenceEffectiveStatement)stmt).argument());
100             } else if (stmt instanceof StatusEffectiveStatement) {
101                 builder.setStatus(((StatusEffectiveStatement)stmt).argument());
102             } else if (stmt instanceof UnitsEffectiveStatement) {
103                 builder.setUnits(((UnitsEffectiveStatement)stmt).argument());
104             } else if (stmt instanceof UnknownSchemaNode) {
105                 // FIXME: should not directly implement, I think
106                 builder.addUnknownSchemaNode((UnknownSchemaNode)stmt);
107             } else if (!(stmt instanceof TypeEffectiveStatement)) {
108                 LOG.debug("Ignoring statement {}", stmt);
109             }
110         }
111
112         final TypeDefinition<?> created = builder.build();
113         final Object witness = TYPE_DEFINITION.compareAndExchangeRelease(this, null, created);
114         return witness == null ? created : (TypeDefinition<?>) witness;
115     }
116
117     private @NonNull ProxyTypeEffectiveStatement loadTypeStatement() {
118         final ProxyTypeEffectiveStatement created = new ProxyTypeEffectiveStatement();
119         final Object witness = TYPE_STATEMENT.compareAndExchangeRelease(this, null, created);
120         return witness == null ? created : (ProxyTypeEffectiveStatement) witness;
121     }
122
123     private final class ProxyTypeEffectiveStatement implements TypeEffectiveStatement<TypeStatement> {
124         @Override
125         public TypeStatement getDeclared() {
126             return null;
127         }
128
129         @Override
130         public <K, V, N extends IdentifierNamespace<K, V>> Optional<V> get(final Class<N> namespace,
131                 final K identifier) {
132             return TypedefEffectiveStatementImpl.this.get(namespace, identifier);
133         }
134
135         @Override
136         public <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAll(final Class<N> namespace) {
137             return TypedefEffectiveStatementImpl.this.getAll(namespace);
138         }
139
140         @Override
141         public ImmutableList<? extends EffectiveStatement<?, ?>> effectiveSubstatements() {
142             return TypedefEffectiveStatementImpl.this.effectiveSubstatements();
143         }
144
145         @Override
146         public QName argument() {
147             return TypedefEffectiveStatementImpl.this.argument();
148         }
149
150         @Override
151         public TypeDefinition<?> getTypeDefinition() {
152             return TypedefEffectiveStatementImpl.this.getTypeDefinition();
153         }
154     }
155 }