Clarify ActionSpec documentation
[mdsal.git] / binding / mdsal-binding-api / src / main / java / org / opendaylight / mdsal / binding / api / ActionSpec.java
1 /*
2  * Copyright (c) 2021 PANTHEON.tech, s.r.o. 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.mdsal.binding.api;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.annotations.Beta;
13 import com.google.common.base.MoreObjects;
14 import java.util.Objects;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.opendaylight.yangtools.concepts.Immutable;
17 import org.opendaylight.yangtools.concepts.Mutable;
18 import org.opendaylight.yangtools.yang.binding.Action;
19 import org.opendaylight.yangtools.yang.binding.Augmentation;
20 import org.opendaylight.yangtools.yang.binding.ChildOf;
21 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
22 import org.opendaylight.yangtools.yang.binding.DataObject;
23 import org.opendaylight.yangtools.yang.binding.DataRoot;
24 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
25 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
26
27 /**
28  * A combination of an {@link Action} class and its corresponding instantiation wildcard, expressed as
29  * an {@link InstanceIdentifier}. This means that {@code list}s are treated exactly as @{code container}s are, e.g.
30  * without a key value specification.
31  *
32  * <p>
33  * This glue is required because action interfaces are generated at the place of their
34  * definition, most importantly in {@code grouping} and we actually need to bind to a particular instantiation (e.g. a
35  * place where {@code uses} references that grouping).
36  *
37  * @param <A> Generated Action interface type
38  * @param <P> Action parent type
39  */
40 @Beta
41 public final class ActionSpec<A extends Action<InstanceIdentifier<P>, ?, ?>, P extends DataObject>
42         implements Immutable {
43     private final @NonNull InstanceIdentifier<P> path;
44     private final @NonNull Class<A> type;
45
46     private ActionSpec(final Class<A> type, final InstanceIdentifier<P> path) {
47         this.type = requireNonNull(type);
48         this.path = requireNonNull(path);
49     }
50
51     public static <P extends ChildOf<? extends DataRoot>> @NonNull Builder<P> builder(final Class<P> container) {
52         return new Builder<>(InstanceIdentifier.builder(container));
53     }
54
55     public static <C extends ChoiceIn<? extends DataRoot> & DataObject, P extends ChildOf<? super C>>
56             @NonNull Builder<P> builder(final Class<C> caze, final Class<P> container) {
57         return new Builder<>(InstanceIdentifier.builder(caze, container));
58     }
59
60     public @NonNull InstanceIdentifier<P> path() {
61         return path;
62     }
63
64     public @NonNull Class<A> type() {
65         return type;
66     }
67
68     @Override
69     public int hashCode() {
70         return Objects.hash(type, path);
71     }
72
73     @Override
74     public boolean equals(final Object obj) {
75         if (obj == this) {
76             return true;
77         }
78         if (!(obj instanceof ActionSpec)) {
79             return false;
80         }
81         final var other = (ActionSpec<?, ?>) obj;
82         return type.equals(other.type) && path.equals(other.path);
83     }
84
85     @Override
86     public String toString() {
87         return MoreObjects.toStringHelper(this).add("action", type).add("path", path).toString();
88     }
89
90     @Beta
91     public static final class Builder<P extends DataObject> implements Mutable {
92         private final InstanceIdentifierBuilder<P> pathBuilder;
93
94         Builder(final InstanceIdentifierBuilder<P> pathBuilder) {
95             this.pathBuilder = requireNonNull(pathBuilder);
96         }
97
98         public <N extends ChildOf<? super P>> @NonNull Builder<N> withPathChild(final Class<N> container) {
99             pathBuilder.child(container);
100             return castThis();
101         }
102
103         public <C extends ChoiceIn<? super P> & DataObject, N extends ChildOf<? super C>>
104                 @NonNull Builder<N> withPathChild(final Class<C> caze, final Class<N> container) {
105             pathBuilder.child(caze, container);
106             return castThis();
107         }
108
109         public <N extends DataObject & Augmentation<? super P>> @NonNull Builder<N> withPathAugmentation(
110                 final Class<N> container) {
111             pathBuilder.augmentation(container);
112             return castThis();
113         }
114
115         public <A extends Action<InstanceIdentifier<P>, ?, ?>> @NonNull ActionSpec<A, P> build(final Class<A> type) {
116             return new ActionSpec<>(type, pathBuilder.build());
117         }
118
119         @SuppressWarnings("unchecked")
120         private <N extends DataObject> @NonNull Builder<N> castThis() {
121             return (Builder<N>) this;
122         }
123     }
124 }