Interface ILcdGXYAsynchronousLayerWrapper

All Superinterfaces:
ILcdGXYLayer, ILcdLayer, ILcdPropertyChangeSource, ILcdSelection<Object>, Serializable
All Known Implementing Classes:
TLcdGXYAsynchronousEditableLabelsLayerTreeNodeWrapper, TLcdGXYAsynchronousEditableLabelsLayerWrapper, TLcdGXYAsynchronousLayerTreeNodeWrapper, TLcdGXYAsynchronousLayerWrapper, TLcdGXYLspAsynchronousLayerTreeNodeWrapper, TLcdGXYLspAsynchronousLayerWrapper

public interface ILcdGXYAsynchronousLayerWrapper extends ILcdGXYLayer
Interface for layers that paint themselves asynchronously. Typically, an asynchronous layer wraps around a regular ILcdGXYLayer. Instead of painting synchronously in the event dispatch thread, this wrapper delegates its paint requests to an ILcdGXYAsynchronousPaintQueue. The paint queue has its own asynchronous thread in which it paints the wrapped layer. This image will then be painted again in the event dispatch thread.

Making a layer paint itself asynchronously

To create the appropriate layer wrapper for your layer you can simply call the create(com.luciad.view.gxy.ILcdGXYLayer) method.

Considerations

When using asynchronous layer painting, please take the following into consideration:

  • retrieving painters or editors from this wrapper may cause the current thread to block while asynchronous painting is ongoing. This includes synchronous view label decluttering algorithms (see TLcdGXYAsynchronousViewLabelPainterWrapper);
  • the wrapped layer's paint method should take care when waiting for another thread: if that thread in turn waits for asynchronous painting to complete, a deadlock will occur;
  • paint queue sharing may affect layer ordering (see ILcdGXYAsynchronousPaintQueue implementations);
  • in order to protect its state, the wrapped layer should not be manipulated directly.

Accessing the wrapped layer

This interface offers the following invocation methods to access and manipulate the wrapped layer's state:

Synchronizing the layer wrapper and the wrapped layer

If the wrapper itself exposes the wrapped layer's state (i.e. by implementing some interface), this state must be duplicated and synchronized. For example, if someone calls ILcdGXYAsynchronousLayerWrapper#setVisible( false ), it is expected that the wrapped layer will also change its visibility. Here, the layer wrapper's responsibility is to duplicate and track state changes (i.e. what to synchronize). The paint queue determines a safe point in time for synchronizing these changes (i.e. when to synchronize). The paint queue accesses this functionality through the getSynchronousGXYLayerChangeTracker() and getAsynchronousGXYLayerChangeTracker() methods. The former method retrieves and applies changes for this wrapper, the latter retrieves and applies changes for the wrapped layer. To illustrate the state synchronization mechanism, consider a visibility change in the layer wrapper:

  1. ILcdGXYAsynchronousLayerWrapper#setVisible(false) is called, e.g. by the user clicking in a layer control
  2. the layer wrapper fires a property change causing a repaint of the view
  3. the paint queue is asked to paint the layer
  4. the paint queue retrieves the layer wrapper's state changes in the EDT by calling ILcdGXYAsynchronousLayerWrapper#getSynchronousGXYLayerChangeTracker#getChanges(). Here, the changed state will consist of the change in visibility.
  5. the paint queue applies the visibility state change to the wrapped layer in the asynchronous paint thread by calling ILcdGXYAsynchronousLayerWrapper#getAsynchronousGXYLayerChangeTracker#applyChanges(). Hence, the wrapped layer will become invisible.
  6. the paint is executed in the asynchronous paint thread, yielding an empty (invisible) result.
  7. the paint queue retrieves the layer's state changes (if any) in the asynchronous paint thread by calling ILcdGXYAsynchronousLayerWrapper#getAsynchronousGXYLayerChangeTracker#getChanges()
  8. the paint queue applies these state changes to the layer wrapper in the EDT by calling ILcdGXYAsynchronousLayerWrapper#getSynchronousGXYLayerChangeTracker#applyChanges()
  9. the view is informed of the asynchronous paint and repaints itself to display the results
Since:
7.2
See Also:
  • Method Details

    • getGXYAsynchronousPaintQueue

      ILcdGXYAsynchronousPaintQueue getGXYAsynchronousPaintQueue()
      Returns the paint queue handling the asynchronous paints.
      Returns:
      a paint queue to which the paint requests are delegated
    • setGXYAsynchronousPaintQueue

      void setGXYAsynchronousPaintQueue(ILcdGXYAsynchronousPaintQueue aQueue)
      Sets the paint queue to delegate asynchronous paint requests to. Paint queues can be shared between multiple layer wrappers. This is even advised, as each paint queue uses memory for buffering the asynchronously generated images.
      Parameters:
      aQueue - the asynchronous paint queue responsible for executing the paint calls.
    • getGXYLayer

      ILcdGXYLayer getGXYLayer()
      Returns the layer that contains the actual paint logic. Note that it is generally unsafe to access the layer while it is painting itself, in the painting thread of the paint queue. In addition, the properties of the layer must not yet have been propagated from this layer wrapper. The methods invokeAndWaitOnGXYLayer(ILcdGXYAsynchronousLayerRunnable) and invokeLaterOnGXYLayer(ILcdGXYAsynchronousLayerRunnable) provide safe alternatives.
      Returns:
      the wrapped layer
    • setAsynchronous

      void setAsynchronous(boolean aAsynchronous) throws InterruptedException
      Disables or enables the asynchronous drawing.
      Parameters:
      aAsynchronous - if false, paints synchronously, if true, paints asynchronously
      Throws:
      InterruptedException - when the thread is interrupted while waiting for the asynchronous paint to complete
    • isAsynchronous

      boolean isAsynchronous()
      Returns whether the wrapped layer is configured to be painted asynchronously.
      Returns:
      whether the asynchronous drawing is enabled
    • invokeAndWaitOnGXYLayer

      void invokeAndWaitOnGXYLayer(ILcdGXYAsynchronousLayerRunnable aInvocation) throws InterruptedException
      Executes the given layer runnable so that the invocation does not interfere with the asynchronous painting. The invocation is executed in the view's paint thread (typically the EDT). The method waits until the invocation has stopped.
      Parameters:
      aInvocation - the invocation to run. The invocation will pass the original layer.
      Throws:
      InterruptedException - when the thread is interrupted while waiting for the asynchronous painting to complete
    • invokeLaterOnGXYLayer

      void invokeLaterOnGXYLayer(ILcdGXYAsynchronousLayerRunnable aInvocation)
      Executes the given layer runnable so that the invocation does not interfere with the asynchronous painting. The invocation is executed in the asynchronous paint thread if the layer is painted asynchronously, and executed in the current thread otherwise. In the former case, the method returns immediately.

      The invocation should take care when waiting for another thread: if that thread in turn waits for asynchronous painting to complete, a deadlock will occur.

      To avoid concurrency problems with property change listeners, layer property changes will be fired on the event dispatch thread, not on the asynchronous paint thread.

      Parameters:
      aInvocation - the invocation to run. The invocation will pass the original layer.
    • invokeLaterOnGXYLayerInEDT

      void invokeLaterOnGXYLayerInEDT(ILcdGXYAsynchronousLayerRunnable aInvocation)
      Executes the given layer runnable so that the invocation does not interfere with the asynchronous painting. The invocation is executed in the event dispatch thread. The method always returns immediately.
      Parameters:
      aInvocation - the invocation to run. The invocation will pass the original layer.
    • invokeNowOnGXYLayer

      void invokeNowOnGXYLayer(ILcdGXYAsynchronousLayerRunnable aInvocation)
      Executes the given layer runnable so that the invocation does not interfere with state synchronization. The invocation is executed in the caller's thread. The method waits until the invocation has stopped. During the invocation, asynchronous painting may occur, so care is advised.
      Parameters:
      aInvocation - the invocation to run. The invocation will pass the original layer.
    • getSynchronousGXYLayerChangeTracker

      ILcdGXYLayerChangeTracker getSynchronousGXYLayerChangeTracker()
      Returns a state change synchronizer for this wrapper. The wrapper's changes will be applied to the wrapped layer before each asynchronous paint, using the asynchronous wrapper.
      Returns:
      a synchronizer tracking changes for this wrapper. To protect this wrapper's state, the tracker should only be used in the synchronous thread, i.e. the event dispatch thread.
    • getAsynchronousGXYLayerChangeTracker

      ILcdGXYLayerChangeTracker getAsynchronousGXYLayerChangeTracker()
      Returns a state change synchronizer for the wrapped layer. The changes will be applied after each asynchronous paint, using the synchronous tracker.
      Returns:
      a synchronizer tracking changes for the wrapped layer. To protect the wrapped layer's state, the tracker should only be used in the asynchronous thread, i.e. the paint thread.
    • create

      Utility method to wrap aLayer with a default ILcdGXYAsynchronousLayerWrapper implementation. The used wrapper depends on the interfaces that aLayer implements.

      This method supports:

      • Single ILcdGXYLayer instances.
      • GXY layer tree structures with ILcdLayerTreeNode instances.
      • ILcdGXYEditableLabelsLayer implementations: the returned asynchronous wrapper will also implement the ILcdGXYEditableLabelsLayer interface.

      Any other interfaces the ILcdGXYLayer implements will not be exposed by the returned asynchronous wrapper.

      Parameters:
      aLayer - The layer (structure) to wrap
      Returns:
      A layer (structure) wrapped with asynchronous wrappers.
      Since:
      2019.0