You seem to have some more fundamental database design and software architecture issues here.
Instead of setting some "expired" field after a certain amount of time, just store the actual expiration time. Then, when the user performs an action, just check the expiration time against the current time to see if the invite is expired. That way, it always works, and you don't have to schedule timers or manage long-running transactions or anything like that. It's also implicitly persistent across program restarts / crashes (current timer-based approach will require effort to prevent it from forgetting to expire pending invites if the program is terminated while a timer is running).
If you want to have live notifications of expiration happening, add a "user has been notified" field (for example) to the invite. Then create a single repeating background task (a timer could be good for this, or a ScheduledExecutorService
) that periodically grabs a list of all expired non-notified invites in a single criteria query. Fire off the notifications, set the notified flags, rinse, repeat. You can queue notifications in a thread pool ExecutorService
if you'd like, if the notifications are time consuming (e.g. sending emails).
Closures (or approximations thereof) aren't quite the right tool for this job.
But, if you must do the timed flag thing, set hibernate to session-object-per-thread mode (actually, I think that might even be the default mode), then use a thread pool ExecutorService (see Executors) to schedule a task that opens transaction, queries invite, waits (no timer), then does it's thing and closes the transaction. Then your whole transaction is on one background thread, and none of the weird transaction management issues you're running into exist any more.
Even better, stop trying to all of this in a single long running transaction (for example, what if the user wants to delete the invite while your timer is running?). Open a transaction then query the invite then close it. Then set your timer (or use a ScheduledExecutorService
) and have the timer open a transaction, query the invite, expire the invite, then close it. You probably don't want to hold a db connection and/or transaction open for the entire interval MAX_TIME
, there's no reason to do that.
As for the final thing, nonfinal variables cannot be referred to in anonymous inner classes because you can't always guarantee that their values won't change before the anonymous class code is run (the compiler doesn't, and usually can't, go through the trouble of analyzing how the anonymous class is used to make that guarantee). So it requires final
.
Just declare invite final:
final Invite invite = ...;
And you can use it in your anonymous class.
A hint of under-the-hood explanation can be found here.
And yes you can modify fields of invite
still. You just can't assign invite to a new object. But like I said, your approach is funky and so you are running into issues.
I'm on my phone or I'd dig up the relevant portion of the JLS for the final stuff. You can look it up there for more info.