Skip to content

Configure multiple installations of a single project

The MapStore2 externalized configuration allows for setting up multiple installations withing a single project. These installations may fulfill needs such as:

  • Having different use case scenarios within a single platform.
  • Providing different services, based on the same framework.
  • Fulfilling third-party customer requirements.

This guideline assumes familiarity with the following sections of the documentation, so please read these first if you haven't done so already:

Basic setup requirements

First you need to create you project following the steps outlined in the linked section.

Then you need to create the datadir folder inside root. To use the contents of the datadir you need to set the JVM system property datadir.location, like in the example below:

java -Ddatadir.location=/etc/mapstore/datadir

This command will make the contents of the datadir available for the application in runtime. For further details on setting up and usage of the datadir, refer to the section using a data directory.

Alternatively, for development purposes only, you can set the same property by modifying the web/pom.xml file inside your custom project.

Find the entry for cargo-maven3-plugin and add the systemProperties tag within the container tag, so that your configuration looks like this:

        <plugin>
            <groupId>org.codehaus.cargo</groupId>
            <artifactId>cargo-maven3-plugin</artifactId>
            <configuration>
                <container>
                    <containerId>tomcat8x</containerId>
                    <systemProperties>
                        <datadir.location>[local_path_to_your_datadir]/datadir/[customInstallationFolder]</datadir.location>
                    </systemProperties>
                    <zipUrlInstaller>
                        <url>https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/8.5.69/tomcat-8.5.69.zip</url>
                    </zipUrlInstaller>
                </container>
                <configuration>
                    <type>standalone</type>
                    <home>
                        ${project.build.directory}/apache-tomcat-${tomcat.version}
                    </home>
                    <properties>
                        <cargo.servlet.port>${tomcat.port}</cargo.servlet.port>
                        <cargo.logging>low</cargo.logging>
                    </properties>
                </configuration>
                <deployables>
                    <deployable>
                        <groupId>${project.groupId}</groupId>
                        <artifactId>${project.artifactId}</artifactId>
                        <type>war</type>
                        <properties>
                            <context>/mapstore</context>
                        </properties>
                    </deployable>
                </deployables>
            </configuration>
        </plugin>

In order to setup the multiple installations we can, for example, create three folders inside our datadir, denoting three different installations.

├── datadir
    ├── customA
    ├── customB
    ├── customC

Please note that the only requirement regarding folder structure is that the datadir exists, any content inside is optional and can be structured freely.

As a final step, we will re-set the datadir.location system property outlined above to point to a specific installation, such that:

java -Ddatadir.location=/etc/mapstore/datadir/customA

Customize configuration, assets and translations

Inside our example installation folder datadir/customA we can include customizations pertinent to this instance only and excluded from the other two instances exemplified in the section above.

For the purpose of this guideline we will adhere to the following folder structure convention, as outlined here:

├── customA
    ├── configs
    │   └── localConfig.json.patch
    └── extensions
        └── customizations
            ├── assets
            │   ├── css
            │   │   └── custom-style.css
            │   ├── img
            │   │   └── custom-logo.jpg
            │   │              
            │   └── js
                    └── customPlugin.js
            ├── index.js
            ├── index.js.LICENSE.txt

            ├── index.json
            └── translations
                ├── data.en-US.json
            │   ├── ...other translation files.

In the customA/configs/localConfig.json.patch file, we can patch the base configuration that is supplied by the configs/localConfig.json file inside root of the custom project, effectively customizing for this particular installation.

In alternative to localConfig.json.patch, that is applied server side, you can insert in the same directory localConfig.patch.json (noted the inverted suffix) in the same directory, and configure MapStore to use it by editing the js/app.jsx file.

import { setLocalConfigurationFile} from '@mapstore/utils/ConfigUtils';
...

setLocalConfigurationFile(['configs/localConfig.json', 'configs/localConfig.patch.json']);

This alternative version uses @mapstore/patcher and allow perform more complex overrides, even if requires this change to be applied to the code, so it will not work with the standard product.

The patch file can serve as the central hub for these customizations (see example below), essentially linking the whole content of the custom datadir folder and allowing for:

  • Adding custom plugins in the application.
  • Replacing default MapStore plugins.
  • Initializing and overriding default application state.
  • Initializing default component state of a particular plugin.
  • Linking to assets, such as images and fonts.
  • Including specific translations and language support.
[
  {
    "op": "replace",
    "path": "/initialState/defaultState/locales/supportedLocales",
    "value": {
      "en": {
        "code": "en-US",
        "description": "English"
      },
      "it": {
        "code": "it-IT",
        "description": "Italiano"
      }
    }
  },
  {
    "op": "replace",
    "path": "/translationsPath",
    "value": [
      "./MapStore2/web/client/translations",
      "./extensions/customizations/translations"
    ]
  },
  {
    "op": "replace",
    "path": "/initialState/defaultState/theme/selectedTheme/id",
    "value": "MyTheme"
  },
  {
    "op": "add",
    "path": "/plugins/desktop/-",
    "value": {
      "name": "Logo",
      "cfg": {
        "src": "./extensions/customizations/assets/img/custom-logo.jpg",
        "width": 100,
        "position": "topleft"
      }
    }
  }
]

In the example above the following modifications are made:

  • Language support is changed to English and Italian only.
  • Translation files for the language support are now read from a custom directory ./extensions/customizations/translations, instead of the default one.
  • A custom theme MyTheme is enabled for the whole application. For details see section below.
  • A custom plugin Logo is added to the application, specifically the homepage, while being configured with the following props:
  • src - for the logo image, pointing to a location in our datadir where the image is located.
  • width and position - which are props used by the component internally.

Theme customizations

Custom themes can be included in the project and applied only to a specific installation as well. Follow this guideline in order to create a custom theme.

Once you have the required folder structure and the necessary imports in theme.less, as well as the required changes in your webpack.config.js, do the following steps:

Check configs/localConfig.json, if you override the configuration, and look for selectedTheme property, it should be the following path.

/initialState/defaultState/theme/selectedTheme

If it's not configured, add the following block to initialState.defaultState, where id points to the name of the default theme (you should include one).

      "theme": {
        "selectedTheme": {
          "id": "default"
        }
      }

Inside the configuration patch file datadir/[installationName]/configs/localConfig.patch.json, modify the id we have previously set to point to the name of your custom theme, in the example below that would be MyTheme.

This change will effectively change the theme for that specific installation only.

[
  {
    "op": "replace",
    "path": "/initialState/defaultState/theme/selectedTheme/id",
    "value": "MyTheme"
  }
]

Please note that the themes/ folder has to be placed outside of the datadir folder, as stated in the linked guideline above.

The reason is that css / less files are assembled and packaged into a theme at build time, while the contents of the datadir folder are only available at runtime.