cleanSession(request);
return;
}
boolean locked = false;
MemcacheService memcache = null;
String mutex = MUTEX_BASE + session.getId();
memcache = MemcacheServiceFactory.getMemcacheService();
try {
// try to get lock
long started = new Date().getTime();
// non-UIDL requests will try indefinitely
while (requestType != RequestType.UIDL
|| new Date().getTime() - started < MAX_UIDL_WAIT_MILLISECONDS) {
locked = memcache.put(mutex, 1, Expiration.byDeltaSeconds(40),
MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT);
if (locked) {
break;
}
try {
Thread.sleep(RETRY_AFTER_MILLISECONDS);
} catch (InterruptedException e) {
logger.finer("Thread.sleep() interrupted while waiting for lock. Trying again. "
+ e);
}
}
if (!locked) {
// Not locked; only UIDL can get trough here unlocked: tell
// client to retry
response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
// Note: currently interpreting Retry-After as ms, not sec
response.setHeader("Retry-After", "" + RETRY_AFTER_MILLISECONDS);
return;
}
// de-serialize or create application context, store in session
ApplicationContext ctx = getApplicationContext(request, memcache);
super.service(request, response);
// serialize
started = new Date().getTime();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(ctx);
oos.flush();
byte[] bytes = baos.toByteArray();
started = new Date().getTime();
String id = AC_BASE + session.getId();
Date expire = new Date(started
+ (session.getMaxInactiveInterval() * 1000));
Expiration expires = Expiration.onDate(expire);
memcache.put(id, bytes, expires);
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
Entity entity = new Entity(AC_BASE, id);
entity.setProperty(PROPERTY_EXPIRES, expire.getTime());
entity.setProperty(PROPERTY_DATA, new Blob(bytes));
ds.put(entity);
} catch (DeadlineExceededException e) {
logger.warning("DeadlineExceeded for " + session.getId());
sendDeadlineExceededNotification(request, response);
} catch (NotSerializableException e) {
logger.log(Level.SEVERE, "Not serializable!", e);
// TODO this notification is usually not shown - should we redirect
// in some other way - can we?
sendNotSerializableNotification(request, response);
} catch (Exception e) {
logger.log(Level.WARNING,
"An exception occurred while servicing request.", e);
sendCriticalErrorNotification(request, response);
} finally {
// "Next, please!"
if (locked) {
memcache.delete(mutex);
}
cleanSession(request);
}
}