Bump versions to 14.0.0-SNAPSHOT
[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 abstract sealed class LazyCodecContextSupplier<C extends CodecContext> implements CodecContextSupplier
21         // Note: while we could merge this class into DataContainerCodecPrototype, we want to keep the lazy-loading part
22         //       separate in case we need to non-DataContainer contexts.
23         permits DataContainerPrototype {
24     private static final VarHandle INSTANCE;
25
26     static {
27         try {
28             INSTANCE = MethodHandles.lookup().findVarHandle(LazyCodecContextSupplier.class, "instance",
29                 CodecContext.class);
30         } catch (NoSuchFieldException | IllegalAccessException e) {
31             throw new ExceptionInInitializerError(e);
32         }
33     }
34
35     // Accessed via INSTANCE
36     @SuppressWarnings("unused")
37     @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "https://github.com/spotbugs/spotbugs/issues/2749")
38     private volatile C instance;
39
40     @Override
41     public final C getCodecContext() {
42         final var existing = (C) INSTANCE.getAcquire(this);
43         return existing != null ? existing : loadInstance();
44     }
45
46     private @NonNull C loadInstance() {
47         final var tmp = createInstance();
48         final var witness = (C) INSTANCE.compareAndExchangeRelease(this, null, tmp);
49         return witness == null ? tmp : witness;
50     }
51
52     // This method must allow concurrent loading, i.e. nothing in it may have effects outside of the loaded object
53     abstract @NonNull C createInstance();
54 }