Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Efxclipse/Runtime/Recipes
This page holds best practice recipes when writing JavaFX application using e(fx)clipse
Contents
Logging
e(fx)clipse has its own logging facade org.eclipse.fx.core.log.Logger
which allows to plug-in different log frameworks.
Currently available are:
-
java.util.Logging
(default) - log4j by adding
org.eclipse.fx.core.log4j
bundle to your OSGi-Runtime
Usage
There are different ways to use get a logger.
LoggerCreator
If you are running on OSGi you can add the org.eclipse.fx.osgi.util
bundle which provides access to the LoggerCreator
factory class
import org.eclipse.fx.core.log.Logger; import org.eclipse.fx.osgi.util.LoggerCreator; public class MyClass { private static Logger LOGGER = LoggerCreator.createLogger(MyClass.class); // .... }
LoggerFactory Service
The different logger bundles contribute their LoggerFactory
implementation into the OSGi-Registry. In case you are e.g. contributing a service via DS you can get simple add a service reference and you'll get the LoggerFactory
with the highest rank injected.
import org.eclipse.fx.core.log.LoggerFactory; import org.eclipse.fx.core.log.Logger; public class MyServiceImpl implements MyService { private Logger logger; public void setLoggerFactory(LoggerFactory factory) { this.logger = factory.createLogger(MyService.class.getName()); } public void unsetLoggerFactory(LoggerFactory factory) { } }
<?xml version="1.0" encoding="UTF-8"?> <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="myservice"> <implementation class="impl.MyServiceImpl"/> <service> <provide interface="service.MyService"/> </service> <reference bind="setLoggerFactory" cardinality="1..1" interface="org.eclipse.fx.core.log.LoggerFactory" name="LoggerFactory" policy="static" unbind="unsetLoggerFactory"/> </scr:component>
Eclipse DI & @Log annotation
If you make use of Eclipse DI in your code you can get a Logger
instance injected with:
import org.eclipse.fx.core.log.Log; import org.eclipse.fx.core.log.Logger; import javax.inject.Inject; public class MyDIComponent { @Inject @Log Logger logger; }
Google Guice & @Log annotation
If you use Guice as the DI container you use the org.eclipse.fx.core.guice
bundle to get a Logger injected in your component with:
import org.eclipse.fx.core.log.Log; import org.eclipse.fx.core.log.Logger; import javax.inject.Inject; public class MyDIComponent { @Log Logger logger; }
if you have configured your Guice-Module with:
import com.google.inject.Module; import com.google.inject.Binder; import org.eclipse.fx.core.log.LoggerFactory; import org.eclipse.fx.core.log4j.Log4JLoggerFactory; import org.eclipse.fx.core.guice.FXLoggerListener; public class MyModule implements Module { public void configure(Binder binder) { binder.bind(LoggerFactory.class).toProvider(Log4JLoggerFactory.class); // or JUtilLoggerFactory binder.bindListener(Matchers.any(), new FXLoggerListener()); } }
Instead of directly binding to a logger factory you can delegate to the OSGi-Service registry by using OSGiLoggerFactoryProvider
:
import com.google.inject.Module; import com.google.inject.Binder; import org.eclipse.fx.core.log.LoggerFactory; import org.eclipse.fx.core.guice.FXLoggerListener; import org.eclipse.fx.core.guice.OSGiLoggerFactoryProvider; public class MyModule implements Module { public void configure(Binder binder) { binder.bind(LoggerFactory.class).toProvider(OSGiLoggerFactoryProvider.class); binder.bindListener(Matchers.any(), new FXLoggerListener()); } }
Extending
Like outlined above there are 2 logger implementations available from the e(fx)clipse p2 repository. If you want to use a different logging framework you are able to plug-in your own by implementing LoggerFactory
and contributing it to the OSGi-Service-Registry.
import javax.inject.Provider; import org.eclipse.fx.core.log.LoggerFactory; import org.eclipse.fx.core.log.Logger; public class MyLoggerFactory implements LoggerFactory, Provider<LoggerFactory> { @Override public LoggerFactory get() { return this; } @Override public Logger createLogger(String name) { return new LoggerImpl(name); } static class LoggerImpl implements Logger { private String name; public LoggerImpl(String name) { this.name = name; } // .... } }
You contribute it to the OSGi-Service registry e.g. by using DS. You should give the service a higher ranking than 1 (which is the ranking of the log4j service) to ensure it is picked when a logger is requested.
<?xml version="1.0" encoding="UTF-8"?> <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="my.logger.framework.factory"> <implementation class="my.logger.framework.MyLoggerFactory"/> <property name="service.ranking" type="Integer" value="2"/> <service> <provide interface="org.eclipse.fx.core.log.LoggerFactory"/> </service> </scr:component>
Eclipse DI
Publishing to the IEclipseContext
The IEclipseContext
is the central component of the Eclipse DI container. Retrieving values from it is as easy as writing @Inject
in your java class and the DI container will fill it with a value and keep it up-to-date if you used field or method injection.
The opposite - publishing a value into the context - is not as easy because your java component will get a dependency on the DI-Container because it needs to access the IEclipseContext
directly. e(fx)clipse provides you the possibility to get around this architectual problem by defining an annotation named @ContextValue
which marks a slot in IEclipseContext
instance which can be used to observe the value and modified.
import org.eclipse.fx.core.di.ContextBoundValue; import org.eclipse.fx.core.di.ContextValue; import javax.inject.Inject; public static class SimpleInject { @Inject @ContextValue(contextKey="user") public ContextBoundValue<String> value; private void updateValue() { value.publish("tomschindl"); } }
To make use of this your bundle needs to have a dependency on org.eclipse.fx.core.di
and your runtime has to include org.eclipse.fx.core.di.context
.
Injected value as an observable
A reoccuring pattern when developing with Eclipse Databinding and Dependency Injection is that the injected value is used as the master in master-detail binding scenario