Skip to main content

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.

Jump to: navigation, search

Efxclipse/Runtime/Recipes

< Efxclipse
Revision as of 21:13, 6 December 2013 by Unnamed Poltroon (Talk) (Publishing to the IEclipseContext)

This page holds best practice recipes when writing JavaFX application using e(fx)clipse

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

Back to the top