Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 184479

Summary: InvalidThreadAccess when update model with entity open in Java editor
Product: [WebTools] Dali JPA Tools Reporter: Tom Mutdosch <mutdosch>
Component: GeneralAssignee: Brian Vosburgh <brian.vosburgh>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: cmjaun
Version: 1.0   
Target Milestone: ---   
Hardware: PC   
OS: Windows XP   
Whiteboard:

Description Tom Mutdosch CLA 2007-04-27 12:59:35 EDT
We have a wizard with an operation that sets the primary key on a selected
Entity:
IPersistentAttribute attribute = myAttribute;                          
attribute.setMappingKey(IMappingKeys.ID_ATTRIBUTE_MAPPING_KEY), false);

If I have that entity open in the Java editor, I get an Invalid Thread Access exception.  If the Java editor is not open, I do not get that error.  Could this be handled in the Annotation editing code to make sure that it happens on the appropriate thread?

!MESSAGE Extended Operation failure: my.package.JpaOperation
!STACK 0
org.eclipse.swt.SWTException: Invalid thread access
	at org.eclipse.swt.SWT.error(SWT.java:3534)
	at org.eclipse.swt.SWT.error(SWT.java:3457)
	at org.eclipse.swt.SWT.error(SWT.java:3428)
	at org.eclipse.swt.widgets.Widget.error(Widget.java:432)
	at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:326)
	at org.eclipse.swt.custom.StyledText.getLinePixel(StyledText.java:3649)
	at org.eclipse.swt.custom.StyledText.handleTextChanging(StyledText.java:5330)
	at org.eclipse.swt.custom.StyledText$6.textChanging(StyledText.java:4772)
	at org.eclipse.jface.text.DefaultDocumentAdapter.fireTextChanging(DefaultDocumentAdapter.java:392)
	at org.eclipse.jface.text.DefaultDocumentAdapter.documentAboutToBeChanged(DefaultDocumentAdapter.java:309)
	at org.eclipse.jface.text.AbstractDocument.fireDocumentAboutToBeChanged(AbstractDocument.java:602)
	at org.eclipse.jface.text.projection.ProjectionDocument.delayedFireDocumentAboutToBeChanged(ProjectionDocument.java:758)
	at org.eclipse.jface.text.projection.ProjectionDocument.masterDocumentAboutToBeChanged(ProjectionDocument.java:717)
	at org.eclipse.jface.text.projection.ProjectionDocumentManager.fireDocumentEvent(ProjectionDocumentManager.java:121)
	at org.eclipse.jface.text.projection.ProjectionDocumentManager.documentAboutToBeChanged(ProjectionDocumentManager.java:138)
	at org.eclipse.jface.text.AbstractDocument.fireDocumentAboutToBeChanged(AbstractDocument.java:606)
	at org.eclipse.jface.text.AbstractDocument.replace(AbstractDocument.java:1072)
	at org.eclipse.core.internal.filebuffers.SynchronizableDocument.replace(SynchronizableDocument.java:151)
	at org.eclipse.jface.text.AbstractDocument.replace(AbstractDocument.java:1091)
	at org.eclipse.core.internal.filebuffers.SynchronizableDocument.replace(SynchronizableDocument.java:137)
	at org.eclipse.text.edits.InsertEdit.performDocumentUpdating(InsertEdit.java:81)
	at org.eclipse.text.edits.TextEdit.traverseDocumentUpdating(TextEdit.java:896)
	at org.eclipse.text.edits.TextEdit.traverseDocumentUpdating(TextEdit.java:889)
	at org.eclipse.text.edits.TextEditProcessor.executeDo(TextEditProcessor.java:186)
	at org.eclipse.text.edits.TextEdit.dispatchPerformEdits(TextEdit.java:736)
	at org.eclipse.text.edits.TextEditProcessor.performEdits(TextEditProcessor.java:154)
	at org.eclipse.text.edits.TextEdit.apply(TextEdit.java:708)
	at org.eclipse.jpa.core.internal.jdtutility.AnnotationEditFormatter.apply(AnnotationEditFormatter.java:36)
	at org.eclipse.jpa.core.internal.jdtutility.Member.edit_(Member.java:369)
	at org.eclipse.jpa.core.internal.jdtutility.Member.edit(Member.java:332)
	at org.eclipse.jpa.core.internal.jdtutility.Member.newMarkerAnnotation(Member.java:211)
	at org.eclipse.jpa.core.internal.content.java.JavaPersistentAttribute.setSpecifiedMapping(JavaPersistentAttribute.java:317)
	at org.eclipse.jpa.core.internal.content.java.JavaPersistentAttribute.setMappingKey(JavaPersistentAttribute.java:341)
	at my.package.EntityAnnotationOperation.execute(EntityAnnotationOperation.java:26)
Comment 1 Neil Hauge CLA 2007-05-17 16:55:49 EDT
Brian, can you take a look at this.
Comment 2 Tom Mutdosch CLA 2007-05-18 08:25:46 EDT
Just a bit more background - we are using the IDataModel framework from our own wizard, and in our operation we are modifying the JPA model objects (such as adding INamedQuery's to the IEntity, etc).  This operation runs in the background (not in the UI thread).  We often run our operation when the Entity java file is not even open - maybe there's a way for the AnnotationEditFormatter to not call all of the UI listeners if not running in the UI thread.

Here's another truncated stacktrace that shows the same scenario when we make a call to: (INamedQuery)query).setName( "foo");

org.eclipse.swt.SWTException: Invalid thread access
	at org.eclipse.swt.SWT.error(SWT.java:3547)
	at org.eclipse.swt.SWT.error(SWT.java:3465)
	at org.eclipse.swt.SWT.error(SWT.java:3436)
	at org.eclipse.swt.widgets.Widget.error(Widget.java:432)
	at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:326)
	at org.eclipse.swt.custom.StyledText.getLinePixel(StyledText.java:3649)
	at org.eclipse.swt.custom.StyledText.handleTextChanging(StyledText.java:5330)
	. . .	at org.eclipse.jpt.core.internal.JpaEObject.eNotify(JpaEObject.java:73)
	at org.eclipse.jpt.core.internal.content.java.mappings.JavaAbstractQuery.setName(JavaAbstractQuery.java:244)
. . . org.eclipse.wst.common.frameworks.internal.datamodel.DataModelPausibleOperationImpl$1.run(DataModelPausibleOperationImpl.java:376)
	at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:1797)
Comment 3 Tom Mutdosch CLA 2007-06-13 14:03:25 EDT
Hi there,

Do you know how difficult this one will be to fix?  Currently we have added a bunch of Display.syncExec blocks to wrap all of our various Dali model access in our code.  This probably isn't the best solution especially since we are running as a non-UI operation, but I don't know a better way at the moment.
Comment 4 Brian Vosburgh CLA 2007-07-25 17:09:22 EDT
I added API to IJpaProject that will allow clients to set a ThreadLocal CommandExecutor: IJpaProject#setThreadLocalModifySharedDocumentCommandExecutor(CommandExecutor commandExecutor). When updating a model in a non-UI thread you will need to set this CommandExecutor to one that will execute the command on the UI thread:
project.setThreadLocalModifySharedDocumentCommandExecutor(SynchronousUiCommandExecutor.instance()). Then any model object in the project can be modified and, if its currently visible in an editor, it will notify its listeners on the UI thread.
Comment 5 Tom Mutdosch CLA 2007-11-14 14:51:08 EST
Hi Brian,

This mechanism seems to work fine, thanks.  After my code sets the Executor and updates the Dali model, afterwards is it my responsibility to again call setThreadLocalModifySharedDocumentCommandExecutor() and set it back to the original executor? 
Comment 6 Brian Vosburgh CLA 2007-11-14 18:43:34 EST
Hi, Tom.

Glad to hear this works for you.

In response to Comment 5: No, you do not need to reset the executor. It is stored in a ThreadLocal, affects only the code running in the Thread that set it originally, and will be garbage-collected when the Thread is finished and garbage-collected.
Comment 7 Tom Mutdosch CLA 2007-11-15 07:49:12 EST
Very cool - thanks!