Package org.jrebirth.af.core.link

Source Code of org.jrebirth.af.core.link.WaveHandler

/**
* Get more info at : www.jrebirth.org .
* Copyright JRebirth.org © 2011-2013
* Contact : sebastien.bordes@jrebirth.org
*
* 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.jrebirth.af.core.link;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.jrebirth.af.core.concurrent.AbstractJrbRunnable;
import org.jrebirth.af.core.concurrent.JRebirth;
import org.jrebirth.af.core.concurrent.JRebirthRunnable;
import org.jrebirth.af.core.concurrent.RunInto;
import org.jrebirth.af.core.concurrent.RunType;
import org.jrebirth.af.core.concurrent.RunnablePriority;
import org.jrebirth.af.core.exception.CoreException;
import org.jrebirth.af.core.exception.JRebirthThreadException;
import org.jrebirth.af.core.exception.WaveException;
import org.jrebirth.af.core.facade.WaveReady;
import org.jrebirth.af.core.log.JRLogger;
import org.jrebirth.af.core.log.JRLoggerFactory;
import org.jrebirth.af.core.ui.Model;
import org.jrebirth.af.core.util.ClassUtility;
import org.jrebirth.af.core.wave.Wave;
import org.jrebirth.af.core.wave.WaveData;
import org.jrebirth.af.core.wave.checker.WaveChecker;

/**
* The class <strong>WaveHandler</strong> is used to define how to manage a Wave for wave type subscribers.
*
* @author Sébastien Bordes
*/
public class WaveHandler implements LinkMessages {

    /** The class logger. */
    private static final JRLogger LOGGER = JRLoggerFactory.getLogger(WaveHandler.class);

    /** The wave ready component that will handle the wave. */
    private final WaveReady<?> waveReady;

    /** The default method to call, will been used when annotation is put on a method, otherwise could be null. */
    private final Method defaultMethod;

    /** The wave checker taht check if the wave could be handled, could be null. */
    private final WaveChecker waveChecker;

    /**
     * Instantiates a new wave handler.
     *
     * @param waveReady the wave ready component that will handle the wave
     * @param waveChecker the wave checker, could be null
     * @param defaultMethod the default method to call, could be null
     */
    public WaveHandler(final WaveReady<?> waveReady, final WaveChecker waveChecker, final Method defaultMethod) {
        super();
        this.waveReady = waveReady;
        this.waveChecker = waveChecker;
        this.defaultMethod = defaultMethod;
    }

    /**
     * Check the wave if the wave checker is not null anf if it returns true.
     *
     * @param wave the wave to check
     *
     * @return true, if check succeeded or if wave checker is null
     */
    public boolean check(final Wave wave) {
        // Skip the check if there isn't any checker
        return this.waveChecker == null || this.waveChecker.call(wave);
    }

    /**
     * Gets the wave ready.
     *
     * @return Returns the waveReady.
     */
    public WaveReady<?> getWaveReady() {
        return this.waveReady;
    }

    /**
     * Handle the wave into JAT for model component or into current thread for others.
     *
     * @param wave the wave to manage
     *
     * @throws WaveException if an error occurred while processing the wave
     */
    public void handle(final Wave wave) throws WaveException {

        final Method customMethod = retrieveCustomMethod(wave);

        if (customMethod == null) {
            throw new WaveException(wave);
        }

        // Grab the run type annotation (if exists)
        final RunInto runInto = customMethod.getAnnotation(RunInto.class);

        // Retrieve the annotation runnable priority (if any)
        final RunnablePriority priority = runInto == null ? RunnablePriority.Normal : runInto.priority();

        // Retrieve the annotation run type (if any)
        final RunType runType = runInto == null ? null : runInto.value();

        final JRebirthRunnable waveHandlerRunnable = buildWaveRunnable(wave, customMethod, priority);

        // If the notified class is part of the UI
        // We must perform this action into the JavaFX Application Thread
        // only if the run type hasn't been overridden
        if (runType != null && runType == RunType.JAT || runType == null && getWaveReady() instanceof Model) {
            JRebirth.runIntoJAT(waveHandlerRunnable);

            // Launch the wave handling into JRebirth Thread Pool
        } else if (runType != null && runType == RunType.JTP) {
            JRebirth.runIntoJTP(waveHandlerRunnable);
        } else {
            // Otherwise we can perform it right now into the current thread (JRebirthThread - JIT)
            waveHandlerRunnable.run();
        }

    }

    /**
     * Build the wave runnable handler that will handle the wave into the right thread.
     *
     * @param wave the wave to handle
     * @param customMethod the custom method to call (could be null)
     * @param priority the runnable priority to use
     *
     * @return the right JRebirth Runnable
     */
    private JRebirthRunnable buildWaveRunnable(final Wave wave, final Method customMethod, final RunnablePriority priority) {

        return new AbstractJrbRunnable(getWaveReady().getClass().getSimpleName() + " handle wave " + wave.toString(), priority) {

            /**
             * {@inheritDoc}
             */
            @Override
            protected void runInto() throws JRebirthThreadException {
                try {
                    performHandle(wave, customMethod);
                } catch (final WaveException e) {
                    LOGGER.error(WAVE_HANDLING_ERROR, e);
                }
            }
        };
    }

    /**
     * Retrieve the custom wave handler method.
     *
     * @param wave the wave to be handled
     *
     * @return the custom handler emthod or null if none exists
     */
    private Method retrieveCustomMethod(final Wave wave) {
        Method customMethod = null;
        try {
            // Search the wave handler method to call
            customMethod = this.defaultMethod != null
                    // Method defined with annotation
                    ? this.defaultMethod
                    // Method computed according to wave prefix and wave type action name
                    : ClassUtility.getMethodByName(getWaveReady().getClass(), ClassUtility.underscoreToCamelCase(wave.getWaveType().toString()));

        } catch (final NoSuchMethodException e) {

            LOGGER.info(CUSTOM_METHOD_NOT_FOUND, e.getMessage());
        }
        return customMethod;
    }

    /**
     * Perform the handle independently of thread used.
     *
     * @param wave the wave to manage
     * @param method the handler method to call, could be null
     *
     * @throws WaveException if an error occurred while processing the wave
     */
    private final void performHandle(final Wave wave, final Method method) throws WaveException {

        // Build parameter list of the searched method
        final List<Object> parameterValues = new ArrayList<>();
        for (final WaveData<?> wd : wave.getWaveItems()) {
            // Add only wave items defined as parameter
            if (wd.getKey().isParameter()) {
                parameterValues.add(wd.getValue());
            }
        }
        // Add the current wave to process
        parameterValues.add(wave);

        // If custom method exists we call it
        if (method != null) {

            try {

                ClassUtility.callMethod(method, getWaveReady(), parameterValues.toArray());

            } catch (final CoreException e) {
                LOGGER.error(WAVE_DISPATCH_ERROR, e);
                // Propagate the wave exception
                throw new WaveException(wave, e);
            }

        } else {
            // If no custom method was proviced, call the default method named 'processWave(wave)'
            try {
                ClassUtility.getMethodByName(getWaveReady().getClass(), AbstractWaveReady.PROCESS_WAVE_METHOD_NAME).invoke(getWaveReady(), wave);
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException e) {
                LOGGER.error(WAVE_DISPATCH_ERROR, e);
                // Propagate the wave exception
                throw new WaveException(wave, e);
            }
        }

    }
}
TOP

Related Classes of org.jrebirth.af.core.link.WaveHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.