Hide CodecContextSupplier
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / LazyCodecContextSupplier.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.mdsal.binding.dom.codec.impl;
9
10 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
11 import java.lang.invoke.MethodHandles;
12 import java.lang.invoke.VarHandle;
13 import org.eclipse.jdt.annotation.NonNull;
14
15 /**
16  * Abstract base class for lazily-instantiated {@link CodecContextSupplier} instances.
17  *
18  * @param <C> {@link CodecContext} type
19  */
20 public abstract sealed class LazyCodecContextSupplier<C extends CodecContext> implements CodecContextSupplier
21         permits CommonDataObjectCodecPrototype {
22     private static final VarHandle INSTANCE;
23
24     static {
25         try {
26             INSTANCE = MethodHandles.lookup().findVarHandle(LazyCodecContextSupplier.class, "instance",
27                 CodecContext.class);
28         } catch (NoSuchFieldException | IllegalAccessException e) {
29             throw new ExceptionInInitializerError(e);
30         }
31     }
32
33     // Accessed via INSTANCE
34     @SuppressWarnings("unused")
35     @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "https://github.com/spotbugs/spotbugs/issues/2749")
36     private volatile C instance;
37
38     @Override
39     public final C getCodecContext() {
40         final var existing = (C) INSTANCE.getAcquire(this);
41         return existing != null ? existing : loadInstance();
42     }
43
44     private @NonNull C loadInstance() {
45         final var tmp = createInstance();
46         final var witness = (C) INSTANCE.compareAndExchangeRelease(this, null, tmp);
47         return witness == null ? tmp : witness;
48     }
49
50     // This method must allow concurrent loading, i.e. nothing in it may have effects outside of the loaded object
51     abstract @NonNull C createInstance();
52 }