Data Descriptor

Now that we have a data provider, we need to create the item that becomes the leaf node in that tree.

src/plugin/georss/georssdescriptor.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
goog.declareModuleId('plugin.georss.GeoRSSDescriptor');

import FileDescriptor from 'opensphere/src/os/data/filedescriptor.js';
import LayerType from 'opensphere/src/os/layer/layertype.js';
import ColorControlType from 'opensphere/src/os/ui/colorcontroltype.js';
import ControlType from 'opensphere/src/os/ui/controltype.js';

import {ID} from './georss.js';
import GeoRSSProvider from './georssprovider.js';

const {default: FileParserConfig} = goog.requireType('os.parse.FileParserConfig');


/**
 * GeoRSS file descriptor.
 */
export default class GeoRSSDescriptor extends FileDescriptor {
  /**
   * Constructor.
   */
  constructor() {
    super();
    this.descriptorType = ID;
  }

  /**
   * @inheritDoc
   */
  getType() {
    return LayerType.FEATURES;
  }

  /**
   * @inheritDoc
   */
  getLayerOptions() {
    var options = super.getLayerOptions();
    options['type'] = ID;

    // allow resetting the layer color to the default
    options[ControlType.COLOR] = ColorControlType.PICKER_RESET;
    return options;
  }
}

/**
 * Creates a new descriptor from a parser configuration.
 * @param {!FileParserConfig} config
 * @return {!GeoRSSDescriptor}
 */
export const createFromConfig = (config) => {
  const provider = GeoRSSProvider.getInstance();
  const descriptor = new GeoRSSDescriptor();
  FileDescriptor.createFromConfig(descriptor, provider, config);
  return descriptor;
};

Let’s walk through that real quick. getType reports FEATURES because we are loading vector data. getLayerOptions returns the JSON object that will be fed to the layer config class that we created earlier. The last two static methods assist with creating and updating a descriptor from the model produced by the import UI.

As always, here’s the test.

test/plugin/georss/georssdescriptor.test.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
goog.require('os.file.File');
goog.require('os.layer.LayerType');
goog.require('os.parse.FileParserConfig');
goog.require('os.ui.ColorControlType');
goog.require('os.ui.ControlType');
goog.require('plugin.georss');
goog.require('plugin.georss.GeoRSSDescriptor');
goog.require('plugin.georss.GeoRSSProvider');

describe('plugin.georss.GeoRSSDescriptor', function() {
  const {default: OSFile} = goog.module.get('os.file.File');
  const {default: LayerType} = goog.module.get('os.layer.LayerType');
  const {default: ColorControlType} = goog.module.get('os.ui.ColorControlType');
  const {default: ControlType} = goog.module.get('os.ui.ControlType');
  const {default: FileParserConfig} = goog.module.get('os.parse.FileParserConfig');

  const {ID} = goog.module.get('plugin.georss');
  const {default: GeoRSSDescriptor, createFromConfig} = goog.module.get('plugin.georss.GeoRSSDescriptor');
  const {default: GeoRSSProvider} = goog.module.get('plugin.georss.GeoRSSProvider');

  it('should report the correct type', function() {
    var d = new GeoRSSDescriptor();
    expect(d.getType()).toBe(LayerType.FEATURES);
  });

  it('should produce the correct layer options', function() {
    var d = new GeoRSSDescriptor();
    var opts = d.getLayerOptions();
    expect(opts.type).toBe(ID);
    expect(opts[ControlType.COLOR]).toBe(ColorControlType.PICKER_RESET);
  });

  it('should create a descriptor from a file parser config', function() {
    var file = new OSFile();
    file.setUrl('http://localhost/doesnotexist.georss');

    // default config
    var config = new FileParserConfig(file);
    var d = createFromConfig(config);

    expect(d.getId()).toBeTruthy();
    expect(d.getProvider()).toBe(GeoRSSProvider.getInstance().getLabel());
    expect(d.getUrl()).toBe(file.getUrl());
    expect(d.getColor()).toBeTruthy();

    // edited config
    var config = new FileParserConfig(file);
    config['tags'] = 'one, two\t, three';

    d = createFromConfig(config);
    expect(d.getId()).toBeTruthy();
    expect(d.getProvider()).toBe(GeoRSSProvider.getInstance().getLabel());
    expect(d.getUrl()).toBe(file.getUrl());
    expect(d.getColor()).toBeTruthy();
    expect(d.getTags()).toContain('one');
    expect(d.getTags()).toContain('two');
    expect(d.getTags()).toContain('three');
  });
});

Now let’s register it in our plugin.

src/plugin/georss/georssplugin.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
goog.declareModuleId('plugin.georss.GeoRSSPlugin');

import DataManager from 'opensphere/src/os/data/datamanager.js';
import ProviderEntry from 'opensphere/src/os/data/providerentry.js';
import LayerConfigManager from 'opensphere/src/os/layer/config/layerconfigmanager.js';
import AbstractPlugin from 'opensphere/src/os/plugin/abstractplugin.js';
import PluginManager from 'opensphere/src/os/plugin/pluginmanager.js';
import ImportManager from 'opensphere/src/os/ui/im/importmanager.js';

import {ID} from './georss.js';
import GeoRSSDescriptor from './georssdescriptor.js';
import GeoRSSImportUI from './georssimportui.js';
import GeoRSSLayerConfig from './georsslayerconfig.js';
import GeoRSSProvider from './georssprovider.js';
import {TYPE} from './mime.js';

/**
 * Provides support for the GeoRSS format.
 */
export default class GeoRSSPlugin extends AbstractPlugin {
  /**
   * Constructor.
   */
  constructor() {
    super();

    this.id = ID;
    this.errorMessage = null;
  }

  /**
   * @inheritDoc
   */
  init() {
    const lcm = LayerConfigManager.getInstance();
    lcm.registerLayerConfig(ID, GeoRSSLayerConfig);

    const im = ImportManager.getInstance();
    im.registerImportDetails('GeoRSS', true);
    im.registerImportUI(TYPE, new GeoRSSImportUI());

    // register georss provider type
    const dm = DataManager.getInstance();
    const title = 'GeoRSS Layers';
    dm.registerProviderType(new ProviderEntry(
        ID, // the type
        GeoRSSProvider, // the class
        title, // the title
        title // the description
    ));

    // register the geojson descriptor type
    dm.registerDescriptorType(ID, GeoRSSDescriptor);
  }
}

// add the plugin to the application
PluginManager.getInstance().addPlugin(new GeoRSSPlugin());

We now have everything we need to get an entry into the Add Data window. So let’s do that! Our UI launcher currently does not launch a UI (and it still won’t), but it could just save a new descriptor directly without any user input at all. Here’s how you hook that up:

src/plugin/georss/georssimportui.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
goog.declareModuleId('plugin.georss.GeoRSSImportUI');

import DataManager from 'opensphere/src/os/data/datamanager.js';
import DescriptorEvent from 'opensphere/src/os/data/descriptorevent.js';
import DescriptorEventType from 'opensphere/src/os/data/descriptoreventtype.js';
import * as Dispatcher from 'opensphere/src/os/dispatcher.js';
import FileParserConfig from 'opensphere/src/os/parse/fileparserconfig.js';
import FileImportUI from 'opensphere/src/os/ui/im/fileimportui.js';

import {createFromConfig} from './georssdescriptor.js';
import GeoRSSProvider from './georssprovider.js';


/**
 * GeoRSS import UI.
 */
export default class GeoRSSImportUI extends FileImportUI {
  /**
   * Constructor.
   */
  constructor() {
    super();
  }

  /**
   * @inheritDoc
   */
  getTitle() {
    return 'GeoRSS';
  }

  /**
   * @inheritDoc
   */
  launchUI(file, opt_config) {
    super.launchUI(file, opt_config);

    const config = new FileParserConfig();

    // if an existing config was provided, merge it in
    if (opt_config) {
      this.mergeConfig(opt_config, config);
    }

    config['file'] = file;
    config['title'] = file.getFileName();

    const descriptor = createFromConfig(config);

    // add the descriptor to the data manager first
    DataManager.getInstance().addDescriptor(descriptor);

    // followed by the provider
    GeoRSSProvider.getInstance().addDescriptor(descriptor);

    if (descriptor.isActive()) {
      Dispatcher.getInstance().dispatchEvent(new DescriptorEvent(DescriptorEventType.USER_TOGGLED, descriptor));
    }
  }
}

This adds the descriptor to the descriptor list, adds it as a child of the provider, and then pretends that the user went ahead and found it in Add Data and turned it on. To try this out:

  1. Go to Open File/URL
  2. Paste https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.atom or another URL in the field there
  3. Hit “Next”

Boom! The layer is on the map. But we kinda had that before. Now it will persist through a restart. So refresh the page and bask in your accomplishment! You can also check it out in the Add Data window, as now there will be a GeoRSS Files > 2.5_day.atom entry. Try importing the same URL again. OpenSphere will detect that you already have a descriptor with the same URL and ask you what you would like to do before continuing.