/* * #%L * carewebframework * %% * Copyright (C) 2008 - 2016 Regenstrief Institute, Inc. * %% * 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. * * This Source Code Form is also subject to the terms of the Health-Related * Additional Disclaimer of Warranty and Limitation of Liability available at * * http://www.carewebframework.org/licensing/disclaimer. * * #L% */ package org.carewebframework.ui; import org.carewebframework.ui.LifecycleEventListener.ILifecycleCallback; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Desktop; import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.Session; import org.zkoss.zk.ui.ShadowElement; import org.zkoss.zk.ui.util.DesktopCleanup; import org.zkoss.zk.ui.util.DesktopInit; import org.zkoss.zk.ui.util.SessionCleanup; import org.zkoss.zk.ui.util.SessionInit; import org.zkoss.zk.ui.util.UiLifeCycle; /** * Dispatches desktop, session, and component lifecycle events to registered listeners. This class * must be registered as a listener in the zk.xml configuration file as follows: * * <pre> * <listener> * <listener-class>org.carewebframework.ui.LifecycleEventDispatcher</listener-class> * </listener> * </pre> */ public class LifecycleEventDispatcher implements DesktopInit, DesktopCleanup, SessionInit, SessionCleanup, UiLifeCycle { private static final String ATTR_COMP_LISTENER = "@component_listener"; private static final LifecycleEventListener<Desktop> desktopListener = new LifecycleEventListener<>(); private static final LifecycleEventListener<Session> sessionListener = new LifecycleEventListener<>(); /** * Add a desktop lifecycle callback. * * @param callback The callback to add. */ public static void addDesktopCallback(ILifecycleCallback<Desktop> callback) { desktopListener.addCallback(callback); } /** * Remove a desktop lifecycle callback. * * @param callback The callback to remove. */ public static void removeDesktopCallback(ILifecycleCallback<Desktop> callback) { desktopListener.removeCallback(callback); } /** * Add a session lifecycle callback. * * @param callback The callback to add. */ public static void addSessionCallback(ILifecycleCallback<Session> callback) { sessionListener.addCallback(callback); } /** * Remove a session lifecycle callback. * * @param callback The callback to remove. */ public static void removeSessionCallback(ILifecycleCallback<Session> callback) { sessionListener.removeCallback(callback); } /** * Add a component lifecycle callback. * * @param comp Component whose lifecycle is to be monitored. * @param callback The callback to add. */ public static void addComponentCallback(Component comp, ILifecycleCallback<Component> callback) { getListener(comp, true).addCallback(callback); } /** * Remove a component lifecycle callback. * * @param comp Component whose lifecycle is to be monitored. * @param callback The callback to remove. */ public static void removeComponentCallback(Component comp, ILifecycleCallback<Component> callback) { LifecycleEventListener<Component> listener = getListener(comp, false); if (listener != null) { listener.removeCallback(callback); if (listener.isEmpty()) { comp.removeAttribute(ATTR_COMP_LISTENER); } } } /** * Returns the lifecycle event listener associated with the specified component. * * @param comp The component whose event listener is sought. * @param autoCreate If true and no associated listener exists, one is created. * @return The associated event listener, or null if none exists and autoCreate is false. */ private static LifecycleEventListener<Component> getListener(Component comp, boolean autoCreate) { @SuppressWarnings("unchecked") LifecycleEventListener<Component> listener = (LifecycleEventListener<Component>) comp .getAttribute(ATTR_COMP_LISTENER); if (listener == null && autoCreate) { listener = new LifecycleEventListener<>(); comp.setAttribute(ATTR_COMP_LISTENER, listener); } return listener; } /** * Called by ZK listener dispatcher when a new desktop is initialized. * * @see org.zkoss.zk.ui.util.DesktopInit#init(org.zkoss.zk.ui.Desktop, java.lang.Object) * @param desktop The desktop being initialized. * @param request The active request object. */ @Override public void init(Desktop desktop, Object request) throws Exception { desktopListener.executeCallbacks(desktop, true); } /** * Called by ZK listener dispatcher when a desktop is about to be destroyed. * * @see org.zkoss.zk.ui.util.DesktopCleanup#cleanup(org.zkoss.zk.ui.Desktop) * @param desktop The desktop being destroyed. */ @Override public void cleanup(Desktop desktop) throws Exception { desktopListener.executeCallbacks(desktop, false); } /** * Called by ZK listener dispatcher when a new session is initialized. * * @see org.zkoss.zk.ui.util.SessionInit#init(org.zkoss.zk.ui.Session, java.lang.Object) * @param session The session being initialized. * @param request The active request object. */ @Override public void init(Session session, Object request) throws Exception { sessionListener.executeCallbacks(session, true); } /** * Called by ZK listener dispatcher when a new session is about to be destroyed. * * @see org.zkoss.zk.ui.util.SessionCleanup#cleanup(org.zkoss.zk.ui.Session) * @param session The session being destroyed. */ @Override public void cleanup(Session session) throws Exception { sessionListener.executeCallbacks(session, false); } /** * Called by ZK listener dispatcher when a component is attached. * * @see org.zkoss.zk.ui.util.UiLifeCycle#afterComponentAttached(Component, Page) * @param comp The component being attached. * @param page The page receiving the component. */ @Override public void afterComponentAttached(Component comp, Page page) { executeCallbacks(comp, true); } /** * Called by ZK listener dispatcher when a component is detached. * * @see org.zkoss.zk.ui.util.UiLifeCycle#afterComponentDetached(Component, Page) * @param comp The component being detached. * @param prevpage The page containing the component. */ @Override public void afterComponentDetached(Component comp, Page prevpage) { executeCallbacks(comp, false); } /** * Execute callbacks for the specified component and its descendants. * * @param comp Component whose callbacks are to be executed. * @param init If true, execute the onInit callback; otherwise, the onCleanup callback. */ private void executeCallbacks(Component comp, boolean init) { LifecycleEventListener<Component> listener = getListener(comp, false); if (listener != null) { listener.executeCallbacks(comp, init); } for (Component child : comp.getChildren()) { executeCallbacks(child, init); } } @Override public void afterComponentMoved(Component parent, Component child, Component prevparent) { // ignored } @Override public void afterPageAttached(Page page, Desktop desktop) { // ignored } @Override public void afterPageDetached(Page page, Desktop prevdesktop) { // ignored } @Override public void afterShadowAttached(ShadowElement shadow, Component host) { // ignored } @Override public void afterShadowDetached(ShadowElement shadow, Component prevhost) { // ignored } }