nextapp.echo.webcontainer.UserInstanceContainer Maven / Gradle / Ivy
package nextapp.echo.webcontainer;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionEvent;
/**
* Container / manager of all UserInstance objects in the servlet session.
*/
public class UserInstanceContainer
implements HttpSessionActivationListener, HttpSessionBindingListener, Serializable {
/**
* Creates a new Web Application Container instance using the provided
* client Connection
. The instance will automatically
* be stored in the relevant HttpSession
*
* @param conn the client/server Connection
for which the
* instance is being instantiated
*/
public static void newInstance(Connection conn) {
new UserInstanceContainer(conn);
}
/**
* Sequential UserInstance
identifier generator.
*/
private int nextUserInstanceId = 0;
/**
* Sequential initial request identifier generator.
*/
private int nextInitId = 0;
/**
* The default character encoding in which responses should be rendered.
*/
private String characterEncoding = "UTF-8";
/**
* The URI of the servlet.
*/
private String servletUri;
/**
* Mapping between client-generated unique browser window identifiers and UserInstance
values.
*/
private Map clientWindowIdToUserInstance = new HashMap();
/**
* Mapping between UserInstance
identifiers and UserInstance
values.
*/
private Map idToUserInstance = new HashMap();
/**
* Mapping between initial request identifiers (as returned by createInitId()
) and maps of initial
* requested parameters retrieved from HttpServletRequest.getParameterMap()
.
*/
private Map initIdToInitialRequestParameterMap = new HashMap();
/**
* The containing HttpSession
.
*/
private transient HttpSession session;
private boolean windowSpecificUserInstances;
/**
* Creates a new UserInstance
.
*
* @param conn the client/server Connection
for which the
* instance is being instantiated
*/
private UserInstanceContainer(Connection conn) {
super();
conn.initUserInstanceContainer(this);
windowSpecificUserInstances = conn.getServlet().getInstanceMode() == WebContainerServlet.INSTANCE_MODE_WINDOW;
}
/**
* Disposes of all contained UserInstance
s.
*/
private void dispose() {
Iterator it = idToUserInstance.values().iterator();
while (it.hasNext()) {
UserInstance userInstance = (UserInstance) it.next();
userInstance.dispose();
}
}
/**
* Creates an initial request identifier.
* Stores request parameters provided by the connection, such that they may be assigned to the
* later-generated UserInstance
if required.
*
* @param conn the Connection
* @return a unique initial request identifier
*/
public String createInitId(Connection conn) {
Map parameterMap = new HashMap(conn.getRequest().getParameterMap());
String initId = new Integer(nextInitId++).toString();
initIdToInitialRequestParameterMap.put(initId, parameterMap);
return initId;
}
/**
* Creates or retrieves a UserInstance
for the specified client window identifier and
* initial request identifier. Invoked when a window is loaded for the first time or reloaded.
*
* If a UserInstance
exists for the specified clientWindowId
, it is
* returned.
*
* If a UserInstance
does not exist for the specified clientWindowId
, one is
* created and stored within this UserInstanceContainer
. The initial request parameters are
* retrieved from the initialization-id-to-request-parameter-map and stored in the created
* UserInstance
.
*
* @param clientWindowId the client-generated unique browser window identifier
* @param initId the server-generated (by createInitId()
) unique initialization
* request identifier
* @return the existing or created UserInstance
*/
synchronized UserInstance loadUserInstance(String clientWindowId, String initId) {
if (!windowSpecificUserInstances) {
clientWindowId = null;
}
UserInstance userInstance = (UserInstance) clientWindowIdToUserInstance.get(clientWindowId);
if (userInstance == null) {
String uiid;
if (windowSpecificUserInstances) {
uiid = new Integer(nextUserInstanceId++).toString();
} else {
uiid = null;
}
Map initialRequestParameterMap = (Map) initIdToInitialRequestParameterMap.remove(initId);
userInstance = new UserInstance(this, uiid, clientWindowId, initialRequestParameterMap);
clientWindowIdToUserInstance.put(clientWindowId, userInstance);
idToUserInstance.put(userInstance.getId(), userInstance);
}
return userInstance;
}
/**
* Unloads a UserInstance
from the container.
* Disposes of the instance.
*
* @param userInstance the instance to unload
*/
synchronized void unloadUserInstance(UserInstance userInstance) {
userInstance.dispose();
clientWindowIdToUserInstance.remove(userInstance.getClientWindowId());
idToUserInstance.remove(userInstance.getId());
}
/**
* Retrieves an existing UserInstance
by its assigned user instance identifier.
*
* @param id the UserInstance
identifier, i.e., value which would be returned by
* the UserInstance
's getId()
method
* @return the UserInstnace
, or null if none exists
*/
synchronized UserInstance getUserInstanceById(String id) {
return (UserInstance) idToUserInstance.get(id);
}
/**
* Returns the default character encoding in which responses should be
* rendered.
*
* @return the default character encoding in which responses should be
* rendered
*/
public String getCharacterEncoding() {
return characterEncoding;
}
/**
* Returns the id of the HTML element that will serve as the Root component.
* This element must already be present in the DOM when the application is
* first rendered.
*
* @return the element id
*/
public String getRootHtmlElementId() {
return "approot";
}
/**
* Returns the HttpSession
containing this
* UserInstanceContainer
.
*
* @return the HttpSession
*/
HttpSession getSession() {
return session;
}
/**
* Determines the URI to invoke the specified Service
.
*
* @param service the Service
* @return the URI
*/
public String getServiceUri(Service service, String userInstanceId) {
StringBuffer out = new StringBuffer(getServletUri());
out.append("?");
out.append(WebContainerServlet.SERVICE_ID_PARAMETER);
out.append("=");
out.append(service.getId());
if (userInstanceId != null) {
out.append("&");
out.append(WebContainerServlet.USER_INSTANCE_ID_PARAMETER);
out.append("=");
out.append(userInstanceId);
}
return out.toString();
}
/**
* Determines the URI to invoke the specified Service
with
* additional request parameters. The additional parameters are provided by
* way of the parameterNames
and parameterValues
* arrays. The value of a parameter at a specific index in the
* parameterNames
array is provided in the
* parameterValues
array at the same index. The arrays must
* thus be of equal length. Null values are allowed in the
* parameterValues
array, and in such cases only the parameter
* name will be rendered in the returned URI.
*
* @param service the Service
* @param parameterNames the names of the additional URI parameters
* @param parameterValues the values of the additional URI parameters
* @return the URI
*/
public String getServiceUri(Service service, String userInstanceId, String[] parameterNames, String[] parameterValues) {
StringBuffer out = new StringBuffer(getServletUri());
out.append("?");
out.append(WebContainerServlet.SERVICE_ID_PARAMETER);
out.append("=");
out.append(service.getId());
if (userInstanceId != null) {
out.append("&");
out.append(WebContainerServlet.USER_INSTANCE_ID_PARAMETER);
out.append("=");
out.append(userInstanceId);
}
for (int i = 0; i < parameterNames.length; ++i) {
out.append("&");
out.append(parameterNames[i]);
if (parameterValues[i] != null) {
out.append("=");
out.append(parameterValues[i]);
}
}
return out.toString();
}
/**
* Returns the URI of the servlet managing this UserInstanceContainer
.
*
* @return the URI
*/
public String getServletUri() {
return servletUri;
}
/**
* Sets the URI of the containing servlet.
*
* @param servletUri the servlet URI
*/
void setServletUri(String servletUri) {
this.servletUri = servletUri;
}
/**
* @see javax.servlet.http.HttpSessionActivationListener#sessionDidActivate(javax.servlet.http.HttpSessionEvent)
*
* Recreates reference to session.
* Notifies ApplicationInstance
of activation.
*/
public synchronized void sessionDidActivate(HttpSessionEvent e) {
session = e.getSession();
Iterator it = idToUserInstance.values().iterator();
while (it.hasNext()) {
UserInstance userInstance = (UserInstance) it.next();
if (userInstance.getApplicationInstance() != null) {
userInstance.getApplicationInstance().activate();
}
}
}
/**
* @see javax.servlet.http.HttpSessionActivationListener#sessionWillPassivate(javax.servlet.http.HttpSessionEvent)
*
* Notifies ApplicationInstance
of passivation.
* Discards reference to session.
*/
public synchronized void sessionWillPassivate(HttpSessionEvent e) {
Iterator it = idToUserInstance.values().iterator();
while (it.hasNext()) {
UserInstance userInstance = (UserInstance) it.next();
if (userInstance.getApplicationInstance() != null) {
userInstance.getApplicationInstance().passivate();
}
}
session = null;
}
/**
* Listener implementation of HttpSessionBindingListener
.
* Stores reference to session when invoked.
*
* @see javax.servlet.http.HttpSessionBindingListener#valueBound(HttpSessionBindingEvent)
*/
public void valueBound(HttpSessionBindingEvent e) {
session = e.getSession();
}
/**
* Listener implementation of HttpSessionBindingListener
.
* Disposes ApplicationInstance
.
* Removes reference to session when invoked.
*
* @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent)
*/
public void valueUnbound(HttpSessionBindingEvent e) {
dispose();
session = null;
}
}