Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » e(fx)clipse » EMF Edit and the FX Application Thread(How to avoid IllegalStateExceptions ?)
EMF Edit and the FX Application Thread [message #1690498] Fri, 27 March 2015 16:01 Go to next message
Thomas Elskens is currently offline Thomas ElskensFriend
Messages: 159
Registered: September 2014
Location: Brussels - Belgium
Senior Member
Hello,

I have an EMF Resource the contents from which is displayed in a ListView by means of an Adapterfactory, as follows :

@FXML
private void initialize() 
{
	domain = domainManager.getEditingDomain();
	adapterFactory.addAdapterFactory(new EmployerItemProviderAdapterFactory());
		
	try 
        {
		domain.runExclusive(() -> 
                {
			EClass clazz = IEmployerPackage.eINSTANCE.getEmployer();
			lv_masterItems.setItems(new AdapterFactoryObservableList<Object>(adapterFactory, domainManager.getResource(clazz))) ;
		});
	} 
        catch (InterruptedException e) 
        {
	        logger.error("Unable to retrieve EmployerResource", e);		
	}


The contents of the EMF Resource is managed outside the UI, in an OSGI Service. This service, at every startup of the program, fetches some remote data and adds it to the resource :

private void addToResource(List<EObject> newValues, Resource resource)
	{
		Map<String,Boolean> options = new HashMap<>() ;
		options.put(Transaction.OPTION_NO_UNDO, Boolean.TRUE) ;
		options.put(Transaction.OPTION_NO_VALIDATION, Boolean.TRUE) ; // data from server are supposed being correct
		try
		{
			stack.execute(new RecordingCommand(domain)
			{
				@Override
				protected void doExecute()
				{					
					resource.getContents().addAll(newValues) ;
				}			
			}, options) ;
		}
		catch (InterruptedException | RollbackException e)
		{
			logger.error(String.format("Unable to add remote data to local resource %s", resource.toString()), e);
		}
	}


Up till now, nothing special I presume. It happens quite often, however, that Eclipse throws an IllegalStateException while loading the UI, with the following stack :

Quote:

Exception in thread "Worker-0" java.lang.IllegalStateException: Not on FX application thread; currentThread = Worker-0
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(Unknown Source)
at javafx.scene.Parent$2.onProposedChange(Unknown Source)
at com.sun.javafx.collections.VetoableListDecorator.setAll(Unknown Source)
at com.sun.javafx.collections.VetoableListDecorator.setAll(Unknown Source)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(Unknown Source)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.<init>(Unknown Source)
at com.sun.javafx.scene.control.skin.CellSkinBase.<init>(Unknown Source)
at com.sun.javafx.scene.control.skin.ListCellSkin.<init>(Unknown Source)
at javafx.scene.control.ListCell.createDefaultSkin(Unknown Source)
at javafx.scene.control.Control.impl_processCSS(Unknown Source)
at javafx.scene.Node.processCSS(Unknown Source)
at javafx.scene.Node.applyCss(Unknown Source)
at org.eclipse.fx.emf.edit.ui.AdapterFactoryCellFactory.resetPropertyState(AdapterFactoryCellFactory.java:387)
at org.eclipse.fx.emf.edit.ui.AdapterFactoryCellFactory.applyItemProviderColor(AdapterFactoryCellFactory.java:431)
at org.eclipse.fx.emf.edit.ui.AdapterFactoryCellFactory.applyItemProviderStyle(AdapterFactoryCellFactory.java:230)
at org.eclipse.fx.emf.edit.ui.AdapterFactoryListCellFactory$1.update(AdapterFactoryListCellFactory.java:118)
at org.eclipse.fx.emf.edit.ui.AdapterFactoryListCellFactory$1.updateItem(AdapterFactoryListCellFactory.java:91)
at javafx.scene.control.ListCell.updateItem(Unknown Source)
at javafx.scene.control.ListCell.lambda$new$163(Unknown Source)
at javafx.scene.control.ListCell$$Lambda$384/346157750.onChanged(Unknown Source)
at javafx.collections.WeakListChangeListener.onChanged(Unknown Source)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(Unknown Source)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(Unknown Source)
at javafx.collections.ObservableListBase.fireChange(Unknown Source)
at javafx.collections.ListChangeBuilder.commit(Unknown Source)
at javafx.collections.ListChangeBuilder.endChange(Unknown Source)
at javafx.collections.ObservableListBase.endChange(Unknown Source)
at javafx.collections.ModifiableObservableListBase.setAll(Unknown Source)
at org.eclipse.fx.emf.edit.ui.AdapterFactoryObservableList$1.notifyChanged(AdapterFactoryObservableList.java:88)
at org.eclipse.emf.common.notify.impl.BasicNotifierImpl.eNotify(BasicNotifierImpl.java:374)
at org.eclipse.emf.common.notify.impl.NotifyingListImpl.dispatchNotification(NotifyingListImpl.java:261)
at org.eclipse.emf.common.notify.impl.NotifyingListImpl.addAllUnique(NotifyingListImpl.java:457)
at org.eclipse.emf.common.notify.impl.NotifyingListImpl.addAllUnique(NotifyingListImpl.java:400)
at org.eclipse.emf.common.util.AbstractEList.addAll(AbstractEList.java:370)
at internal.DomainManagerImpl$1.doExecute(DomainManagerImpl.java:143)
at org.eclipse.emf.transaction.RecordingCommand.execute(RecordingCommand.java:135)
at org.eclipse.emf.common.command.BasicCommandStack.execute(BasicCommandStack.java:78)
at org.eclipse.emf.transaction.impl.AbstractTransactionalCommandStack.basicExecute(AbstractTransactionalCommandStack.java:241)
at org.eclipse.emf.transaction.impl.TransactionalCommandStackImpl.doExecute(TransactionalCommandStackImpl.java:63)
at org.eclipse.emf.transaction.impl.AbstractTransactionalCommandStack.execute(AbstractTransactionalCommandStack.java:165)
at internal.DomainManagerImpl.addToResource(DomainManagerImpl.java:138)
at internal.DomainManagerImpl.requestData(DomainManagerImpl.java:114)
at parts.master.Master.lambda$0(Master.java:57)
at parts.master.Master$$Lambda$275/361758860.run(Unknown Source)
at org.eclipse.core.runtime.jobs.Job$1.run(Job.java:159)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)


This make me wondering if I should use an UISynchronize for every operation on a UI control that fetches its data from an EMF-Adapterfactory? Isn't there an easier (and less error prone) solution ?

Any best practices in this regard ?

Thomas Elskens
Re: EMF Edit and the FX Application Thread [message #1690625 is a reply to message #1690498] Mon, 30 March 2015 07:32 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas SchindlFriend
Messages: 6651
Registered: July 2009
Senior Member
Hi,

First of both frameworks (EMF, JavaFX) are not thread-safe so you need
to make sure that only one thread is modifying them at a time so I think
if you do things in different threads you'd have something like
Eclipse-Databinding-Realm-System who defines on each observable on which
thread is has to be synced.

We currently don't have support for that in place, feel free to file a
feature-request but I'm afraid without funding we won't be able to
implement this until 2.0.

Tom

On 27.03.15 17:01, Thomas Elskens wrote:
> Hello,
>
> I have an EMF Resource the contents from which is displayed in a
> ListView by means of an Adapterfactory, as follows :
>
>
> @FXML
> private void initialize() {
> domain = domainManager.getEditingDomain();
> adapterFactory.addAdapterFactory(new
> EmployerItemProviderAdapterFactory());
>
> try {
> domain.runExclusive(() -> {
> EClass clazz = IEmployerPackage.eINSTANCE.getEmployer();
> lv_masterItems.setItems(new
> AdapterFactoryObservableList<Object>(adapterFactory,
> domainManager.getResource(clazz))) ;
> });
> } catch (InterruptedException e) {
> logger.error("Unable to retrieve EmployerResource", e);
> }
>
>
> The contents of the EMF Resource is managed outside the UI, in an OSGI
> Service. This service, at every startup of the program, fetches some
> remote data and adds it to the resource :
>
>
> private void addToResource(List<EObject> newValues, Resource resource)
> {
> Map<String,Boolean> options = new HashMap<>() ;
> options.put(Transaction.OPTION_NO_UNDO, Boolean.TRUE) ;
> options.put(Transaction.OPTION_NO_VALIDATION, Boolean.TRUE) ; //
> data from server are supposed being correct
> try
> {
> stack.execute(new RecordingCommand(domain)
> {
> @Override
> protected void doExecute()
> {
> resource.getContents().addAll(newValues) ;
> }
> }, options) ;
> }
> catch (InterruptedException | RollbackException e)
> {
> logger.error(String.format("Unable to add remote data to
> local resource %s", resource.toString()), e);
> }
> }
>
>
> Up till now, nothing special I presume. It happens quite often, however,
> that Eclipse throws an IllegalStateException while loading the UI, with
> the following stack :
>
> Quote:
>> Exception in thread "Worker-0" java.lang.IllegalStateException: Not on
>> FX application thread; currentThread = Worker-0
>> at com.sun.javafx.tk.Toolkit.checkFxUserThread(Unknown Source)
>> at
>> com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(Unknown
>> Source)
>> at javafx.scene.Parent$2.onProposedChange(Unknown Source)
>> at com.sun.javafx.collections.VetoableListDecorator.setAll(Unknown
>> Source)
>> at com.sun.javafx.collections.VetoableListDecorator.setAll(Unknown
>> Source)
>> at
>> com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(Unknown
>> Source)
>> at
>> com.sun.javafx.scene.control.skin.LabeledSkinBase.<init>(Unknown Source)
>> at com.sun.javafx.scene.control.skin.CellSkinBase.<init>(Unknown
>> Source)
>> at com.sun.javafx.scene.control.skin.ListCellSkin.<init>(Unknown
>> Source)
>> at javafx.scene.control.ListCell.createDefaultSkin(Unknown Source)
>> at javafx.scene.control.Control.impl_processCSS(Unknown Source)
>> at javafx.scene.Node.processCSS(Unknown Source)
>> at javafx.scene.Node.applyCss(Unknown Source)
>> at
>> org.eclipse.fx.emf.edit.ui.AdapterFactoryCellFactory.resetPropertyState(AdapterFactoryCellFactory.java:387)
>>
>> at
>> org.eclipse.fx.emf.edit.ui.AdapterFactoryCellFactory.applyItemProviderColor(AdapterFactoryCellFactory.java:431)
>>
>> at
>> org.eclipse.fx.emf.edit.ui.AdapterFactoryCellFactory.applyItemProviderStyle(AdapterFactoryCellFactory.java:230)
>>
>> at
>> org.eclipse.fx.emf.edit.ui.AdapterFactoryListCellFactory$1.update(AdapterFactoryListCellFactory.java:118)
>>
>> at
>> org.eclipse.fx.emf.edit.ui.AdapterFactoryListCellFactory$1.updateItem(AdapterFactoryListCellFactory.java:91)
>>
>> at javafx.scene.control.ListCell.updateItem(Unknown Source)
>> at javafx.scene.control.ListCell.lambda$new$163(Unknown Source)
>> at
>> javafx.scene.control.ListCell$$Lambda$384/346157750.onChanged(Unknown
>> Source)
>> at javafx.collections.WeakListChangeListener.onChanged(Unknown
>> Source)
>> at
>> com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(Unknown
>> Source)
>> at
>> com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(Unknown
>> Source)
>> at javafx.collections.ObservableListBase.fireChange(Unknown Source)
>> at javafx.collections.ListChangeBuilder.commit(Unknown Source)
>> at javafx.collections.ListChangeBuilder.endChange(Unknown Source)
>> at javafx.collections.ObservableListBase.endChange(Unknown Source)
>> at javafx.collections.ModifiableObservableListBase.setAll(Unknown
>> Source)
>> at
>> org.eclipse.fx.emf.edit.ui.AdapterFactoryObservableList$1.notifyChanged(AdapterFactoryObservableList.java:88)
>>
>> at
>> org.eclipse.emf.common.notify.impl.BasicNotifierImpl.eNotify(BasicNotifierImpl.java:374)
>>
>> at
>> org.eclipse.emf.common.notify.impl.NotifyingListImpl.dispatchNotification(NotifyingListImpl.java:261)
>>
>> at
>> org.eclipse.emf.common.notify.impl.NotifyingListImpl.addAllUnique(NotifyingListImpl.java:457)
>>
>> at
>> org.eclipse.emf.common.notify.impl.NotifyingListImpl.addAllUnique(NotifyingListImpl.java:400)
>>
>> at
>> org.eclipse.emf.common.util.AbstractEList.addAll(AbstractEList.java:370)
>> at internal.DomainManagerImpl$1.doExecute(DomainManagerImpl.java:143)
>> at
>> org.eclipse.emf.transaction.RecordingCommand.execute(RecordingCommand.java:135)
>>
>> at
>> org.eclipse.emf.common.command.BasicCommandStack.execute(BasicCommandStack.java:78)
>>
>> at
>> org.eclipse.emf.transaction.impl.AbstractTransactionalCommandStack.basicExecute(AbstractTransactionalCommandStack.java:241)
>>
>> at
>> org.eclipse.emf.transaction.impl.TransactionalCommandStackImpl.doExecute(TransactionalCommandStackImpl.java:63)
>>
>> at
>> org.eclipse.emf.transaction.impl.AbstractTransactionalCommandStack.execute(AbstractTransactionalCommandStack.java:165)
>>
>> at
>> internal.DomainManagerImpl.addToResource(DomainManagerImpl.java:138)
>> at internal.DomainManagerImpl.requestData(DomainManagerImpl.java:114)
>> at parts.master.Master.lambda$0(Master.java:57)
>> at parts.master.Master$$Lambda$275/361758860.run(Unknown Source)
>> at org.eclipse.core.runtime.jobs.Job$1.run(Job.java:159)
>> at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
>
>
> This make me wondering if I should use an UISynchronize for every
> operation on a UI control that fetches its data from an
> EMF-Adapterfactory? Isn't there an easier (and less error prone) solution ?
>
> Any best practices in this regard ?
>
> Thomas Elskens
>
Re: EMF Edit and the FX Application Thread [message #1691080 is a reply to message #1690625] Thu, 02 April 2015 07:50 Go to previous message
Thomas Elskens is currently offline Thomas ElskensFriend
Messages: 159
Registered: September 2014
Location: Brussels - Belgium
Senior Member
Hmm I took a look at the Realm documentation and for now it seems a bit overkill for my use case.

To solve the problem at hand, I finally turned the OSGi service that manages the EMF resources into a context function, inject a UISynchronize instance, and do all calls on resources on the UI-thread.

Thanks for the hint anyhow !

Thomas Elskens
Previous Topic:Use AquaFX or AeroFX Themes in e4/Equinox Application
Next Topic:Migrate E4 RCP from SWT to JavaFX using SWTonJavaFX
Goto Forum:
  


Current Time: Mon Sep 23 13:53:56 GMT 2024

Powered by FUDForum. Page generated in 0.03392 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top