0

Constraint.validate() event thread bug

asked 2010-01-27 13:05:08 +0800

dastultz gravatar image dastultz
797 9

Hello,

I have an "EventThreadListener" that implements EventThreadCleanup, EventThreadSuspend, EventThreadInit, EventThreadResume. EventThreadCleanup.cleanup() and EventThreadSuspend.beforeSuspend() release a database connection that is on a ThreadLocal variable. I have a Textbox with a Constraint added to it. Constraint.validate(...) gets a database connection and runs a query. The connection is not being released, which is to say the cleanup routine is not being called on the thread that is active during Constraint.validate(...). I've added debugging to my EventThreadListener. When I enter something in the textbox and trigger the validation routine I get this in the log:

DEBUG 01/27 13:25:23 : EventThreadInit.prepare() - on http-8080-2
DEBUG 01/27 13:25:23 : EventThreadInit.init() - on Thread-33
DEBUG 01/27 13:25:23 : EventThreadCleanup.cleanup() - on Thread-33
DEBUG 01/27 13:25:23 : EventThreadCleanup.complete() - on http-8080-2
DEBUG 01/27 13:25:23 : EventThreadInit.prepare() - on http-8080-2
DEBUG 01/27 13:25:23 : EventThreadInit.init() - on Thread-33
DEBUG 01/27 13:25:23 : EventThreadCleanup.cleanup() - on Thread-33
DEBUG 01/27 13:25:23 : EventThreadCleanup.complete() - on http-8080-2
DEBUG 01/27 13:25:23 : Constraint.validate() on http-8080-2

The event threads usually have a name like "Thread-##". Here is appears Constraint.validate() is being run on the http request thread rather than an event thread. This looks like a bug to me. (It also looks odd that Constraint.validate() is called after completion of the event thread.) Is this expected behavior? Should I also be cleaning up my database connection on EventThreadCleanup.complete() since this appears to run on the http request thread?

/Daryl

delete flag offensive retag edit

16 Replies

Sort by ยป oldest newest

answered 2010-01-27 13:18:04 +0800

dastultz gravatar image dastultz
797 9

Oh, yeah, I'm using 3.6.3FL

/Daryl

link publish delete flag offensive edit

answered 2010-01-31 21:21:04 +0800

tmillsclare gravatar image tmillsclare
799 2 5 30

Hey dastultz,

Firstly ZK 3.6.3 final version has been released so can you upgrade to that and then see whether that fixes your issue. If not, I will take a look, would it be possible to provide me with quick a quick sample (I know it is database, I can set one up here)?

Thanks,
Tim

link publish delete flag offensive edit

answered 2010-02-01 11:31:14 +0800

dastultz gravatar image dastultz
797 9

I've upgraded to 3.6.3 final. The behavior is the same. There is no database required to demonstrate this, but I don't know if/how to do it in ZUL.

Here is my Event Listener (just logging):



public class EventThreadListener implements org.zkoss.zk.ui.event.EventThreadCleanup, org.zkoss.zk.ui.event.EventThreadSuspend,
org.zkoss.zk.ui.event.EventThreadInit, org.zkoss.zk.ui.event.EventThreadResume {

	// EventThreadCleanup
	@SuppressWarnings("unchecked")
	public void cleanup(Component component, Event event, List list) throws Exception {
		Logger logger2 = Hierarchy.getDefaultHierarchy().getLoggerFor("6d.util");
		if (logger2.isDebugEnabled()) {
			logger2.debug("EventThreadCleanup.cleanup() - on " + Thread.currentThread().getName());
		}
		freeResources();
	}

	public void complete(Component component, Event event) throws Exception {
		Logger logger2 = Hierarchy.getDefaultHierarchy().getLoggerFor("6d.util");
		if (logger2.isDebugEnabled()) {
			logger2.debug("EventThreadCleanup.complete() - on " + Thread.currentThread().getName());
		}
	}

	// EventThreadSuspend
	public void beforeSuspend(Component component, Event event, Object arg) throws Exception {
		Logger logger2 = Hierarchy.getDefaultHierarchy().getLoggerFor("6d.util");
		if (logger2.isDebugEnabled()) {
			logger2.debug("EventThreadSuspend.beforeSuspend() - on " + Thread.currentThread().getName());
		}
		freeResources();
	}

	public void afterSuspend(Component component, Event event) throws Exception {
		Logger logger2 = Hierarchy.getDefaultHierarchy().getLoggerFor("6d.util");
		if (logger2.isDebugEnabled()) {
			logger2.debug("EventThreadSuspend.afterSuspend() - on " + Thread.currentThread().getName());
		}
	}

	private void freeResources() {
		... close database connection
	}

	public boolean init(Component comp, Event event) throws Exception {
		Logger logger2 = Hierarchy.getDefaultHierarchy().getLoggerFor("6d.util");
		if (logger2.isDebugEnabled()) {
			logger2.debug("EventThreadInit.init() - on " + Thread.currentThread().getName());
		}
		return true;
	}

	public void prepare(Component comp, Event event) throws Exception {
		Logger logger2 = Hierarchy.getDefaultHierarchy().getLoggerFor("6d.util");
		if (logger2.isDebugEnabled()) {
			logger2.debug("EventThreadInit.prepare() - on " + Thread.currentThread().getName());
		}
	}

	public void abortResume(Component comp, Event evt) throws Exception {
		Logger logger2 = Hierarchy.getDefaultHierarchy().getLoggerFor("6d.util");
		if (logger2.isDebugEnabled()) {
			logger2.debug("EventThreadResume.abortResume() - on " + Thread.currentThread().getName());
		}
	}

	public void afterResume(Component comp, Event evt) throws Exception {
		Logger logger2 = Hierarchy.getDefaultHierarchy().getLoggerFor("6d.util");
		if (logger2.isDebugEnabled()) {
			logger2.debug("EventThreadResume.afterResume() - on " + Thread.currentThread().getName());
		}
	}

	public void beforeResume(Component comp, Event evt) throws Exception {
		Logger logger2 = Hierarchy.getDefaultHierarchy().getLoggerFor("6d.util");
		if (logger2.isDebugEnabled()) {
			logger2.debug("EventThreadResume.beforeResume() - on " + Thread.currentThread().getName());
		}
	}
}

And here is the code with the constraint:

	Textbox textbox = new Textbox();
	textbox.setConstraint(new Constraint() {
		public void validate(Component comp, Object value) throws WrongValueException {
			Logger logger2 = Hierarchy.getDefaultHierarchy().getLoggerFor("6d.util");
			if (logger2.isDebugEnabled()) {
				logger2.debug("Constraint.validate() on " + Thread.currentThread().getName());
			}
		}
	}

/Daryl

link publish delete flag offensive edit

answered 2010-02-05 21:10:00 +0800

tmillsclare gravatar image tmillsclare
799 2 5 30

updated 2010-02-05 21:16:26 +0800

Hey Dastultz,

I have investigated your problem and can reveal that the execution cycle is indeed correct.

In a general cycle, ZK receives the validate command and then issues an uses the EventThread to take care of the processing and return the result.

There is an easy way for you to handle this by implementing ExecutionInit and ExecutionCleanup. These operate either side of commands. However, they are run before and after any commands, so if you click a button and check then validate you get the following output:

EventCycleCleanup.init() - on http-8080-2
Constraint.validate() on http-8080-2
Button.onClick() on Thread-13
EventCycleCleanup.cleanup() - on http-8080-2

or

EventCycleCleanup.init() - on http-8080-2
Constraint.validate() on http-8080-2
EventCycleCleanup.cleanup() - on http-8080-2

EventCycleCleanup.init() - on http-8080-2
Button.onClick() on Thread-13
EventCycleCleanup.cleanup() - on http-8080-2

The second only happens when something delays one of the calls, eg. debugging. What I would recommend is you get your data connection in the validate method, perform the validation and then clean it up in the cleanup() method if it is open.

I hope this helps and please let me know if you have any other questions.

link publish delete flag offensive edit

answered 2010-02-08 10:26:31 +0800

dastultz gravatar image dastultz
797 9

I think I see what you are saying, but some of the text doesn't seem right. You said:

>In a general cycle, ZK receives the validate command and then issues an uses the EventThread to take care of the processing and return the result.

but I think the test case shows that it is not running on an Event Thread.

I'm using 3.6.3. Is EventCycleCleanup a Zk5 thing? My example implements EventThreadCleanup. I am closing the database connection in EventThreadCleanup.cleanup() and EventThreadSuspend.beforeSuspend(). It seems if I also close the connection in EventThreadCleanup.complete() that will take care of things. Is this correct?

Thanks.

/Daryl

link publish delete flag offensive edit

answered 2010-02-08 20:23:28 +0800

tmillsclare gravatar image tmillsclare
799 2 5 30

Hey Daryl,

The original received validate command is HTTP then the processing is done in the EventThread.

Sorry, EventCycleCleanup is my implementation of the two interfaces, ExecutionInit and ExecutionCleanup. Both interfaces are available in ZK 3.6.3. You can therefore use these to handle the Constraint.validate() event as these interfaces both operate on the same thread. Hence you can open your connection on validate and then close the connection if it is open on "ExecutionCleanup."

I hope this helps!

link publish delete flag offensive edit

answered 2010-02-09 07:31:30 +0800

dastultz gravatar image dastultz
797 9

> The original received validate command is HTTP then the processing is done in the EventThread.

Ok, I'll add cleanup code to EventThreadCleanup.complete(), thanks.

/Daryl

link publish delete flag offensive edit

answered 2010-02-12 08:15:49 +0800

dastultz gravatar image dastultz
797 9

Well, I thought that would work, but it doesn't. Here's my current log of happenings:

DEBUG 02/12 09:11:00 : EventThreadInit.prepare() - on http-8080-4
DEBUG 02/12 09:11:00 : EventThreadInit.init() - on Thread-65
DEBUG 02/12 09:11:00 : EventThreadCleanup.cleanup() - on Thread-65
DEBUG 02/12 09:11:00 : EventThreadCleanup.complete() - on http-8080-4
DEBUG 02/12 09:11:00 : EventThreadInit.prepare() - on http-8080-4
DEBUG 02/12 09:11:00 : EventThreadInit.init() - on Thread-65
DEBUG 02/12 09:11:00 : EventThreadCleanup.cleanup() - on Thread-65
DEBUG 02/12 09:11:00 : EventThreadCleanup.complete() - on http-8080-4
DEBUG 02/12 09:11:00 : Constraint.validate() on http-8080-4

EventThreadCleanup.complete() is called BEFORE Constraint.validate(), thus missing the opportunity to close the database connection. This certainly has to be a bug as EventThreadCleanup can't do what it's supposed to be able to do. Unless there's another interface I could implement to clean up the main thread after Constraint.validate()?

/Daryl

link publish delete flag offensive edit

answered 2010-02-22 19:34:54 +0800

tmillsclare gravatar image tmillsclare
799 2 5 30

Hey Daryl,

Here are some steps:

1. Implement the interface ExecutionCleanup. Let's name the implementing class "CycleCleanup"
2. Get your db connection in the Validate routine and make sure the data is valid
3. In CycleCleanup's clean up routine implement your cleanup code, checking to see whether the db connection is active and if it is release the resource

This should now work.

link publish delete flag offensive edit

answered 2010-03-01 12:12:08 +0800

dastultz gravatar image dastultz
797 9

I've done as you say, and if I simply TAB off the textbox it works as expected and I get this logging:

DEBUG 03/01 12:51:36 : Constraint.validate() on http-8080-1
DEBUG 03/01 12:51:36 : ConnectionResource.get() conn ...Connection@392cf455 on http-8080-1
DEBUG 03/01 12:51:36 : Constraint.validate() got connection ...Connection@392cf455
DEBUG 03/01 12:51:36 : Constraint.validate() exiting
DEBUG 03/01 12:51:36 : ExecutionCleanup.cleanup() - on http-8080-1
DEBUG 03/01 12:51:36 : ConnectionResource.cleanUp() - connectionRetrieved = true
DEBUG 03/01 12:51:36 : ConnectionResource.cleanUp() - removing from http-8080-1

The second line shows the connection being retrieved. The second to last shows that the ThreadLocal variable knows the connection was retrieved and it is closed (not shown). But if instead of TABBING off the field, I click the Save button, I get a different set of log entries and it fails:

DEBUG 03/01 12:49:06 : Constraint.validate() on http-8080-1
DEBUG 03/01 12:49:06 : ConnectionResource.get() conn ...Connection@393d701a on http-8080-1
DEBUG 03/01 12:49:06 : Constraint.validate() got connection ...Connection@393d701a
DEBUG 03/01 12:49:06 : Constraint.validate() exiting
DEBUG 03/01 12:49:06 : EventThreadInit.prepare() - on http-8080-1

DEBUG 03/01 12:49:06 : EventThreadInit.init() - on Thread-33
DEBUG 03/01 12:49:06 : EventThreadCleanup.cleanup() - on Thread-33
DEBUG 03/01 12:49:06 : ConnectionResource.cleanUp() - connectionRetrieved = true
DEBUG 03/01 12:49:06 : ConnectionResource.get() conn ...Connection@5a3bb53f on Thread-33
DEBUG 03/01 12:49:06 : ConnectionResource.cleanUp() - removing from Thread-33

DEBUG 03/01 12:49:06 : EventThreadCleanup.complete() - on http-8080-1
DEBUG 03/01 12:49:06 : ConnectionResource.cleanUp() - connectionRetrieved = false
DEBUG 03/01 12:49:06 : ConnectionResource.cleanUp() - removing from http-8080-1

DEBUG 03/01 12:49:06 : ExecutionCleanup.cleanup() - on http-8080-1
DEBUG 03/01 12:49:06 : ConnectionResource.cleanUp() - connectionRetrieved = false
DEBUG 03/01 12:49:06 : ConnectionResource.cleanUp() - removing from http-8080-1

Again, the second line shows the connection being retrieved and the constraint runs. Then Thread-33 is spun up presumably to handle the Save click. On the third line of the "second paragraph" it appears as though Thread-33 has retrieved a connection, though there is no corresponding retrieval line. I then expected the third line of the third paragraph to show that the connection had been retrieved on http-8080-1, but it doesn't show this. It appears as though the state of my ThreadLocal jumped from one thread to the other. Since it doesn't think the connection was ever retrieved, it doesn't try to close it.

Do you have any insight as to what may be going on here?

Thanks.

/Daryl

link publish delete flag offensive edit
Your reply
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow

RSS

Stats

Asked: 2010-01-27 13:05:08 +0800

Seen: 816 times

Last updated: Mar 12 '10

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More