Content Type Detection

The first thing we need to do for a file type is to detect the file type given a generic file. This is an XML format, so we can extend a generic XML content type detection function from OpenSphere.

src/plugin/georss/mime.js:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
goog.declareModuleId('plugin.georss.mime');

import {register} from 'opensphere/src/os/file/mime.js';
import {TYPE as XMLTYPE, createDetect} from 'opensphere/src/os/file/mime/xml.js';

/**
 * @type {string}
 */
export const TYPE = 'application/rss+xml+geo';

register(
    // the type for this detection
    TYPE,
    // os.file.mime.xml provides a function that creates a detection function for a
    // given root tag regex and xmlns regex
    createDetect(/^feed$/, /^http:\/\/www.w3.org\/2005\/Atom$/),
    // the priority of this detection. 0 is the default, lower numbers run earlier
    0,
    // the parent type; XML in this case
    XMLTYPE);

As always, let’s test it.

External Plugins

If you are working with an external plugin, you will need to add the following two lines to the files list in karma.conf.js:

{pattern: resolver.resolveModulePath('chardetng-wasm/dist/es5/chardetng.es5.min.js'), watched: false, included: true, served: true},
{pattern: '../opensphere/.build/xml-lexer.min.js', watched: false, included: true, served: true},
test/plugin/georss/mime.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
goog.require('os.file.File');
goog.require('os.file.mime.mock');
goog.require('plugin.georss.mime');

describe('plugin.georss.mime', function() {
  const {default: OSFile} = goog.module.get('os.file.File');
  const {testNo, testYes} = goog.module.get('os.file.mime.mock');
  const {TYPE} = goog.module.get('plugin.georss.mime');

  it('should detect Atom feeds as GeoRSS', function() {
    var feed = '<?xml version="1.0" encoding="utf-8"?>' +
      '<feed xmlns="http://www.w3.org/2005/Atom"/>';

    var buffer = new TextEncoder().encode(feed).buffer;

    // pretend this came from a file
    var file = new OSFile();
    file.setFileName('something.georss');
    file.setUrl(file.getFileName());

    var testFunc = testYes(TYPE);
    testFunc(buffer, file);
  });

  it('should not detect other XML as GeoRSS', function() {
    var xml = '<?xml version="1.0" encoding="utf-8"?><something xmlns="http://something.com/schema"/>';
    var buffer = new TextEncoder().encode(xml).buffer;

    // pretend this came from a file
    var file = new OSFile();
    file.setFileName('something.xml');
    file.setUrl(file.getFileName());

    var testFunc = testNo(TYPE);
    testFunc(buffer, file);
  });

  it('should register itself with mime detection', function() {
    var chain = os.file.mime.getTypeChain(TYPE).join(', ');
    expect(chain).toBe('application/octet-stream, text/plain, text/xml, ' + TYPE);
  });
});

Run yarn test to try that out.

Now we will have our plugin import our mime package.

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
goog.declareModuleId('plugin.georss.GeoRSSPlugin');

import './mime.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 {ID} from './georss.js';
import GeoRSSLayerConfig from './georsslayerconfig.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);
  }
}

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

Save and run the build. You should now be able to import any atom feed (assuming the remote server has CORS configured; download it and import it as a file otherwise) into OpenSphere! Once it loads, it will complain that it does not have an import UI registered for ‘application/rss+xml+geo’, which is fine for now.