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

org.jacpfx.rcp.util.TearDownHandler Maven / Gradle / Ivy

The newest version!
/*
 * **********************************************************************
 *
 *  Copyright (C) 2010 - 2015
 *
 *  [TearDownHandler.java]
 *  JACPFX Project (https://github.com/JacpFX/JacpFX/)
 *  All rights reserved.
 *
 *  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 org.jacpfx.rcp.util;

import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Node;
import org.jacpfx.api.annotations.lifecycle.PreDestroy;
import org.jacpfx.api.component.Perspective;
import org.jacpfx.api.component.StatelessCallabackComponent;
import org.jacpfx.api.component.SubComponent;
import org.jacpfx.api.workbench.Base;
import org.jacpfx.rcp.component.ASubComponent;
import org.jacpfx.rcp.component.CallbackComponent;
import org.jacpfx.rcp.component.EmbeddedFXComponent;
import org.jacpfx.rcp.registry.ComponentRegistry;
import org.jacpfx.rcp.workbench.GlobalMediator;
import org.jacpfx.rcp.worker.AComponentWorker;
import org.jacpfx.rcp.worker.TearDownWorker;

import java.util.*;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Handles TearDown annotations on all component when application is closed.
 *
 * @author Andy Moncsek
 */
@SuppressWarnings("Convert2streamapi")
public class TearDownHandler {
    private static final ExecutorService executor = Executors
            .newCachedThreadPool(new HandlerThreadFactory(
                    "TearDownHandler:"));
    private static Base, Event, Object> rootWorkbench;

    /**
     * Register the parent workbench, from here all perspective and component
     * should be reachable.
     *
     * @param rootWorkbench, the root workbench
     */
    public static void registerBase(
            Base, Event, Object> rootWorkbench) {
        TearDownHandler.rootWorkbench = rootWorkbench;
    }

    /**
     * perform global teardown on all component. This method will cause all @TearDown
     * annotated methods to be executed.
     */
    public static void handleGlobalTearDown() {
        if (rootWorkbench == null)
            throw new UnsupportedOperationException("can't teardown workbench");
        final List, Event, Object>> perspectives = rootWorkbench
                .getPerspectives();
        if (perspectives == null) return;
        for (final Perspective, Event, Object> perspective : perspectives) {
            // TODO ... teardown perspective itself
            final List, Event, Object>> subcomponents = perspective
                    .getSubcomponents();
            if (subcomponents != null) {
                final List, Event, Object>> handleAsync = new ArrayList<>();
                // TODO FIXME for teardow all parameters in PreDestroyed should be passed -- see init process
                for (final SubComponent, Event, Object> component : subcomponents) {
                    if (CallbackComponent.class.isAssignableFrom(component.getClass())) {
                        handleAsync
                                .add(component);
                    } else {
                        // run teardown in app thread
                        FXUtil.invokeHandleMethodsByAnnotation(PreDestroy.class,
                                component.getComponent());
                    }

                }
                if (!handleAsync.isEmpty())
                    handleAsyncTearDown(handleAsync);

            }

            FXUtil.invokeHandleMethodsByAnnotation(PreDestroy.class,
                    perspective.getPerspective());

        }
        executor.shutdown();
    }

    /**
     * executes all methods in ICallbackComponent, annotated with @OnTeardown
     * outside application thread.
     *
     * @param components, all component that should execute an async teardown
     */
    @SafeVarargs
    public static void handleAsyncTearDown(
            SubComponent, Event, Object>... components) {
        final List, Event, Object>> handleAsync = new ArrayList<>();
        Collections.addAll(handleAsync, components);
        handleAsyncTearDown(handleAsync);
    }

    /**
     * executes all methods in ICallbackComponent, annotated with @OnTeardown
     * outside application thread.
     *
     * @param components, all component that should execute an async teardown
     */
    private static void handleAsyncTearDown(
            final List, Event, Object>> components) {
        try {
            final Set> set = new HashSet<>();
            for (final SubComponent, Event, Object> component : components) {
                if (component instanceof StatelessCallabackComponent) {
                    final StatelessCallabackComponent, Event, Object> tmp = (StatelessCallabackComponent, Event, Object>) component;
                    final List, Event, Object>> instances = tmp.getInstances();
                    for (final SubComponent, Event, Object> instance : instances) {
                        set.add(executor.submit(new TearDownWorker(instance)));
                    }
                }
                set.add(executor.submit(new TearDownWorker(component)));
            }
            awaitTermination(set);
        } catch (RejectedExecutionException e) {
            log("component teardown was not executed");
        }

    }

    public static void shutDownFXComponent(final EmbeddedFXComponent component, final String parentId, final Object... params) {
        // run teardown
        FXUtil.invokeHandleMethodsByAnnotation(PreDestroy.class,
                component.getComponent(), params);
        GlobalMediator.getInstance().clearToolbar(component, parentId);
        component.interruptWorker();
        component.initEnv(null, null);
        ComponentRegistry.removeComponent(component);
    }

    private static void awaitTermination(Set> set) {
        // await termination
        for (final Future future : set) {
            try {
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                log("error while handle TearDown");
                e.printStackTrace();
            }
        }
    }

    public static void shutDownAsyncComponent(final ASubComponent component, final Object... params) {
        if (component instanceof StatelessCallabackComponent) {
            final Set> set = new HashSet<>();
            final StatelessCallabackComponent, Event, Object> tmp = (StatelessCallabackComponent, Event, Object>) component;
            final List, Event, Object>> instances = tmp.getInstances();
            for (final SubComponent, Event, Object> instance : instances) {
                if (instance.isStarted())
                    set.add(executor.submit(new TearDownWorker(instance)));
            }
            awaitTermination(set);
            tmp.getExecutorService().shutdownNow();
            instances.clear();
            ComponentRegistry.removeComponent(component);
        } else {
            try {
                executor.submit(new TearDownWorker(component)).get();
            } catch (InterruptedException | RejectedExecutionException | ExecutionException e) {
                // "hide" exception as this can happen on shutdown
                e.printStackTrace();
            }
            component.interruptWorker();
            component.initEnv(null, null);
            ComponentRegistry.removeComponent(component);
        }
    }

    public static void executePredestroy(final SubComponent, Event, Object> component) {
        FXUtil.invokeHandleMethodsByAnnotation(PreDestroy.class,
                component.getComponent());
    }

    private static void log(final String message) {
        if (Logger.getLogger(AComponentWorker.class.getName()).isLoggable(
                Level.FINE)) {
            Logger.getLogger(AComponentWorker.class.getName()).fine(
                    ">> " + message);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy