org.zkoss.zk.ui.sys.DesktopCtrl Maven / Gradle / Ivy
/* DesktopCtrl.java
Purpose:
Description:
History:
Fri Jul 29 08:47:19 2005, Created by tomyeh
Copyright (C) 2005 Potix Corporation. All Rights Reserved.
{{IS_RIGHT
This program is distributed under LGPL Version 2.1 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.zk.ui.sys;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import org.zkoss.util.media.Media;
import org.zkoss.zk.ui.Session;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Execution;
import org.zkoss.zk.ui.UiException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.impl.DesktopEventQueue;
import org.zkoss.zk.ui.util.EventInterceptor;
import org.zkoss.zk.au.AuRequest;
import org.zkoss.zk.au.AuResponse;
/**
* An addition interface to {@link Desktop}
* for implementation.
*
* Note: applications shall never access this interface.
*
* @author tomyeh
*/
public interface DesktopCtrl {
/** Returns the request queue.
*/
public RequestQueue getRequestQueue();
/** Returns the next available key which is unique in the whole desktop.
*/
public int getNextKey();
/** Returns the next available UUID for a page.
* The returned UUID is unique in the desktop.
* You can consider it as unique in the whole session, though
* it may not be true if {@link org.zkoss.zk.ui.ext.RawId} is used
* (developer's responsibility to avoid conflict),
* integer overflow (too many UUID in one session, which
* can be considered as impossible), or a custom ID generator
* ({@link org.zkoss.zk.ui.sys.IdGenerator}) is used.
* @since 5.0.3
*/
public String getNextUuid(Page page);
/** Returns the next available UUID for a component.
* The returned UUID is unique in the desktop.
* You can consider it as unique in the whole session, though
* it may not be true if {@link org.zkoss.zk.ui.ext.RawId} is used
* (developer's responsibility to avoid conflict),
* integer overflow (too many UUID in one session, which
* can be considered as impossible), or a custom ID generator
* ({@link org.zkoss.zk.ui.sys.IdGenerator}) is used.
* @since 5.0.3
*/
public String getNextUuid(Component comp);
/** Adds a component to this page.
*
It is used internally and developers shall not invoke it
* explicityly.
* @exception InternalError if there is a component associated with
* the same UUID
*/
public void addComponent(Component comp);
/** Maps a component associated with the given UUID to this page.
* Notice that the given uuid can be different from comp's UUID
* ({@link Component#getUuid}).
*
If the given component is null, the mapping of UUID is removed.
*
Unlike {@link #addComponent} and {@link #removeComponent}, this method simply replaces
* the mapping if the given UUID is already mapped to the other component.
*
It is used internally and developers shall not invoke it
* explicitly.
* @param comp the component to associate with the given UUID.
* If not, the association (i.e., mapping) is removed.
* @return the previous component that was associated with the given UUID.
* @since 6.0.0
*/
public Component mapComponent(String uuid, Component comp);
/** Removes a component to this page.
*
It is used internally and developers shall not invoke it
* explicitly.
* @param recycleUuidAllowed whether it is OK to recycle UUID.
* @return whether UUID is recycled. If true, the caller shall
* reset UUID of the give component.
* @since 5.0.4
*/
public boolean removeComponent(Component comp, boolean recycleUuidAllowed);
/** Adds a page to this desktop.
* It must be called when a page is created.
*
*
This is one of the only few method you could access
* before activating an execution.
*/
public void addPage(Page page);
/** Removes a page from this desktop.
*
NOTE: once a page is removed, you can NOT add it back.
* You shall just GC it.
*/
public void removePage(Page page);
/** Sets the desktop identifier.
*
*
It is callable only if it is the recovering phase, i.e.,
* {@link ExecutionCtrl#isRecovering} is true.
* In other words, callable only in the invocation of
* {@link FailoverManager#recover}.
*
* @exception IllegalStateException if it is NOT in recovering.
*/
public void setId(String id);
/** Called when the recovering failed.
*/
public void recoverDidFail(Throwable ex);
/** Notification that the session, which owns this desktop,
* is about to be passivated (a.k.a., serialized) by the Web container.
*/
public void sessionWillPassivate(Session sess);
/** Notification that the session, which owns this desktop,
* has just been activated (a.k.a., deserialized) by the Web container.
*/
public void sessionDidActivate(Session sess);
/** Called when the desktop is about to be destroyed.
*/
public void destroy();
/** Called when the desktop has been recycled.
* More precisely, it is called when the desktop is no longer used
* and ready to be re-used later.
* @since 5.0.7
*/
public void recycle();
/** Returns a collection of suspended event processing threads, or empty
* if no suspended thread at all.
*
*
An event processing thread is an instance of
* {@link EventProcessingThread}
*
*
Note: if you access this method NOT in an event listener for
* the SAME desktop, you have to synchronize the iteration
* (though the returned collection is synchronized).
* Of course, it is always safe to test whether it is empty
* ({@link Collection#isEmpty}).
*
*
//Use the following pattern IF it is not in the SAME desktop's listener
Collection c = otherDesktop.getSuspendedThreads();
if (c.isEmpty()) {
//do something accordingly
} else {
synchronized (c) {
for (Iterator it = c.iterator(); it.hasNext();) {
//...
}
}
}
*/
public Collection getSuspendedThreads();
/** Ceases the specified event thread.
*
* @param cause an arbitrary text to describe the cause.
* It will be the message of the thrown InterruptedException.
* @return true if the event processing thread is ceased successfully;
* false if no such thread or it is not suspended.
*/
public boolean ceaseSuspendedThread(EventProcessingThread evtthd, String cause);
/** Returns the media that is associated with
* {@link Desktop#getDownloadMediaURI}, or
* null if not found.
*
* This method is used internally. Developers rarely need to
* access this method.
*
* @param reserved reserved for future use.
* @return the media or null if not found.
*/
public Media getDownloadMedia(String medId, boolean reserved);
/** Called when a component added or removed a listener for
* {@link Events#ON_PIGGYBACK}.
*
*
The implementation usually uses it to optimize whether to
* call the listener when {@link #onPiggyback} is called.
*
* @param comp the component that adds an listener for
* {@link Events#ON_PIGGYBACK}.
* The component may or may not be a root component.
* @param listen whether the listener is added (or removed).
* @since 3.0.0
*/
public void onPiggybackListened(Component comp, boolean listen);
/** Called each time when ZK Update Engine retrieves events.
* It is used to implement the piggyback feature by posting
* the events (see {@link Events#ON_PIGGYBACK}).
* The implementation could post events here. It should not process
* event here (since event thread might be used).
*
*
Used only internally. Application developers shall not call it.
*
* @since 3.0.0
*/
public void onPiggyback();
/** Returns the server-push controller, or null if it is not enabled
* yet.
*/
public ServerPush getServerPush();
/** Enables the server-push feature with the specified server-push
* controller.
* If you want to use the default serverpush, use {@link Desktop#enableServerPush}
* instead. This method allows the caller to provide a server push
* for more control.
*
Example:
*
desktop.enableServerPush(new PollingServerPush(1000,6000,5));
*
* Notice: a server push controller can be used in one desktop.
* It cannot be shared.
*
* @param serverpush the server-push controller. If null,
* the server-push feature is disabled (for this desktop).
* Note: this method will invoke {@link ServerPush#start}, so the
* caller doesn't need to do it.
* @since 3.0.0
* @see Desktop#enableServerPush
*/
public boolean enableServerPush(ServerPush serverpush);
/** Invokes {@link EventInterceptor#beforeSendEvent}
* registered by {@link Desktop#addListener}.
*
*
Note: it invokes
* {@link org.zkoss.zk.ui.util.Configuration#beforeSendEvent}
* automatically.
* @since 3.0.0
*/
public Event beforeSendEvent(Event event);
/** Invokes {@link EventInterceptor#beforePostEvent}
* registered by {@link Desktop#addListener}.
*
*
Note: it invokes
* {@link org.zkoss.zk.ui.util.Configuration#beforePostEvent}
* automatically.
* @since 3.0.0
*/
public Event beforePostEvent(Event event);
/** Invokes {@link EventInterceptor#beforeProcessEvent}
* registered by {@link Desktop#addListener}.
*
*
Note: it invokes
* {@link org.zkoss.zk.ui.util.Configuration#beforeProcessEvent}
* automatically.
* @since 3.0.0
*/
public Event beforeProcessEvent(Event event) throws Exception;
/** Invokes {@link EventInterceptor#afterProcessEvent}
* registered by {@link Desktop#addListener}.
*
*
Note: it invokes
* {@link org.zkoss.zk.ui.util.Configuration#afterProcessEvent}
* automatically.
* @since 3.0.0
*/
public void afterProcessEvent(Event event) throws Exception;
/** Invokes {@link org.zkoss.zk.ui.util.DesktopCleanup#cleanup} for each relevant
* listener registered by {@link Desktop#addListener}.
*
*
Used only internally.
*
*
It never throws an exception.
*
* @since 3.0.6
*/
public void invokeDesktopCleanups();
/** Invokes {@link org.zkoss.zk.ui.util.ExecutionInit#init} for each relevant
* listener registered by {@link Desktop#addListener}.
*
*
Used only internally.
*
* @param exec the execution that is created
* @param parent the previous execution, or null if no previous at all
* @exception UiException to prevent an execution from being created
* @since 3.0.6
*/
public void invokeExecutionInits(Execution exec, Execution parent)
throws UiException;
/** Invokes {@link org.zkoss.zk.ui.util.ExecutionCleanup#cleanup} for each relevant
* listener registered by {@link Desktop#addListener}.
*
*
Used only internally.
*
*
It never throws an exception but logs and adds it to the errs argument,
* if not null.
*
* @param exec the execution that is being destroyed
* @param parent the previous execution, or null if no previous at all
* @param errs a list of exceptions (java.lang.Throwable) if any exception
* occurred before this method is called, or null if no exception at all.
* Note: you can manipulate the list directly to add or clean up exceptions.
* For example, if exceptions are fixed correctly, you can call errs.clear()
* such that no error message will be displayed at the client.
* @since 3.0.6
*/
public void invokeExecutionCleanups(Execution exec, Execution parent, List errs);
/** Invokes {@link org.zkoss.zk.ui.util.UiLifeCycle#afterComponentAttached}.
* @since 3.0.6
*/
public void afterComponentAttached(Component comp, Page page);
/** Invokes {@link org.zkoss.zk.ui.util.UiLifeCycle#afterComponentDetached}.
* @since 3.0.6
*/
public void afterComponentDetached(Component comp, Page prevpage);
/** Invokes {@link org.zkoss.zk.ui.util.UiLifeCycle#afterComponentMoved}.
*
* @param prevparent the previous parent. If it is the same as
* comp's {@link Component#getParent}, comp is moved in the same parent.
* @since 3.0.6
*/
public void afterComponentMoved(Component parent, Component child, Component prevparent);
//Response Utilities//
/** Called when ZK Update Engine has sent a response to the client.
*
* @param reqId the request ID that the response is generated for.
* Ignore if null.
* @param resInfo the response. Ignored if reqId is null.
* @since 5.0.0
*/
public void responseSent(String reqId, Object resInfo);
/** Returns the response for the last request, or null
* if no response yet, or the specified request ID doesn't match
* the last one (passed to {@link #responseSent}).
* The return value is the value passed to resInfo when calling
* {@link #responseSent}.
* @since 5.0.0
*/
public Object getLastResponse(String reqId);
/** Returns the sequence ID of the response.
* The client and server uses the sequence ID to make sure
* the responses are processed in the correct order.
*
*
The range of the sequence IDs is 1~999.
*
* @param advance whether to advance the number before returning.
* If true, the ID is increased and then returned.
* If false, the previous value is returned
* @since 3.5.0
*/
public int getResponseId(boolean advance);
/** Sets the sequence ID of the response.
*
*
It is rarely called other than in the recovering mode, i.e.,
* {@link ExecutionCtrl#isRecovering} is true.
*
* @param resId a value between 1 and 999.
* You can reset the ID by passing a non-positive value.
* @since 3.5.0
*/
public void setResponseId(int resId);
/** Adds the responses to the so-called piggy-back queue.
* The responses in the piggy-back queue will be sent in
* the next AU request.
*
This method is useful for working thread that
* wants to sent the responses back to the client.
* A typical example is the Comet-based server push.
*
* @param response the responses to be appended to the piggy-back queue.
* @param reset whether to reset the piggy-back queue after
* returning the queued responses.
* @return all responses in the piggy-back queue, or null
* if nothing in the queue.
* @since 5.0.0
*/
public List piggyResponse(Collection response, boolean reset);
/** Schedules a task to run under the server push of the given desktop asynchronously.
* It is called by {@link org.zkoss.zk.ui.Executions#schedule}.
* Don't call it directly.
* Like {@link #activateServerPush} and {@link #deactivateServerPush}, this method could
* be called in any thread, so the implementation of this method has to be safe for concurrent access.
* @param task the task to execute
* @param event the event to be passed to the task (i.e., the event listener).
* It could null or any instance as long as the task recognizes it.
* @exception IllegalStateException if the server push is not enabled.
* @exception DesktopUnavailableException if the desktop is removed
* (when activating).
* @since 5.0.6
*/
public void scheduleServerPush(EventListener task, T event);
/** Returns if there is any scheduled task for server push.
* @since 5.0.6
*/
public boolean scheduledServerPush();
/** Activates the current thread for accessing this desktop by the server push.
* It is called by {@link org.zkoss.zk.ui.Executions#activate}.
* Don't call it directly.
*
* Like {@link #scheduleServerPush}, this method could
* be called in any thread, so it has to be safe for concurrent access.
*
Note: the server push must be enabled first (by use of
* {@link Desktop#enableServerPush}).
*
* @param timeout the maximum time to wait in milliseconds.
* Ignored (i.e., never timeout) if non-positive.
* @exception IllegalStateException if the server push is not enabled.
* @since 3.5.2
*/
public boolean activateServerPush(long timeout)
throws InterruptedException;
/** Deactivates the thread that has invoked {@link #activateServerPush}
* successfully.
* It is called by {@link org.zkoss.zk.ui.Executions#deactivate}.
* Don't call it directly.
* @since 3.5.2
*/
public void deactivateServerPush();
/**
* Enable/Disable serverpush using reference counting, so that multiple enablers can
* use the same serverpush and deregister whenever they want.
* @param enable true/false enable/disable serverpush
* @param enabler the same reference must be used to disable again
* @return Currently only used by {@link DesktopEventQueue} to enable several
* eventqueues to use the same {@link ServerPush}
* @since 6.5.4
*/
public boolean enableServerPush(boolean enable, Serializable enabler);
/** Processes an AU request.
* Notice that not only the requests for a desktop but also the requests
* for any component in the desktop will go thru this method.
*
*
To override the default processing, register an AU request service
* {@link org.zkoss.zk.au.AuService} by invoking {@link Desktop#addListener}.
*
*
* - This method first invokes the registered AU request service
* ({@link org.zkoss.zk.au.AuService}) one-by-one, until
* the first one returns true.
* - If none of them returns true or no AU service at all,
* it checks if the request is targeting a component
* (i.e., {@link AuRequest#getComponent} is not null).
* - If it is targeting a component, it invokes
* {@link ComponentCtrl#service} to handle the service.
* - If it is not targeting a component (i.e., targeting to
* this desktop), it handles as follows.
*
* - It handles the recognized requests, including
* onBookmarkChange, onURIChange and onClientInfo.
* - If the request is not one of above, it converts the request to
* an event (by {@link Event#getEvent}) and then posts the event
* (by {@link Events#postEvent}).
*
*
* Notice that the registered AU request service
* ({@link org.zkoss.zk.au.AuService}) will be called, no matter
* the request is targeting a component or a desktop.
* And, it can 'intercept' or 'filter' it by returning false.
*
*
To send responses to the client, use
* {@link org.zkoss.zk.ui.AbstractComponent#smartUpdate},
* {@link org.zkoss.zk.ui.AbstractComponent#response}
* or {@link Component#invalidate()}.
*
*
If you want to intercept events, you can register a listener implementing
* {@link EventInterceptor}, or overriding {@link #afterProcessEvent}.
*
* @param everError if any error ever occurred before
* processing this request. In other words, indicates if the previous
* request causes any exception.
* @since 5.0.0
*/
public void service(AuRequest request, boolean everError);
/** Sets the execution (used to represent a lock).
*
Used only to implement {@link UiEngine}.
*/
public void setExecution(Execution exec);
/** Returns the visualizer associated with this desktop.
*
Used only to implement {@link UiEngine}.
* @since 3.6.2
*/
public Visualizer getVisualizer();
/** Sets the visualizer associated with is desktop.
*
Used only to implement {@link UiEngine}.
* @since 3.6.2
*/
public void setVisualizer(Visualizer uv);
/** Returns the lock used to activate an execution.
* Before calling {@link #setVisualizer}, this object returned
* by this method must be locked first.
*
Used only to implement {@link UiEngine}.
* @since 3.6.2
*/
public Object getActivationLock();
}