001/**
002 * Copyright (C) 2006-2025 Talend Inc. - www.talend.com
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.talend.sdk.component.runtime.serialization;
017
018import static java.util.Optional.ofNullable;
019import static lombok.AccessLevel.PRIVATE;
020
021import java.util.Iterator;
022import java.util.ServiceLoader;
023import java.util.concurrent.atomic.AtomicReference;
024import java.util.function.Supplier;
025
026import lombok.NoArgsConstructor;
027
028@FunctionalInterface
029public interface ContainerFinder {
030
031    LightContainer find(String plugin);
032
033    @NoArgsConstructor(access = PRIVATE)
034    final class Instance {
035
036        private static final AtomicReference<ContainerFinder> FINDER = new AtomicReference<>();
037
038        public static boolean isInitialized() {
039            return FINDER.get() != null;
040        }
041
042        // really a classloader (JVM most of the time) singleton since it is intended to
043        // be used by serialization
044        public static void set(final Supplier<ContainerFinder> provider) {
045            // todo: do we want some safety here or not? normally shouldnt be needed, then
046            // Supplier would be needed
047            FINDER.set(provider.get());
048        }
049
050        public static ContainerFinder get() {
051            if (!isInitialized()) {
052                synchronized (FINDER) {
053                    if (!isInitialized()) {
054                        final Iterator<ContainerFinder> loader = ServiceLoader
055                                .load(ContainerFinder.class, ContainerFinder.class.getClassLoader())
056                                .iterator();
057                        if (loader.hasNext()) {
058                            FINDER.set(loader.next());
059                        }
060                    }
061                }
062            }
063
064            // fallback on TCCL, depending the packaging it can work or not safer to not
065            // return null here
066            return ofNullable(FINDER.get()).orElseGet(TCCLContainerFinder::new);
067        }
068    }
069}