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

jdplus.toolkit.desktop.plugin.TsManager Maven / Gradle / Ivy

/*
 * Copyright 2018 National Bank of Belgium
 * 
 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved 
 * by the European Commission - subsequent versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 * 
 * http://ec.europa.eu/idabc/eupl
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and 
 * limitations under the Licence.
 */
package jdplus.toolkit.desktop.plugin;

import jdplus.main.desktop.design.GlobalService;
import jdplus.toolkit.desktop.plugin.util.LazyGlobalService;
import jdplus.toolkit.base.api.timeseries.*;
import jdplus.toolkit.base.tsp.DataSource;
import jdplus.toolkit.base.tsp.DataSourceFactory;
import jdplus.toolkit.base.tsp.DataSourceListener;
import jdplus.toolkit.base.tsp.DataSourceProvider;
import nbbrd.design.swing.OnAnyThread;
import nbbrd.design.swing.OnEDT;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.openide.util.WeakListeners;

import javax.swing.*;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;

/**
 *
 * @author Philippe Charles
 */
@GlobalService
public final class TsManager implements DataSourceFactory, Closeable {

    @NonNull
    public static TsManager get() {
        return LazyGlobalService.get(TsManager.class, TsManager::new);
    }

    private final ConcurrentMap providers;
    private final ConcurrentLinkedQueue events;
    private final List updateListeners;
    private final DataSourceListener listener;
    private final ExecutorService executor;

    private TsManager() {
        this.providers = new ConcurrentHashMap<>();
        this.events = new ConcurrentLinkedQueue<>();
        this.updateListeners = new ArrayList<>();
        this.listener = new DataSourceListenerImpl();
        this.executor = Executors.newCachedThreadPool();

        TsFactory.setDefault(this);
    }

    @Override
    public void close() {
        executor.shutdown();
    }

    @OnAnyThread
    public boolean register(@NonNull TsProvider provider) {
        providers.put(provider.getSource(), provider);
        if (provider instanceof DataSourceProvider) {
            ((DataSourceProvider) provider).addDataSourceListener(listener);
        }
        return true;
    }

    @OnAnyThread
    public boolean unregister(@NonNull TsProvider provider) {
        TsProvider removedProvider = providers.remove(provider.getSource());
        if (removedProvider instanceof DataSourceProvider) {
            ((DataSourceProvider) removedProvider).removeDataSourceListener(listener);
        }
        return true;
    }

    @OnEDT
    public void addWeakListener(@NonNull TsListener listener) {
        addListener(WeakListeners.create(TsListener.class, listener, this));
    }

    @OnEDT
    public void addListener(@NonNull TsListener listener) {
        updateListeners.add(listener);
    }

    @OnEDT
    public void removeListener(@NonNull TsListener listener) {
        updateListeners.remove(listener);
    }

    @Override
    public Optional getProvider(String name) {
        return Optional.ofNullable(providers.get(name));
    }

    public  @NonNull Optional getProvider(@NonNull Class type) {
        return getProviders()
                .filter(type::isInstance)
                .map(type::cast)
                .findFirst();
    }

    @OnEDT
    public void loadAsync(@NonNull Ts ts, @NonNull TsInformationType info, @NonNull Consumer onLoaded) {
        if (!ts.getMoniker().isProvided()) {
            SwingUtilities.invokeLater(() -> onLoaded.accept(ts));
            return;
        }
        executor.execute(() -> {
            Ts loaded = makeTs(ts.getMoniker(), info);
            SwingUtilities.invokeLater(() -> onLoaded.accept(loaded));
        });
    }

    @OnEDT
    public void loadAsync(@NonNull TsCollection col, @NonNull TsInformationType info, @NonNull Consumer onLoaded) {
        if (!col.getMoniker().isProvided() && col.stream().allMatch(s -> !s.getMoniker().isProvided())) {
            return;
        }
        executor.execute(() -> {
            if (col.getMoniker().isProvided()) {
                TsCollection loaded = makeTsCollection(col.getMoniker(), info);
                SwingUtilities.invokeLater(() -> onLoaded.accept(loaded));
            } else {
                // One by one
                TsCollection loaded = col.getItems().stream().map(s
                        -> s.getType().encompass(info) ? s : makeTs(s.getMoniker(), info))
                        .collect(TsCollection.toTsCollection());
                SwingUtilities.invokeLater(() -> onLoaded.accept(loaded));
            }
        });
    }

    @Override
    public Stream getProviders() {
        return providers.values().stream();
    }

    @OnAnyThread
    public void notify(Predicate related) {
        events.add(new TsEvent(this, related));
        SwingUtilities.invokeLater(this::notifyUpdateListeners);
    }

    @OnEDT
    private void notifyUpdateListeners() {
        TsEvent event;
        while ((event = events.poll()) != null) {
            for (TsListener o : updateListeners) {
                o.tsUpdated(event);
            }
        }
    }

    private final class DataSourceListenerImpl implements DataSourceListener {

        @Override
        public void opened(@NonNull DataSource ds) {
        }

        @Override
        public void closed(@NonNull DataSource ds) {
        }

        @OnAnyThread
        @Override
        public void changed(@NonNull DataSource ds) {
            Optional provider = getProvider(DataSourceProvider.class, ds);
            if (provider.isPresent()) {
                TsManager.this.notify(dataSetMoniker -> isRelated(provider.orElseThrow(), ds, dataSetMoniker));
            }
        }

        private boolean isRelated(DataSourceProvider provider, DataSource dataSource, TsMoniker dataSetMoniker) {
            return dataSetMoniker.getSource().equals(provider.getSource())
                    && provider
                            .toDataSet(dataSetMoniker)
                            .filter(dataSet -> dataSet.getDataSource().equals(dataSource))
                            .isPresent();
        }

        @Override
        public void allClosed(@NonNull String string) {
        }
    }

    public static boolean isDynamic(Ts s) {
        TsMoniker moniker = s.getMoniker();
        return moniker.isProvided() && moniker.getSource().equals(TsDynamicProvider.DYNAMIC);
    }

    public static boolean isDynamic(TsCollection coll) {
        return coll.stream().anyMatch(s -> isDynamic(s));
    }

    public static TsCollection frozenCopyOf(TsCollection input) {
        return input.stream().map(Ts::freeze).collect(TsCollection.toTsCollection());
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy