All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.devbench.uibuilder.data.common.datasource.CommonDataSourceReferenceHolder Maven / Gradle / Ivy

/*
 *
 * Copyright © 2018 Webvalto Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.devbench.uibuilder.data.common.datasource;

import com.vaadin.flow.component.Component;
import io.devbench.uibuilder.data.api.datasource.interfaces.DataSourceRefreshNotifiable;
import io.devbench.uibuilder.data.api.exceptions.DataSourceReferenceException;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;

import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class CommonDataSourceReferenceHolder {

    private final Map> referringComponentsTypeMap;

    @Getter
    private DATA_SOURCE dataSource;

    CommonDataSourceReferenceHolder(Component initialReference, DATA_SOURCE dataSource) {
        this.dataSource = dataSource;
        referringComponentsTypeMap = new ConcurrentHashMap<>();
        referringComponentsTypeMap.put(createKey(initialReference), createWeakReferenceThenPrepareForCleanupFor(initialReference));
    }

    boolean containsReferences() {
        return referringComponentsTypeMap.values().stream()
            .anyMatch(componentWeakReference -> componentWeakReference.get() != null);
    }

    boolean canHoldReference(Component component) {
        return !referringComponentsTypeMap.containsKey(createKey(component))
            || referringComponentsTypeMap.get(createKey(component)).get() == component;
    }

    void registerReference(Component component) {
        if (canHoldReference(component)) {
            if (referringComponentsTypeMap.containsKey(createKey(component))) {
                return;
            }
            referringComponentsTypeMap.put(createKey(component), createWeakReferenceThenPrepareForCleanupFor(component));
        } else {
            throw new DataSourceReferenceException("Reference cannot be registered, because the holder already contains a reference with this class.");
        }
    }

    boolean hasReferenceTo(Component component) {
        return referringComponentsTypeMap.containsKey(createKey(component))
            && referringComponentsTypeMap.get(createKey(component)).get() == component;
    }

    void notifyReferencesAboutRefresh() {
        referringComponentsTypeMap.values().stream()
            .map(WeakReference::get)
            .filter(DataSourceRefreshNotifiable.class::isInstance)
            .map(DataSourceRefreshNotifiable.class::cast)
            .forEach(DataSourceRefreshNotifiable::refresh);
    }

    private WeakReference createWeakReferenceThenPrepareForCleanupFor(Component component) {
        WeakReference componentWeakReference = createWeakReferenceFor(component);
        component.addDetachListener(event -> componentWeakReference.clear());
        return componentWeakReference;
    }

    WeakReference createWeakReferenceFor(Component component) {
        return new WeakReference<>(component);
    }

    @SuppressWarnings("unchecked")
    void notifyReferencesAboutDataSourceChange(String dataSourceId, CommonDataSourceSelector selector) {
        referringComponentsTypeMap.values().stream()
            .map(WeakReference::get)
            .filter(DataSourceChangeNotifiable.class::isInstance)
            .map(DataSourceChangeNotifiable.class::cast)
            .forEach(changeListener -> changeListener.dataSourceChanged(dataSourceId, selector, dataSource));
    }

    void setDataSource(DATA_SOURCE dataSource) {
        this.dataSource = dataSource;
    }

    private ContextKey createKey(Component component) {
        if (component instanceof SupportsDataSourceReuse) {
            return new ContextKey(component.getClass(), ((SupportsDataSourceReuse) component).getContextId());
        }

        return new ContextKey(component.getClass(), "");
    }

    @Getter
    @EqualsAndHashCode
    @AllArgsConstructor
    static class ContextKey {
        private Class clazz;
        private String contextId;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy