This article explains how you can quickly add support for each data format used in your application. As a result, your application will be able to load each data type as soon as a user opens a new file via a dialog box, or drags and drops a file into the application’s view, for example.
LuciadLightspeed comes with pre-configured code that allows you to add all available formats with just a few lines of code, as demonstrated in Program: Adding GUI actions to open data from a file or a URL.
samples/gxy/decoder/MainPanel
)
fOpenSupport = createOpenSupport();
fOpenSupport.addStatusListener(getStatusBar());
toolBar.addAction(new OpenAction(fOpenSupport));
toolBar.addAction(new OpenURLAction(fOpenSupport));
To set up the service look-up mechanism for each data format used in your application:
-
Get a hold of the relevant format-specific services such as model decoders and layer factories. For more information, see Selecting data format services.
-
Integrate these data decoding services into a GUI for opening data. See Configuring an action to load model data for more information.
-
Integrate other format-specific services. See Using other format services for more information.
-
Define and integrate your own format-specific services, if you have any. See How to plug in your own data format for more information.
This article goes into more detail about each step of the setup of the service look-up mechanism. To read more about such a look-up mechanism as well as other solutions for data format support, see Selecting data format services.
Selecting data format services
Most LuciadLightspeed formats simply consist of a model decoder, an implementation of ILcdModelDecoder
, and a layer factory, an implementation of ILcdGXYLayerFactory
or ILspLayerFactory
. Some formats come with a few extra services, as explained in Using other format services.
To add support for LuciadLightspeed 's formats, you need to instantiate and add these to your application.
There are several ways to add instant data format support in an application:
- Direct instantiation:
-
The most straightforward way to add format support. Create your own composite model decoder and layer factory and add the model decoders and layer factories you require in your application. Direct instantiation of a model decoder and layer factory is demonstrated in the LuciadLightspeed fundamentals samples.
- A dependency injection framework:
-
This approach wires the required model decoders and layer factories using a dependency injection framework such as Guice or Spring. For more information about dependency injection, refer to the documentation of the respective frameworks.
- A service look-up:
-
Using a look-up mechanism to query all supported model decoders and layer factories at run-time. In this approach, the support provided for each data format, such as its model decoder and layer factory, is regarded as a service that can be looked up, retrieved and activated. LuciadLightspeed comes with a look-up mechanism that supports both the built-in formats, as well as your own, custom-defined or custom-configured data formats.
While all three options have their advantages and disadvantages, this article primarily focuses on the service look-up option, because it is used throughout the LuciadLightspeed samples, and because it does not depend on third-party libraries.
Looking up data format services
The service look-up mechanism in LuciadLightspeed is compatible with Java’s java.util.service.ServiceLoader
, but offers extra functionality. The most important extra functionality of the service registry in LuciadLightspeed is the
ability to sort services based on their priority.
The LuciadLightspeed model decoders and layer factories are automatically registered with the service registry through the
annotation @LcdService
.
For more information about these annotations, see How to plug in your own data format.
In the sample code, the look-up mechanism is accessed through TLcdServiceLoader
.
The API consists of a single method getInstance
that returns an Iterable
for the given Java class.
Program: Retrieving all available ILcdModelDecoder
objects shows how to retrieve the ILcdModelDecoder
instances that are available in LuciadLightspeed and the samples.
ILcdModelDecoder
objects (from samples/common/formatsupport/OpenSupport
)
TLcdServiceLoader.getInstance(ILcdModelDecoder.class)
In the same way, you can retrieve all available ILcdGXYLayerFactory
or ILspLayerFactory
instances. Next to some format-specific layer factories, LuciadLightspeed also offers layer factories like GXYUnstyledLayerFactory
/UnstyledLayerFactory
and GXYSLDFileLayerFactory
/SLDFileLayerFactory
. These sample layer factories handle formats that do not contain or impose specific styling, for example. They are also registered
as a service with the service registry.
Composites are available for many services. Program: Creating composites for services shows how they can be instantiated. These composites, when instantiated using the service loader, combine all model decoders, layer factories or other services of all available optional components. They can therefore provide sensible default behavior for almost all data formats. For example the optional Ecdis maritime charts are decoded and styled correctly by default if this option is available. Do keep in mind that the exact behavior may change in future versions.
ILcdModelDecoder modelDecoder =
new TLcdCompositeModelDecoder(TLcdServiceLoader.getInstance(ILcdModelDecoder.class));
ILcdGXYLayerFactory gxyLayerFactory =
new TLcdCompositeGXYLayerFactory(TLcdServiceLoader.getInstance(ILcdGXYLayerFactory.class));
ILspLayerFactory layerFactory =
new TLspCompositeLayerFactory(TLcdServiceLoader.getInstance(ILspLayerFactory.class));
If you need full control, or if customization is desired, you’re recommended to implement your own service. Many examples
are available as sample code. If you annotate them with @LcdService
and generate the services files using the annotation processor, your services take precedence when using the default, or
higher, priority. See How to plug in your own data format for more information on the annotation processor.
Configuring an action to load model data
This section shows how to set up and configure an ILcdAction
to load ILcdModel
data from an external source.
The OpenSupport
class offers the most important functionality for this. It wires a composite model decoder with a customizable GUI support
class.
The openSource
method of the support class finds the most appropriate model decoder and decodes the given source into an ILcdModel
.
The GXYOpenSupport
and LspOpenSupport
classes further build upon this, creating a layer for the decoded model and adding it to a view. This is shown in Program: Adding a layer for a decoded model.
When adding layers to a GXY view for client side use, you will likely want to wrap the layers with an asynchronous layer.
That is not taken care of by the layer factories discovered using TLcdServiceLoader
as it is undesired for server-side views. GXYOpenSupport
decorates layers with asynchronous behavior using AsynchronousLayerFactory
.
samples/common/formatsupport/GXYOpenSupport
)
fLayerFactory = new TLcdCompositeGXYLayerFactory(aLayerFactories);
ILcdGXYLayer layer = new AsynchronousLayerFactory(fLayerFactory).createGXYLayer(aEvent.getModel());
if (layer == null) {
noLayerFactory(getParentComponent(), aEvent.getModel());
} else {
GXYLayerUtil.addGXYLayer(fView, layer);
if (layer.isVisible()) {
GXYLayerUtil.fitGXYLayer(fView, layer);
}
}
Three clients of this support class link the data loading functionality with the functionality for data selection by the application user:
- OpenAction
-
presents the user with a file chooser dialog
- OpenURLAction
-
presents the user with a dialog box that asks for a URL
- OpenTransferHandler
-
allows dragging files or URLs onto the view
This is illustrated in the decoder sample.
Using other format services
The format functionality in LuciadLightspeed is not restricted to model decoders and layer factories: other format services
can be registered with the service registry as well.
One example is the ILcdModelMeasureProviderFactory
, which is used in samples.gxy.common.MouseLocationComponent
for reading out measurements under the current mouse location. See the samples for an illustration of the readout functionality.
How to plug in your own data format
To add your own model decoder or layer factory to the service look-up mechanism, simply annotate it with @LcdService
.
If your class implements multiple interfaces, make sure that you also specify the interface you want to include as a service,
for example, ILcdModelDecoder.class
.
Optionally, you can specify a priority for the service. The default priority ensures that your own service takes precedence
over the LuciadLightspeed services. See the API reference documentation of LcdService
for a list of available priorities.
Program: Annotating a layer factory as a service shows how to annotate a layer factory with low priority.
samples/gxy/decoder/custom1/Custom1LayerFactory
)
@LcdService(service = ILcdGXYLayerFactory.class, priority = LcdService.LOW_PRIORITY)
public class Custom1LayerFactory implements ILcdGXYLayerFactory {
During compilation, the TLcdServiceAnnotationProcessor
makes sure that the annotation is translated into a service entry in the META-INF directory. The ServiceRegistry
look-up mechanism queries this directory at run-time to to provide the requested format services. This is illustrated in
Figure 1, “Service look-up mechanism”.
Note that annotation processing should be enabled when compiling and that the jar files containing the annotation processor (lcd_annotations*) should be in the compiler classpath. All major IDE implementations support annotation processing. Also note that the NetBeans IDE contains a known bug causing annotation processing not to work well in combination with the 'Compile on Save' option. A workaround is to disable this option. |