77ceab24e06213cb0908451722abb10e766ae8bc
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / EffectiveStatementBase.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;
9
10 import com.google.common.collect.Collections2;
11 import com.google.common.collect.ImmutableList;
12 import java.util.Collection;
13 import java.util.function.Predicate;
14 import org.eclipse.jdt.annotation.NonNull;
15 import org.eclipse.jdt.annotation.Nullable;
16 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
17 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
18 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
19 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
20
21 /**
22  * Stateful version of {@link AbstractEffectiveStatement}, which holds substatements in an {@link ImmutableList}.
23  *
24  * @param <A> Argument type ({@link Void} if statement does not have argument.)
25  * @param <D> Class representing declared version of this statement.
26  */
27 // TODO: This class is problematic in that it interacts with its subclasses via methods which are guaranteed to allows
28 //       atrocities like RecursiveObjectLeaker tricks. That should be avoided and pushed to caller in a way where
29 //       this class is a pure holder taking {@code ImmutableList<? extends EffectiveStatement<?, ?>>} in the
30 //       constructor.
31 //
32 //       From memory efficiency perspective, it is very common to have effective statements without any substatements,
33 //       in which case 'substatements' field is redundant.
34 public abstract class EffectiveStatementBase<A, D extends DeclaredStatement<A>>
35         extends AbstractEffectiveStatement<A, D> {
36     private final @NonNull ImmutableList<? extends EffectiveStatement<?, ?>> substatements;
37
38     /**
39      * Constructor.
40      *
41      * @param ctx context of statement.
42      */
43     protected EffectiveStatementBase(final StmtContext<A, D, ?> ctx) {
44         this.substatements = ImmutableList.copyOf(initSubstatements(BaseStatementSupport.declaredSubstatements(ctx)));
45     }
46
47     /**
48      * Create a set of substatements. This method is split out so it can be overridden in
49      * ExtensionEffectiveStatementImpl to leak a not-fully-initialized instance.
50      *
51      * @param substatementsInit proposed substatements
52      * @return Filtered substatements
53      */
54     protected Collection<? extends EffectiveStatement<?, ?>> initSubstatements(
55             final Collection<? extends StmtContext<?, ?, ?>> substatementsInit) {
56         return Collections2.transform(Collections2.filter(substatementsInit,
57             StmtContext::isSupportedToBuildEffective), StmtContext::buildEffective);
58     }
59
60     @Override
61     public final Collection<? extends EffectiveStatement<?, ?>> effectiveSubstatements() {
62         return substatements;
63     }
64
65     @SuppressWarnings("unchecked")
66     public final <T> Collection<T> allSubstatementsOfType(final Class<T> type) {
67         return Collection.class.cast(Collections2.filter(effectiveSubstatements(), type::isInstance));
68     }
69
70     protected final <T> @Nullable T firstSubstatementOfType(final Class<T> type) {
71         return effectiveSubstatements().stream().filter(type::isInstance).findFirst().map(type::cast).orElse(null);
72     }
73
74     protected final <R> R firstSubstatementOfType(final Class<?> type, final Class<R> returnType) {
75         return effectiveSubstatements().stream()
76                 .filter(((Predicate<Object>)type::isInstance).and(returnType::isInstance))
77                 .findFirst().map(returnType::cast).orElse(null);
78     }
79
80     protected final EffectiveStatement<?, ?> firstEffectiveSubstatementOfType(final Class<?> type) {
81         return effectiveSubstatements().stream().filter(type::isInstance).findFirst().orElse(null);
82     }
83
84     // FIXME: rename to 'getFirstEffectiveStatement()'
85     protected final <S extends SchemaNode> S firstSchemaNode(final Class<S> type) {
86         return findFirstEffectiveSubstatement(type).orElse(null);
87     }
88 }