7ec2b446db2ecdd732c22017f72b5c879d35e88e
[yangtools.git] / binding / binding-spec / src / main / java / org / opendaylight / yangtools / binding / impl / AbstractDataObjectReference.java
1 /*
2  * Copyright (c) 2024 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.yangtools.binding.impl;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.base.MoreObjects;
13 import com.google.common.collect.Iterables;
14 import java.io.IOException;
15 import java.io.NotSerializableException;
16 import java.io.ObjectInputStream;
17 import java.io.ObjectOutputStream;
18 import java.io.ObjectStreamException;
19 import java.util.List;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.opendaylight.yangtools.binding.DataObject;
23 import org.opendaylight.yangtools.binding.DataObjectReference;
24 import org.opendaylight.yangtools.binding.DataObjectStep;
25 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
26
27 /**
28  * Base implementation of {@link DataObjectReference}.
29  */
30 public abstract sealed class AbstractDataObjectReference<T extends DataObject, S extends DataObjectStep<?>>
31         implements DataObjectReference<T>
32         permits DataObjectIdentifierImpl, DataObjectReferenceImpl, InstanceIdentifier {
33     @java.io.Serial
34     private static final long serialVersionUID = 1L;
35
36     private final @NonNull Iterable<? extends @NonNull S> steps;
37
38     protected AbstractDataObjectReference(final Iterable<? extends @NonNull S> steps) {
39         this.steps = requireNonNull(steps);
40     }
41
42     @Override
43     public final Iterable<? extends @NonNull S> steps() {
44         return steps;
45     }
46
47     @Override
48     public DataObjectStep<T> lastStep() {
49         return getLast(steps);
50     }
51
52     @Override
53     public final int hashCode() {
54         int hash = 1;
55         for (var step : steps) {
56             hash = 31 * hash + step.hashCode();
57         }
58         return hash;
59     }
60
61     @Override
62     public final boolean equals(final Object obj) {
63         return this == obj || obj instanceof AbstractDataObjectReference other
64             && Iterables.elementsEqual(steps, other.steps);
65     }
66
67     @Override
68     public final String toString() {
69         // FIXME: YANGTOOLS-1577: pretty-print steps instead
70         return MoreObjects.toStringHelper(contract()).add("steps", Iterables.toString(steps())).toString();
71     }
72
73     protected @NonNull Class<?> contract() {
74         return DataObjectReference.class;
75     }
76
77     @SuppressWarnings("unchecked")
78     protected static final <T> @NonNull T getLast(final Iterable<?> steps) {
79         return (@NonNull T) switch (steps) {
80             case AppendIterable<?> append -> append.last();
81             case List<?> list -> list.getLast();
82             default -> Iterables.getLast(steps);
83         };
84     }
85
86     protected final void throwNSE() throws NotSerializableException {
87         throw new NotSerializableException(getClass().getName());
88     }
89
90     @java.io.Serial
91     protected final Object writeReplace() throws ObjectStreamException {
92         return toSerialForm();
93     }
94
95     protected @NonNull Object toSerialForm() {
96         return new ORv1(this);
97     }
98
99     @NonNullByDefault
100     public static final <T> Iterable<? extends T> concat(final Iterable<? extends T> others, final T last) {
101         return new AppendIterable<>(others, last);
102     }
103
104     @java.io.Serial
105     private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException {
106         throwNSE();
107     }
108
109     @java.io.Serial
110     private void readObjectNoData() throws ObjectStreamException {
111         throwNSE();
112     }
113
114     @java.io.Serial
115     private void writeObject(final ObjectOutputStream stream) throws IOException {
116         throwNSE();
117     }
118 }