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

org.wings.session.LowLevelEventDispatcher Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2000,2005 wingS development team.
 *
 * This file is part of wingS (http://wingsframework.org).
 *
 * wingS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 *
 * Please see COPYING for the complete licence.
 */
package org.wings.session;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wings.LowLevelEventListener;
import org.wings.SComponent;
import org.wings.SFrame;
import org.wings.comet.Comet;
import org.wings.comet.Pushable;

import java.util.*;

/**
 * Registers session component instants which want to receive low level events.
 * The dispatcher holds a list of all known low level event listeners and is responsible
 * to dispatch the according part of an original HTTP request to the
 * {@link LowLevelEventListener#processLowLevelEvent(String, String[])} method of the registered
 * {@link LowLevelEventListener}s.
 *
 * @author Armin Haaf
 */
public final class LowLevelEventDispatcher
        implements java.io.Serializable {
    private final transient static Logger log = LoggerFactory.getLogger(LowLevelEventDispatcher.class);

    /**
     * The name prefix is stored in the
     * HashMap as key. The value is a Set (ArrayList) of {@link LowLevelEventListener}s
     */
    private final HashMap listeners = new HashMap();

    private String eventEpoch;

    protected boolean namedEvents = true;

    private final Session session;

    public LowLevelEventDispatcher(Session session) {

        this.session = session;
    }

    public final void addLowLevelEventListener(LowLevelEventListener gl,
                                               String eventId) {
        List l = (List) listeners.get(eventId);
        if (l == null) {
            l = new ArrayList(2);
            l.add(gl);
            listeners.put(eventId, l);
        } else if (!l.contains(gl)) {
            l.add(gl);
        }
    }

    public final void removeLowLevelEventListener(LowLevelEventListener gl,
                                                  String eventId) {
        List l = (List) listeners.get(eventId);
        if (l != null) {
            l.remove(gl);
            if (l.isEmpty()) {
                listeners.remove(eventId);
            }
        }
    }

    /**
     * Returns list of registered low level event listener for the given event id.
     *
     * @param eventId The id (HTTP request parameter name) under which the listeners are registered.
     * @return A list of registered low level event listener for the given event id.
     */
    public final List getLowLevelEventListener(String eventId) {
        final List list = (List) listeners.get(eventId);
        return list != null ? Collections.unmodifiableList(list) : Collections.emptyList();
    }

    /**
     * Register low level event listeners additionally by their component name as event id.
     * Used for purposes where you use fixed ids vs. dnymaically applied ids.
     *
     * @param registerListenerAlsoUnderName if true then components will also receieve
     *                                      HTTP values under their {@link org.wings.SComponent#getName()}
     *                                      in addition to {@link org.wings.LowLevelEventListener#getLowLevelEventId()}
     */
    public final void setNamedEvents(boolean registerListenerAlsoUnderName) {
        namedEvents = registerListenerAlsoUnderName;
    }

    /**
     * Registers a low level event listeners (for HTTP request processing).
     * 

* The NamePrefix of the listeners id is used as HTTP requestr parameter name. . * * @param gl listeners */ public void register(LowLevelEventListener gl) { if (gl != null) { final String id = gl.getLowLevelEventId(); log.debug("register id '" + id + "' (type: " + gl.getClass() + ')'); addLowLevelEventListener(gl, id); } } public void unregister(LowLevelEventListener gl) { if (gl != null) { final String id = gl.getLowLevelEventId(); log.debug("unregister id '" + id + "' (type: " + gl.getClass() + ')'); removeLowLevelEventListener(gl, id); } } boolean lowLevelEventPhase; void startLowLevelEventPhase() { lowLevelEventPhase = true; } void endLowLevelEventPhase() { lowLevelEventPhase = false; } public boolean isLowLevelEventPhase() { return lowLevelEventPhase; } /** * dispatch the events, encoded as [name/(multiple)values] * in the HTTP request. the part in front of the UID_DIVIDER ('-') is removed, first. * if the remainder contains an underscore ('_'), only the portion afore will be used * to identify the target component. * * @param name * @param values * @return if the event has been dispatched */ public boolean dispatch(String name, String... values) { String id = null; String suffix = null; // Does name contain underscores? int dividerIndex = name.indexOf('_'); if (dividerIndex > 0) { // Use the part before the first '_' as the // ID to detect the low level event listener id = name.substring(0, dividerIndex); suffix = name.substring(dividerIndex + 1); } else { id = name; // ID equals name in case of no '_' } final List l = (List) listeners.get(id); boolean result = false; if (l != null && l.size() > 0) { for (Object aL : l) { LowLevelEventListener gl = (LowLevelEventListener) aL; if (gl.isEnabled()) { if (!gl.isEpochCheckEnabled() || isEventEpochValid(gl)) { if (!"focus".equals(suffix) || gl instanceof SFrame) { if (log.isDebugEnabled()) { log.debug("processing event '" + name + "' by " + gl.getClass() + '(' + gl.getLowLevelEventId() + ')'); } gl.processLowLevelEvent(name, values); result = true; } } } } } return result; } protected boolean isEventEpochValid(LowLevelEventListener gl) { if (eventEpoch != null) { SFrame frame = ((SComponent) gl).getParentFrame(); if (frame == null) { if (log.isDebugEnabled()) { log.debug("request for dangling component '" + gl.getName() + '\''); } unregister(gl); return false; } if (!eventEpoch.equals(frame.getEventEpoch())) { if (log.isDebugEnabled()) { log.debug("### got outdated event '" + gl.getName() + "' from frame '" + frame.getName() + "' --> received epoch: " + eventEpoch + " | expected epoch: " + frame.getEventEpoch()); } frame.fireInvalidLowLevelEventListener(gl); frame.reload(); return false; } } return true; } void clear() { listeners.clear(); } private final List runnables = new LinkedList<>(); public void invokeLater(Runnable runnable) { synchronized (this.runnables) { runnables.add(runnable); } final Comet comet = session.getComet(); if (comet == null) return; final Pushable pushable = comet.getPushable(); if (SessionManager.getSession() != session) { synchronized (pushable) { if (pushable.isValid()) { pushable.push(); log.info("push called (Pushable: " + pushable + ")\n"); } } } } public void invokeLater_piggyback(Runnable runnable) { synchronized (this.runnables) { runnables.add(runnable); } } void invokeRunnables() { synchronized (this.runnables) { for (Iterator iterator = runnables.iterator(); iterator.hasNext();) { Runnable runnable = null; try { runnable = (Runnable)iterator.next(); try { runnable.run(); } catch (Throwable e) { log.error(runnable.toString(), e); } iterator.remove(); } catch(ConcurrentModificationException e) { throw new RuntimeException("Runnable class: " + runnable.getClass().getName(), e); } } } } public boolean isRunnablesListEmpty() { synchronized (this.runnables) { return runnables.isEmpty(); } } protected void setEventEpoch(String epoch) { this.eventEpoch = epoch; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy