// All scripts destined for a page go to a ScriptSession and then out
// via a ScriptConduit.
final RealScriptSession scriptSession = (RealScriptSession) webContext.getScriptSession();
// So we're going to go to sleep. How do we wake up?
Sleeper sleeper = containerAbstraction.createSleeper(request);
// Create a conduit depending on the type of request (from the URL)
final BaseScriptConduit conduit = createScriptConduit(sleeper, batch, response);
// There are various reasons why we want to wake up and carry on ...
final List<Alarm> alarms = new ArrayList<Alarm>();
// If the conduit has an error flushing data, it needs to give up
alarms.add(conduit);
// Use of comet depends on the type of browser and the number of current
// connections from this browser (detected by cookies)
boolean clientSupportsLongRequests = BrowserDetect.supportsComet(request);
boolean clientSupportsStreamingUpdates = (batch.getPartialResponse() != PartialResponse.NO);
boolean configurationSaysFullStreaming = streamingEnabled || (maxWaitAfterWrite == -1);
boolean canWeHaveFullStreaming = clientSupportsLongRequests && clientSupportsStreamingUpdates && configurationSaysFullStreaming;
// For early closing mode add an output listener to the script session that calls the
// "wake me" method on whatever is putting us to sleep - if the client
// does not support streaming or streaming has not been configured.
if (!canWeHaveFullStreaming) {
int earlyCloseTimeout = (maxWaitAfterWrite == -1) ? ProtocolConstants.DEFAULT_MAX_WAIT_AFTER_WRITE : maxWaitAfterWrite;
alarms.add(new OutputAlarm(sleeper, scriptSession, earlyCloseTimeout, executor));
}
if (clientSupportsLongRequests)
{
// Nasty 2 connection limit hack. How many times is this browser connected?
String httpSessionId = webContext.getSession(true).getId();
Collection<ScriptSession> sessions = scriptSessionManager.getScriptSessionsByHttpSessionId(httpSessionId);
int persistentConnections = 0;
for (ScriptSession session : sessions)
{
persistentConnections += ((RealScriptSession) session).countPersistentConnections();
}
int connectionLimit = BrowserDetect.getConnectionLimit(request);
if (persistentConnections + 1 >= connectionLimit)
{
clientSupportsLongRequests = false;
if (log.isDebugEnabled())
{
String uaStr = BrowserDetect.getUserAgentDebugString(request);
log.debug("Persistent connections=" + persistentConnections + ". (limit=" + connectionLimit + " in " + uaStr + "). Polling");
}
}
}
else
{
log.debug("Browser does not support comet, polling");
}
// Set the system up to resume anyway after maxConnectedTime
ServerLoadMonitor slm = serverLoadMonitor;
long connectedTime = slm.getConnectedTime();
final int disconnectedTime = slm.getDisconnectedTime();
alarms.add(new TimedAlarm(sleeper, connectedTime, executor));
// We also need to wake-up if the server is being shut down
// WARNING: This code has a non-obvious side effect - The server load
// monitor (which hands out shutdown messages) also monitors usage by
// looking at the number of connected alarms.
alarms.add(new ShutdownAlarm(sleeper, serverLoadMonitor));
// Register the conduit with a script session so messages can get out.
// This must happen late on in this method because this will cause any
// scripts cached in the script session (because there was no conduit
// available when they were written) to be sent to the conduit.
// We need any AlarmScriptConduits to be notified so they can make
// maxWaitAfterWrite work for all cases
scriptSession.addScriptConduit(conduit);
// We need to do something sensible when we wake up ...
Runnable onAwakening = new Runnable()
{
public void run()
{
// Cancel all the alarms
for (Alarm alarm : alarms)
{
alarm.cancel();
}
// We can't be used as a conduit to the browser any more
scriptSession.removeScriptConduit(conduit);
// Tell the browser to come back at the right time
try
{
conduit.close(disconnectedTime);
}
catch (IOException ex)
{
log.warn("Failed to write reconnect info to browser");
}
}
};
// Actually go to sleep. This *must* be the last thing in this method to
// cope with all the methods of affecting Threads. Jetty throws,
// Weblogic continues, others wait().
sleeper.goToSleep(onAwakening);
}