Overview
The purpose of the plugin is to allow to set up a specific configuration for a Wedia portal application, by overriding a basic configuration provided by the product.
The base of the configuration is a JSON file. Any element of this JSON can be overriden in a folder, through a tree of files and folders that correspond to the tree of the base JSON. Multiple folders can be added to redefine the configuration redefined by the previous folders.
Mappings
A configuration is thus defined by a series of files that will redefine the basic configuration successively, in order to obtain a final configuration, the fusion of the whole.
This series of folder constitutes a path designated by a unique identifier. A client application will retrieve its final configuration via this ID. Mappings define the correspondence between IDs and paths. The configuration of mappings is done in the plugin settings.
Adaptation to the context
The final configuration depends on an invocation context that constitutes different variables, mainly from the surfer, in order to have different configurations depending on the connected user.
There are therefore folders in the path associated with a mapping whose name depends on the invocation context that allow specific configurations.
Post processors
A postprocessor is a component that determines a folder name according to elements of the invocation context.
A postprocessor provides
a list of possible values, at least one, but preferably several (for a single value, you might as well use a static file).
a function to convert the invocation context into a value that must be one of the possible values
Plugin settings
Mappings
Mappings associate configuration identifiers with paths defining a configuration.
A path consists of a succession of folder names or references to a postprocessor, separated by arobase (@
).
For example _portal@picker defines a configuration whose base is in the _portal folder, overridden by what is in the _portal@picker folder.
Postprocessors are identified by their associated variable name preceded by a colon (:
).
For example _portal@picker@:surferRole defines a configuration whose base is the portal folder, overridden by what is in the portal@picker@picker folder, overridden by what is in a folder whose name is determined by the postprocessor associated with the surferRole variable, by example _portal@picker@role_4 for the role 4.
For example _portal@config@picker designates a configuration defined in 3 folders whose relative paths are successively :
_portal
_portal@config
_portal@config@picker
The path _portal@$config@picker designates a configuration defined in 3 folders whose relative paths are successively :
_portal
config
config@picker
The dollar character has this effect whether it is in the path or in the value returned by a postprocessor. Only the first character is considered.
The dollar character can be used in a variable:
in name (like for example here
_portal@config@$:surferRole@custo
)in a value produced by a post processors
for example,_portal@config@$:customSurferRole
and post processor return$role-1
,$role-2
,role-4
..., to get the following folders (or files):_portal
_portal@config
role-1@custo
role-2@custo
_portal@config@role-4@custo
To configure the mappings, use the config_settings plugin parameter. This is a JSON object whose the mappings property that designs the mappings as an object, whose keys are the mapping IDs and whose associated values are the paths.
For example :
{ "mappings": { "portal": "_portal@club-wed@:surferRole@:userAgent", "picker": "_portal@club-wed@:picker" } }
Postprocessors
To configure the post processors, use the config_settings plugin parameter. This is a JSON object in the postProcessors property that designs the post processors as an object, whose keys are the post processors names (variable names) and whose associated values define the corresponding post processors.
To define a post processor you can specify
a class name from a set of standard post processors provided in the plugin
configuration set-up parameters (depending of the component)
Base locations
By default, folders and configuration files are stored in arbitrary folders in the :
the base configurations are in the folder
config/config_resolver/bases
situé dans le plugin WXM_CONFIG_RESOLVERthe other configurations (overrides) are in the folder
config/config_resolver/configs
if a holding plugin has been configured, located in this one
otherwise located in the WXM_CONFIG_RESOLVER plugin
Basic configurations can be placed in other plugins, using the baseLocations section.
This section is a JSON object whose
the keys are base names
the properties are
either a plugin name
in this case, the storage folder isconfig/config_resolver/bases
relative to this plugin pathor a plugin name and a path (relative to the path of this plugin)
Example:
{ "mappings": { "portal": "_portal@club-wed@:surferRole@:userAgent", "picker": "_portal@club-wed@:picker" }, "baseLocations": { "_portal": "PACKAGED_Portal" } }
Example with the configuration file in the config folder of the plugin:
{ "mappings": { "portal": "_portal@club-wed@:surferRole@:userAgent", "picker": "_portal@club-wed@:picker" }, "baseLocations": { "_portal": { "plugin": "PACKAGED_Portal", "path": "config" } }
Lock system
fs_lock_enabled, boolean (default is true)
enable or disable the lock system
lock_config, json
lock system set-up
safeProcessCaptureTimeout, time, optional (default 10000 ms)
Miscellaneous
default_holding_plugin, string, optional
designates the name of a plugin where the configuration will be stored (in its config/config_resolver/configs
folder. If no value is specified, the configuration is stored in the config/config_resolver/configs
folder of the wxm_config_resolver plugin, unless there is an activated wxm_config_resolver_config plugin.
default_contribution_plugin, string, optional
designate the name of a default plugin to store custom postprocessors (groovy files)
default_service_debug, boolean, optional
enables by default the debug mode on all requests
default_uri_segment, string, optional
the root segment of the end point URI (if no value is provided, the value is portalconfig (so all end point URIs served by this plugin are of the form /api/portalconfig/*
))
this means that you can create a new configuration universe by duplicating the plugin and using another uri, for example, /api/whatyouwant/*
Time set-up
The values of type time can be
either a number (the unit depends on the parameter)
or a number (integer or decimal) followed by a unit, among
s
(seconds)ms
(milliseconds)m
(minutes)h
(hours)
Standard postprocessors
Surfer role
Class name: fr.wedia.confres.core.model.processor.SurferRolePostProcessor
This post processor allows to have a specific configuration for each role. The folder name for a role is formed by concatenating a prefix and the role identifier.
For example: role-1.
Set-up
The prefix can be configured using the property prefix.
For exemple:
"surferRole": { "processor": "fr.wedia.confres.core.model.processor.SurferRolePostProcessor", "prefix": "altrole-" }
The value for not connected mode is ““. It could be changed with the property notConnectedValue.
Abstraction
You can implement your own surfer-dependent post processor by implementing the fr.wedia.confres.core.model.processor.AbstractSurferPostProcessor
abstraction and its String getValue(CTSurfer)
method.
User agent
Class name: fr.wedia.confres.core.model.processor.UserAgentPostProcessor
This post processor allows you to have a specific configuration for a particular browser.
The association between a configuration folder and a browser is done by configuration, by indicating a folder name associated with a regular expression pattern: the User-Agent header that will match the regular expression will select the folder.
You can indicate several files and patterns. This is done through the config property, which is an array of objects, with a name property for the folder name and a pattern property for the regular expression pattern.
For example:
"userAgent": { "processor": "fr.wedia.confres.core.model.processor.UserAgentPostProcessor", "config": [{ "pattern": ".*Mobi.*", "name": "mobile" }] }
If several patterns are indicated, they are tested in the order of the array. The first one that matches is used.
Set-up
By default, only one User-Agent header is tested, the first one found. You can test all the values of this header using the anyMatch configuration property by setting it to true.
"userAgent": { "processor": "fr.wedia.confres.core.model.processor.UserAgentPostProcessor", "anyMatch": true, "config": [{ "pattern": ".*Mobi.*", "name": "mobile" }] }
Abstraction
You can implement your own header-dependent post processor by implementing the fr.wedia.confres.core.model.processor.AbstractHeaderPostProcessor abstraction and its String getValue(String,Collection<fr.wedia.confres.api.util.Headers>)
method. See others methods getValueFoNoHeaders
and getValueForNull
to return a value respectively for no headers or null headers. See the javadoc for more information
Customizings postprocessors
You can create your own postprocessors. Just define the implementation class in a groovy extension file. The class must extend one of the abstractions provided as standard, or possibly a standard postprocessor.
In this case, the component reference is expressed as a path to a file.
For examples:
"surferRole": "customprocessors/mysurferrolepostprocessors.groovy"
"surferRole": { "processor": "customprocessors/mysurferrolepostprocessors.groovy", "prefix": "altrole-" }
Location
The location of the file can be:
the SAN
a plugin
To specify a plugin, add the plugin property."surferRole": { "processor": "customprocessors/mysurferrolepostprocessors.groovy", "plugin": name of the plugin }
If the value of property plugin is a string, it’s the name of the plugin
In all other cases,, the plugin is a default plugin, configured in the default_contribution_plugin parameter of the wxm_config_resolver plugin
Implementation
To implement a postprocessor in groovy, extend the class fr.wedia.confres.core.model.processor.AbstractPostProcessor
. You can also base your class on one of the pre-implemented postprocessor classes (see Standard postprocessors).
Example:
package fr.wedia.confref.custom.processor; import fr.wedia.confres.core.model.processor.*; class CustomProcessor extends AbstractPostProcessor { private static final String CONNECTED = "connected"; private static final String NOTCONNECTED = "notconnected"; private static final List<String> VALUES = Arrays.asList("",CONNECTED,NOTCONNECTED); @Override String getValue(ProcessorContext context) { wsnoheto.engine.CTSurfer surfer = context.getSurfer(); return surfer==null?"":(surfer.isConnected()?CONNECTED:NOTCONNECTED); } @Override Collection<String> getAvailableValues() { return VALUES; } }
You must implement two methods:
The
getAvailableValues()
method must return all possible values returned by the other method.The method
getValue(ProcessorContext)
will return the desired value in the invocation context. It is important to consider the context rather than the query, because in some cases, for the purposes of the configuration editing tool, and for testing purposes, the context information may override query values. It is the ProcessorContext class that allows access to the invocation context:ProcessorContext.getSurfer()
: returns the surfer for which we want to execute the postprocessorProcessorContext.getSurferProperty(String name)
: returns the value of a property of the surfer (or null if it does not exist).ProcessorContext.getHeaders(String name)
: returns the values of the specified headerProcessorContext.getParameters()
: returns a wrapper to retrieve query parametersProcessorContext.getMappingId()
: returns the ID of the mapping we are trying to solveProcessorContext.getPathInfo()
: allows to have a contextual description of invocation to log in particularAs a last resort, you can retrieve the request, with the method
ProcessorContext.getRequest()
There is no guarantee that any of the returned values are not null: if any of the information provided by the ProcessorContext is used, all cases must be tested (including, for example, testing whether getRequest() is null, as the postprocessor could be invoked as part of a simulation outside of HTTP calls).
A value returned by these methods must meet certain conditions:
as it is a folder name, there must not be any forbidden characters in the file names (slash (
/
), backslash(\
), column(:
), pipe (|
), chevrons (<
and>
), question mark (?
), double-quotes ("
)...)do not use arobase (
@
), this character being used as a name separator in configuration folder names, to avoid possible conflicts. Avoid also other separators, like dot (.
), whitespaces…generally avoid characters other than letters (without accent), numbers, underscore and dash (avoid dash if possible, this character can cause problems within URLs
the initial dollar character (
$
) is always considered as a cutting ordervalues should be considered case insensitive, but use lower case (as folders can be deployed by nar)
the blank values are always ignored (skip the processor value in the final path). For example, if a path is defined by
x@:processor@y
, and the corresponding postprocessor returns a blank string, the path will bex@y
.
Set-up
You can configure a custom postprocessor via its declaration in the plugin configuration.
Basic set-up
By default, the properties indicated in the postprocessor configuration, except the reserved properties processor
, plugin
, config
and configDeserializer
are all injected in the class variables by compliant setter.
For example, the implementation of postprocessor is (mypostprocessor.groovy
):
package fr.wedia.confref.custom.processor; import fr.wedia.confres.core.model.processor.*; class CustomProcessor extends AbstractPostProcessor { String connectedValue = "connected"; String notConnectedValue = "notconnected"; void setConnectedValue(String connectedValue) { if ( StringUtils.isNotBlank(connectedValue) ) { this.connectedValue=connectedValue; } } void setNotConnectedValue(String notConnectedValue) { if ( StringUtils.isNotBlank(notConnectedValue) ) { this.notConnectedValue=notConnectedValue; } } @Override String getValue(ProcessorContext context) { wsnoheto.engine.CTSurfer surfer = context.getSurfer(); return surfer==null?"":(surfer.isConnected()?connectedValue:notconnectedvalue); } @Override Collection<String> getAvailableValues() { return Arrays.asList("", connectedValue, notConnectedValue); } }
The configuration of the postprocessor could be:
"connectionState": { "processor": "customprocessors/mypostprocessor.groovy", "plugin": name of the plugin, "connectedValue": "on", "notConnectedValue": "off" }
The two variables connectedValue
and notConnectedValue
will have the values "on" and "off" respectively.
Control of configuration variables
You can designate which variables will be configurable by using the @PostProcessorConfig annotation. In this case, only the variables that have this annotation will be configurable.
For example:
package fr.wedia.confref.custom.processor; import fr.wedia.confres.core.model.processor.*; import fr.wedia.confres.utils.annot.PostProcessorConfig; class CustomProcessor extends AbstractPostProcessor { @PostProcessorConfig(blank=false) String connectedValue = "connected"; @PostProcessorConfig(blank=false) String notConnectedValue = "notconnected"; int myvariable = 42; @Override String getValue(ProcessorContext context) { wsnoheto.engine.CTSurfer surfer = context.getSurfer(); return surfer==null?"":(surfer.isConnected()?connectedValue:notConnectedValue); } @Override Collection<String> getAvailableValues() { return Arrays.asList("", connectedValue, notConnectedValue); } }
And
"connectionState": { "processor": "customprocessors/mypostprocessor.groovy", "plugin": name of the plugin, "connectedValue": "on", "notConnectedValue": "off", "myvariable": 0 }
The two variables connectedValue
and notConnectedValue
will have the values "on" and "off" respectively, but myvariable
will remain unchanged.
The annotation has two parameters:
name: (string, optional) to select the name of the property in the json
for example, you can have@PostProcessorConfig(name="threshold") int myvar=42;
blank: (boolean, optional, default is true) if false, blank (emtpy or null) values are ignored
It’s not possible to mix the setter and the annotation ways to configure the postprocessor.
Advanced set-up
You can also deport the configuration to a separate object. If you configure your postprocessor by specifying properties in a config section, the properties will also be injected into the class variables.
For example
"connectionState": { "processor": "customprocessors/mypostprocessor.groovy", "plugin": name of the plugin, "config": { "connectedValue": "on", "notConnectedValue": "off" } }
You can also take control of the configuration decoding by adding to your class a setter called setConfig (void
return type and only one argument).
the type of argument can be
com.google.gson.JsonElement
.the type of argument can be
fr.wedia.confres.core.model.processor.PostProcessorConfig
. It is an encapsulation ofcom.google.gson.JsonElement
that allows to retrieve information more easily.at any inner class with a no-argument constructor. It will be instancied the properties will be injected as described above
Example:package fr.wedia.confref.custom.processor; import fr.wedia.confres.core.model.processor.*; import com.google.gson.*; import fr.wedia.confres.plugin.PluginLogger; class CustomProcessorWithConfig extends AbstractPostProcessor { private static final List<String> VALUES = Arrays.asList("V1","V2","V3","V4","V5"); /** * this is a debug postprocessor which use a non contextual property (index attribute value) */ @fr.wedia.confres.utils.annot.PostProcessorConfig() private int index=0; private Config config; private List<String> values = VALUES; public void start() { PluginLogger.info(CustomProcessorWithConfig.class,"starting component with config " + config); if ( config!=null ) { if ( config.getValues()!=null ) { PluginLogger.info(CustomProcessorWithConfig.class,"starting component with config " + config.getValues()); values = config.getValues(); } } } @Override String getValue(ProcessorContext context) { return values.get(index); } @Override Collection<String> getAvailableValues() { return values; } @Override String toString() { return this.getClass().getName()+" Groovy:CustomProcessor#"+index+"#"+values; } @Override public boolean equals(Object obj) { return fr.wedia.confres.utils.Utils.equals(CustomProcessorWithConfig.class, this, obj, (o1,o2)-> o1.index==o2.index); } public void setConfig(Config config) { this.config=config; } public static class Config { private List<String> values; public void setValues(List<String> values) { this.values=values; } public List<String> getValues() { return values; } } }
And the configuration:
"connectionState": { "processor": "customprocessors/mypostprocessor.groovy", "plugin": name of the plugin, "index": 2, "config": { "values": ["a","b","c"] } }
Startup
You can execute code right after loading the postprocessor by adding the start()
method.
For example, here is a postprocessor with a JsonElement configuration:
package fr.wedia.confref.custom.processor; import fr.wedia.confres.core.model.processor.*; import com.google.gson.*; import fr.wedia.confres.plugin.PluginLogger; class CustomProcessorJsonElement extends AbstractPostProcessor { private static final List<String> VALUES = Arrays.asList("V1","V2","V3","V4","V5"); private JsonElement config; private List<String> values = VALUES; public void start() { PluginLogger.info(CustomProcessorJsonElement.class,"starting component with config " + config); if ( config!=null && config.isJsonArray() ) { JsonArray jsonArray = config.getAsJsonArray(); List<String> list = new ArrayList<>(); for(int i=0; i<jsonArray.size(); i++) { list.add(jsonArray.get(i).getAsString()); } values = list; } } @Override String getValue(ProcessorContext context) { return ... } @Override Collection<String> getAvailableValues() { return values; } public void setConfig(JsonElement config) { this.config=config; } }
Plugin
If the postprocessor is contributed by a plugin, you can retrieve this plugin by adding a method setPlugin with an argument of type String or com.noheto.plugins.IPlugin
. However, be aware that postprocessors are loaded at the start of the wxm_config_resolver plugin and the contributing plugins are not necessarily started at that time.
Class fr.wedia.confres.core.model.processor.PostProcessorConfig
This class makes it easier to recover a JSON postprocessor configuration.
the method
isList()
tests if the configuration is a list (a JSON array): if true, you can get it withasList()
method, as afr.wedia.confres.core.model.processor.PostProcessorConfigList
.the method
isMap()
tests if the configuration is a map (a JSON object): if true, you can get it withasMap()
method, as afr.wedia.confres.core.model.processor.PostProcessorConfigMap
.
See the JavaDoc of these classes for more information.
Operation
Postprocessors are loaded when the wxm_config_resolver plugin is started. If startup is not possible at that time (error during instantiation, file not found, etc.), the component will not be available until the plugin is restarted.
In any case a postprocessor loaded from a plugin will be invoked (whether the plugin is activated, started or not). Be careful, however, if you invoke plugin classes in the resolution (with a plugin.invoke()
): remember that a plugin cannot be invoked when it is not fully started (and therefore necessarily activated).
In case of an error during the resolution, the postprocessor is ignored and therefore its value is removed from the resolved path.
Services
general information
JSON request parameters
JSON parameters of options (so except data files, but also verbosity, specific parameters like processorValues for example, etc) can use a lenient syntax.
Errors
The error system is basic and only based on the standard HTTP code. It is possible to get an explicit message in debug mode.
Instance reference parameter
When referring to an instance of an object, in particular a user (to set up a surfer for example), we use a parameter of type "instance reference". The valke:
either a uuid
either a uid (object type followed by the object instance id, separated by an underscore, a slash or a dash)
or an id (the type of the object will automatically be the main type by default, for example user, for a surfer)
or, for a surfer/user, the value “notconnected” (case insensitive) to set a not connected surfer
Specific parameters syntax
pathMatcher
The pathMatchers allow to define file filters. The syntax used is based on the Java interface java.nio.file.PathMatcher:
it is either a character string, interpreted as a glob filter by default
if you specify a full PathMatcher syntax, with the prefix glob: or regex:, the string is used as is
if you don’t specify a prefix, the prefix glob; is added automatically
for example{ pathMatcher: '**/^*' }
or a JSON object, with two fields:
type: string/enum (optional, default is glob) the pattern syntax
glob
: for Glob syntaxregex
: for Regular Expressions pattern
pattern: string (mandatory) the pattern
Beware, the handling of the glob syntax may be system dependent, especially regarding case.
get configuration
Gets a final configuration for a mapping ID.
GET /api/portalconfig/config
(operation ID: configGet
)
GET /api/portalconfig/config/merge
(operation ID: configMerge
)
The difference between the two endpoints is that the first one takes no parameters other than the mapping id (and debug). It is intended to retrieve the desired configuration for the requesting surfer (or no surfer). The second one is more for the configuration UX to get different views of the configuration depending on the parameters. The first one is not secured while the second one is.
parameters
mappingID: string (mandatory), the mapping for which we want the configuration
wip: boolean (optional, false by default), activate the “wip” mode (if false, wip/inherit files are ignored, if true, wip/inherit files are taken into account
pathFilter, string/nodePath (optional, none by default), a pathfilter to select nodes (See Filtering)
pathFilterMode, string/enum (optional, FILTER by default), the filter mode (See Filtering)
nodesWithPath, boolean (optional, false by default), (See Filtering)
surfer, instance reference (optional, none by default), a substitute user/surfer to get the configuration that this surfer would have if he called the service. (See Instance reference parameter)
processorValues, JSON/map (optional, none by default), a processor/value association map to obtain the corresponding configuration
For example,{ "surferRole": "role-31" }
options, JSON (optional)
xjson: boolean (options, false by default), true to get the configuration as an xjson
explain configuration
Shows a detailed view of the components of a configuration and how they were obtained.
GET /api/portalconfig/config/explain
(operation ID: configExplain
)
parameters
mappingID: string (mandatory), the mapping for which we want the configuration
wip: boolean (optional, false by default), activate the “wip” mode (if false, wip/inherit files are ignored, if true, wip/inherit files are taken into account
pathFilter, string/nodePath (optional, none by default), a pathfilter to select nodes (See Filtering)
pathFilterMode, string/enum (optional, FILTER by default), the filter mode (See Filtering)
nodesWithPath, boolean (optional, false by default), (See Filtering)
surfer, instance reference (optional, none by default), a substitute user/surfer to get the configuration that this surfer would have if he called the service. (See Instance reference parameter)
processorValues, json/map (optional, none by default), a processor/value association map to obtain the corresponding configuration
options JSON (optional)
xjson: boolean (options, false by default), true to get the configuration as an xjson
verbosity JSON, int or string/enum (optional), determines what information will or will not be exposed
We can configure the verbosityeither by a numerical verbosity level (from 0 to 15)
or by one of the following words:
max
min
default
or by a json which lists the different properties and their values (none is mandatory, all have a default value)
or by a combination of both: in the json, the verbosity property is the level, the other properties allowing to select values different from those of the level.
For example:{ verbosity: default, includesVerbosity: true }
if not specified, the verbosity is
{ "includesVerbosity": false, "includesLocation": true, "includesLayer": true, "includesOverrides": true, "locationVerbose": true, "locationRecursive": true, "pathVerbosity": true, "decomposePaths": false, "decomposePathsVerbose": true, "includeNodePath": true, "includeJsonPath": true, "includeXJsonPath": true, "nameVerbosity": true, "includesIgnored": true, "groupsIgnoredInRoot": true, "ignoredLocationVerbose": true, "includesErrors": true, "groupsErrorsInRoot": true, "errorVerbose": true, "exceptionVerbose": true, "exceptionDepth": -1, "stackTraceVerbosity": 2 }
here is the default json for the verbosity (value
default
or 3){ "includesVerbosity": false, "includesLocation": true, "includesLayer": true, "includesOverrides": true, "locationVerbose": false, "locationRecursive": false, "pathVerbosity": true, "decomposePaths": false, "decomposePathsVerbose": false, "includeNodePath": false, "includeJsonPath": false, "includeXJsonPath": false, "nameVerbosity": false, "simpleName": true, "includesIgnored": true, "groupsIgnoredInRoot": false, "ignoredLocationVerbose": false, "includesErrors": true, "groupsErrorsInRoot": false, "errorVerbose": false, "exceptionVerbose": false, "exceptionDepth": 0, "stackTraceVerbosity": 0 }
The meaning of the properties
includesVerbosity, boolean (optional, default is false): If true, include the verbosity configuration in the response
includesLocation, boolean (optional, default is true): if true, locations are included in the response
includesLayer, boolean (optional, default is true): if true, layer (location root folder) are included in the response
includesOverrides, boolean (optional, default is true): if true, overridden elements are included in the response
locationVerbose, boolean (optional, default is true): if true, the locations are exposed with a maximum of information
locationRecursive, boolean (optional, default is true): if true, the locations are exposed with their parent, recursively
pathVerbosity, boolean (optional, default is true): if true, the paths of the locations are exported with a maximum of verbosity
decomposePaths, boolean (optional, default is false): if true, the path decomposition of the locations is exported (how these paths were built, in particular which postprocessors were used and their value)
decomposePathsVerbose, boolean (optional, default is true): if true, the path decomposition of the locations is in maximum verbosity
includeNodePath, boolean (optional, default is true): if true, the nodepaths of each element are exported
includeJsonPath, boolean (optional, default is true): if true, the JSONpaths of each element are exported
includeXJsonPath: boolean (optional, default is true): if true, the XJSONpaths of each element are exported
nameVerbosity, boolean (optional, default is false): if true, the names are exported in maximum verbosity (in particular, we get the details of the type of name: if it is a wip, an inherit, an array, etc)
simpleName, boolean (optional, default is true): if true, the name doesn’t include decorations( wip, inherit, array…).
includesIgnored, boolean (optional, default is true): if true, files found but ignored are exported, with the reason for ignoring them
groupsIgnoredInRoot, boolean (optional, default is true): if true, the ignored files are grouped at the root, if false, they are exported at the level where they were detected
ignoredLocationVerbose, boolean (optional, default is true): if true, ignored files are exported with maximum verbosity
includesErrors, boolean (optional, default is true): if true, the files or folders whose reading triggered an error are exported
groupsErrorsInRoot, boolean (optional, default is true): if true, the files in error are grouped at the root, if false, they are exported at the level where they were detected
errorVerbose, boolean (optional, default is true): if true, files with errors are exported with maximum verbosity
exceptionVerbose, boolean (optional, default is true): if true, the exceptions encountered are exported with a maximum of verbosity
exceptionDepth, int (optional, default is 0): defines the depth of the causes of the exceptions (0 corresponds to no cause)
stackTraceVerbosity, int (optional, default is 0): defines the verbosity level of the stack traces
configuration merge and explain tests
It is possible to test the config merge and config explain services without having any configuration, mapping, processors, etc.
The config/test service allows you to test the merging of several Jsons (or XJsons) by obtaining either a merge response or an explain response.
GET /api/portalconfig/config/test/merge
to make a merge
GET /api/portalconfig/config/test/explain
to make an explain
GET /api/portalconfig/config/test
also works, with the parameter explain (operation ID: configTest
)
parameters
The parameters are a combination of the parameters found in the services config/merge, config/explain and xjson/to and xjson/from.
json, string or file, (at least one is mandatory), that contains JSon (or XJSon), multiple values allowed (JSon lenient parsing is not supported)
xjson, boolean, optional (default is false). If true, if the jsons passed in parameter must be considered as xjson, false, otherwise (not to be confused with the xjson option which controls how the response json is formed)
lenient, boolean, optional (default is false). If true, the xjsons passed in parameter must be processed as lenient
explain, boolean optional (default is false). If true, the result is an explain, if false, the result is a merge. (works only with end point
/test
)locations, optional
This parameter allows to give location names to each JSon. Indeed, as there is no corresponding physical location (no files or folders), a virtual location is generated with just an incremental index (from 1 to n, and Root for root). This parameter allows to name the layers.either by a JSon array (example:
locations=[_base,_base@test]
)or by strings (example
...&locations=_base&locations=_base%40test&...
)
pathFilter (see get configuration and explain configuration)
pathFilterMode (see get configuration and explain configuration)
nodesWithPaths (see get configuration and explain configuration)
options (see get configuration and explain configuration)
verbosity, only if explain (see get configuration and explain configuration)
processors list
Gets processors list (variable names)
GET /api/portalconfig/postprocessors/list
(operation ID: postProcessorsList
)
parameters
mappingID: string (optional), designates a particular mapping (filter)
postProcessor: multiple strings or comma-separated (optional), designates a particular post processor, or a list of post processors (filter)
(you can have several times the parameter, or list several postProcessor in the same parameter, separated by commas)options: a JSON object (optional), defines options
withMappings: (default false) allows to have the list of mappings that use the postprocessor
withValues: (default false) allows to have the list of mappings that use the postprocessor
processors value
Gets post processor value for the current context
GET /api/portalconfig/postprocessors/value
(operation ID: postProcessorsValue
)
parameters
mappingID: string (mandatory) the mapping ID
postProcessor multiple strings or comma-separated (optional), designates a particular post processor, or a list of post processors (filter)
(you can have several times the parameter, or list several postProcessor in the same parameter, separated by commas)surfer: string, as UUID, UID, ID… (optional), a particular user for whom we want the resolution
options: a JSON object (optional), defines options
withMappings (false)
withValues (false)
all paths
Gets all possible paths for a mapping to resolve a configuration.
GET /api/portalconfig/path/all
(operation ID: pathAll
)
parameters
mappingID string (mandatory), the mapping ID
options a JSON object (optional), defines options
explain boolean (optional)
true: gives the details of each part of the paths, with the source of the postprocessors and values that determined them
false (or absent): no details (default behavior)
withFileInfo (optional) boolean
sizeOfDirectory boolean (optional, default is true) if true, the size of a folder is calculated by adding the size of all the files in it. If false, it is the size of the file-folder.Files and directories
filter JSON object (optional)
This filter allows you to select files according to criteria. It is defined as a JSON with the following properties:withBase boolean (optional)
if true, base config is included in response
if false, base config is not included in response
if absent or null, has no effect
exists boolean (optional)
if true, configuration files that do not exist aren’t included in the response
if false, configuration files that exist aren’t included in the response
if absent or null, has no effect
postProcessors (optional) string, or array of strings (A list of post processor names)
Only the paths that have been determined from the listed processors are included in the response.postProcessorValues (optional) JSON object/map
Allows to get only the paths that contain certain values of post processors.keys are post processors names
values (string, or array) are the list of values from the post processors for which a path will be included in the response
resolve paths
Gets all possible full paths for a mapping. The difference with “all paths” is that we only have the final folders (those that correspond to the evaluation of postprocessors in the context).
GET /api/portalconfig/path/resolve
(operation ID: pathResolve
)
parameters
mappingID, string (mandatory): the mapping ID
options, JSON (optional)
explain boolean (optional, default is false) if true, expose details on each paths
withFileInfo boolean (optional, default is false) if true, informations on files are included (size and length)
sizeOfDirectory boolean (optional, default is true) if true, the size of a folder is calculated by adding the size of all the files in it. If false, it is the size of the file-folder.Files and directories
filter, JSON (optional)
This filter allows you to select files according to criteria. It is defined as a JSON with the following properties:withBase, boolean (optional, default is false)
if true, base config is included in response
if false, base config is not included in response
if absent or null, has no effect
exists boolean (optional, default is false)
if true, configuration files that do not exist aren’t included in the response
if false, configuration files that exist aren’t included in the response
if absent or null, has no effect
postProcessors (optional) string, or array of strings (A list of post processor names)
Only the paths that have been determined from the listed processors are included in the response.postProcessorValues (optional), JSON object
Allows to get only the paths that contain certain values of post processors.keys are post processors names
values (string, or array) are the list of values from the post processors for which a path will be included in the response
mappings
Gets list of existing mappings
GET /api/portalconfig/mappings
(operation ID: mappingsGet
)
The configuration is stored in folders and files that will be merged to obtain a final configuration. A base is provided by the product and it is possible to create new files that will successively redefine this base.
A configuration is finally accessed by an identifier. For each identifier, we define a configuration path, consisting of the paths of the different folders or configuration files, separated with the character arobase (@
) that will successively overload the database. The combination of the two is called mapping.
parameters
options, JSON (optional)
withStatus, boolean (optional, default is false)
Expose status of mapping:OK: the mapping is existing and is valid
NO_FILE: the mapping exists but no base file has been found
INVALID: the configuration of the base path is invalid (probably the folder is outside the specific base location)
VARIABLE: the path associated to mapping is variable. This service could not handle variable bases.
withFileInfo, boolean (optional, default is false) if true, informations on base files are included (size and length)
sizeOfDirectory, boolean (optional, default is true) if true, the size of a folder is calculated by adding the size of all the files in it. If false, it is the size of the file-folder.Files and directories
containers
Gets a list of containers (configuration layers root directory)
GET /api/portalconfig/containers
(operation ID: containersList
)
parameters
pathMatcher (optional)
A filter to select containers. See pathMatcher.options, JSON (optional)
withRights, boolean, (optional, default is true)
If true, we expose the writing rights in this containeronlyIfExists, boolean, (optional, default is false)
If true, we expose that the containers that physically existwithMappings, boolean, (optional, default is false)
If true, we expose the list of mappings that include the layer stored in this containerwithInfo, boolean (optional, default is false)
If true, we expose some information about the container:exists, a boolean: if true, the container physically exists
var, a boolean: if true, the container name has been calculated by postprocessors
restarting, a boolean: if true, the container name is relative (it has been cut by a $ during its resolution)
withFileinfo, boolean (optional, default is false)
If true, we expose the last modification date and the size of the container (if it exists)sizeOfDirectory, boolean (optional, default is false)
If true, the size of the folder is the total size of all the files it contains (otherwise, this information is what thejava.nio.file.Files.size()
method returns)outOfMappings, boolean (option, default is false)
if true, also retrieves the containers that are not used by a mapping (so all folders created in the configuration storage folder)
This service can be used to know if a container is used in a mapping. For example to know if _portal@role-4
is used in a mapping:
pathMatcher=_portal@role-4
options
withMappings=true
outOfMappings=true
diff
Compares two JSON. The result is a list of differences.
GET/POST /api/portalconfig/diff
(operation ID: jsonDiff
)
Parameters
leftJson, JSON descriptor (mandatory), a JSON to compare to rightJson
rightJson, JSON descriptor (mandatory), a JSON to compare to leftJson
processorValues, JSON/map (optional), a default set of processor values
options, JSON (optional),
JSON descriptor
Describes the reference JSON to compare the other to (left), or the JSON to compare to the reference (right).
It is a JSON object (It can be a string of characters. In this case, it will automatically be the mapping type and the string is the mapping ID). The type field indicates the type of descriptor. Here are the different values for type:
json
In this case, the json field (mandatory) contains the JSON value to compare.
Example:{ "type":"json", "json": { "a": 1, "b": true, "c": "abc" } }
xjson (optional, default is false) if true, the JSON is a XJSON, if false the JSON will be converted to XJSON to compute differences.
form
In this case, the field field (mandatory) contains the name of the form field that contains the JSON (file or string)
Example:{ type: form, field: json1, xjson: true }
xjson (optional, default is false) if true, the JSON is a XJSON, if false the JSON will be converted to XJSON to compute differences.
mapping
References a mapping.mappingID, string (mandatory), the mapping ID
wip, boolean (optional, default is false): true activates the wip mode
processorValues, JSON/map (optional, none by default) a set of processor values
surfer, instance reference (optional, none by default), a surfer
config
References a configuration containerIn this case, the path field (mandatory) is the path of the configuration container
Example{ type: config, path : '_portal@club-wed@role-4' }
base
References a configuration baseIn this case, the mappingID field is the mapping for which we want the base
Example{ type: base, mappingID: portal }
dir
To get a filesystem view of a configuration folder.
GET /api/portalconfig/fs/dir
(operation ID: dir
)
Parameters
path string (mandatory): the path of the desired container (a configuration path)
for exemple,_portal@club-wed@role-4
subpath, string (optional): a path relative to the container
for example,boardsview
verbosity, JSON (optional):
includesFileInfos, boolean (optional, default is true): exports dates and file sizes
includesFileCounters, boolean (optional, default is true): exports the number of files and folders
options, JSON (optional):
depth: int (optional, default is -1=infinite depth)
pathMatcher: (optional) defines a filter on paths and file names. The filter is applied to the relative path and name: if it matches one of the two, then the file or folder is exported, and those that do not match one of the two are not. See pathMatcher.
merged dir
To get a filesystem oriented view of a set of configuration folders corresponding to a mapping resolution, in a merged way.
GET /api/portalconfig/fs/dir
(operation ID: dirMerged
)
Parameters
path: string, multiple (mandatory, if mappingID is not present): a list of paths (base or configuration containers). If mappingID is also present, it’s used as an inclusive filter. If mappingID is not present, it's the list of paths to get.
mappingID: string (mandatory, if path is not present), the mapping for which we want the configuration
wip: boolean (optional, false by default), activate the “wip” mode (if false, wip/inherit files are ignored, if true, wip/inherit files are taken into account
surfer, instance reference (optional, none by default), a substitute user/surfer to get the configuration that this surfer would have if he called the service. (See Instance reference parameter)
processorValues, JSON/map (optional, none by default), a processor/value association map to obtain the corresponding configuration
For example,{ "surferRole": "role-31" }
maxLayers, int (optional, default is -1=infinite): only if mappingID present and resolve true, limits the numbers of paths
resolve, boolean (optional, default is true): only if mappingID present, if true, resolve the configuration layers against the context (so get only the involved paths), if false, get all possible paths
verbosity, JSON (optional):
includesErrors, boolean (optional, default is true): export the files or directories that caused read errors
includesIgnored, boolean (optional, default is true): export the files or directories ignored during the resolution of a mapping
includesNotFound, boolean (optional, default is true): export the configuration container folders that do not exist
includesFileInfos, boolean (optional, default is true): exports dates and file sizes
includesFileContent, boolean (optional, default is true): exports the content of files
options, JSON (optional):
depth: int (optional, default is -1=infinite depth)
pathMatcher: (optional) defines a filter on paths and file names. The filter is applied to the relative path and name: if it matches one of the two, then the file or folder is exported, and those that do not match one of the two are not. See pathMatcher.
Lock services
These services allow you to obtain a lock that allows you to call the configuration creation or modification services (and configuration files). Once the lock is obtained, other users cannot obtain one until it is released or expired.
Comming soon: locks per layer, by the container (or layer) parameter
lock
POST /fs/lock
(operation ID: lockPut
)
Put an exclusive access lock (if not already owned).
Response
Http status | |
---|---|
200 | The lock has been obtained or extended |
403 | Unable to obtain a lock (already owned, or error) |
503 | Locks are unavailable |
500 | Other errors |
unlock
DELETE /fs/lock
(operation ID: lockDelete
)
Delete the owned lock.
Response
Http status | |
---|---|
200 | Lock deleted |
202 | No lock |
403 | Lock not owned |
500 | Other errors |
get lock
GET /fs/lock
(operation ID: lockGet
)
Test if lock is owned (and extend it)
Http status | |
---|---|
200 | Lock is owned and extended |
202 | Lock not owned (free) |
403 | Lock is owned by some body else (other surfer or other session) |
503 | Locks are unavailable |
500 | Errors |
Auto locking
Any service that creates, modifies or deletes configuration files automatically creates a lock (enableable/disableable by plugin configuration).
Lock live time
Lock live time is configurable in plugin configuration (by default 60s).
Enable/disable
This feature is disableable by plugin configuration.
Command submission⚠️
Services that may fail due to lack of lock availability can be run in batch with guaranteed execution. When the execution fails because of the lock system, the execution is retried later.
At invocation, a set of commands is specified, each command corresponding to a service invocation. The service returns a command identifier and the current status of each command. It is possible to query this status via the command set identifier at any time until complete. Completed command sets are kept for a limited time. If the status of an unknown order set is requested (unknown id, or retention time exceeded), a done status will be obtained, without details per command
There is a guarantee of order execution of a set of orders, but no guarantee of order execution of a set of orders.
The parameter value that describes the command set is a JSON (lenient syntax).
Description of a set of commands
A set of commands is described by a JSON array of commands. A single command can be described directly (out of an array).
Any value other than an array or object (command description) will result in an empty command set.
Description of a command
A command is described by a JSON object with the following properties:
name: string, mandatory (if missing, command is ignored, if not corresponding to an executable service, command is ignored), name of command. See the documentation of each service to have the associated command name (services that do not have one are not executable by this service).
It is also possible to use the API operation ID.parameters: mandatory, parameters for the command
This can bean object for which each property corresponds to a parameter (value of property is parameter name), and the associated value describes the values for that parameter
an array of objects with the following properties (values are grouped by identical name)
name: name of parameter
values: values of parameter
value: single value of parameter
The values of a parameter are defined either
as an array of values
in the form of a value of another type than array if the value is unique
The value of the value property is always treated as a single value.
A value can be specified either as a string (as it would be passed when invoking the service directly), or as a JSON type compatible with the expected value (for example, a JSON object for an options parameter).
The parameter names are the same as for the corresponding services.
Examples
{ name: 'FS/CONTAINER/WRITE', parameters: { container: '_portal@test@role-4' } }
[ { id: 'writeMainContainers', name: 'FS/CONTAINER/WRITE', parameters: { container: ['_portal@test@role-4','portal@test@role-14'] } }, { id: 'role_4_displayNaturalSearch' name: 'FS/FILE/WRITE', parameters: { container: '_portal@test@role-4', path: [home,displayNaturalSearch], content: true, options: { mkDirs: true } } }, { id: 'role_14_displayNaturalSearch' name: 'FS/FILE/WRITE', parameters: [ { name: container, values: '_portal@test@role-14' }, { name: path, values: [[home,displayNaturalSearch]] }, { name: content, values: false }, { name: options, values: { mkDirs: true } } ] }, { id: 'role_16_displayNaturalSearch' name: 'FS/FILE/WRITE', parameters: [ { name: container, value: '_portal@test@role-16' }, { name: path, value: [home,displayNaturalSearch] }, { name: content, values: false }, { name: options, values: { mkcontainers: true, mkdirs: true, clear: true } } ] } ]
Response
Timeout
Service to submit a command set
POST /fs/command
(operation ID: commandSubmit
)
parameters
commands, mandatory, description of commands (see above)
timeout, optional (default 0), maximum waiting time in seconds for service response
You can specify unit (as ms, s, m(for minute)). For examples: 45s
, 45000 ms
, 0.75m
...
options
none
Service to get state of a command set
GET /fs/command
(operation ID: commandStatus
)
parameters
id, mandatory, command id
timeout, optional (default 0), maximum waiting time in ms for service response (ignored if commandset is finished, or not found)
options
none
Runtime system configuration
The job manager is configured by the command_submit_manager_config parameter in the WXM_CONFIG_RESOLVER plugin configuration which is a JSON object with the following properties:
threadCount: number (int), optional (default is 3, minimum is 1),
the number of allocated threadskeepOldJobTime: number (long), optional (default is 30000, minimum is 0),
the maximum retention time of a set of commands (after execution), in msmaxOldJobCount: number (int), optional (default is 1000, minimul is 0),
the maximum number of command sets retained after they have been completed
Modify or create configuration properties
These are services to modify the configuration without manipulating files (without using basic file operations).
Operations
General
With a few exceptions, these services operate on the same principle.
For write services, a configuration can be specified either as an XJSON (lenient) or as a list of paths (XJSONPATH), always in a specified configuration container (layer). If a path is specified together with an xjson, the path must be unique and constitute the complete path to the property being written. If the path is omitted, the root of the configuration container is addressed. You can write either configuration, wip files or delete files, but not all three at the same time in one call: this is handled by two boolean parameters named delete and wip.
In the XJSON, as in the paths, we do not put a file extension. The XJSON is called lenient because it accepts JSON arrays: in this case, the XJSON object is evaluated automatically (indexes are assigned automatically), and the property name does not have to end with empty brackets ([]
). In writing, only what is described in the XJSON is written, without modifying the other properties (but the properties referenced by the XJSON are well replaced: all siblings files for the property are deleted). The option merge allows you to specify that you want to delete the properties that are not described in the json.
Patch configuration properties with a XJSON
To patch a configuration layer with an XJSON, use
service:
POST fs/config
(operation ID:configWrite
)parameters
content (mandatory): the XJSON
container (mandatory): the layer container name
path (optional): an xjsonpath target subpath
Patch configuration delete files by paths
To patch a configuration layer with delete files, use
service:
DELETE fs/config
(operation ID:configDelete
)parameters
content: none
container (mandatory): the layer container name
path (at least one): one or several xjsonpath
Replace configuration properties with a XJSON
To patch a configuration layer with an XJSON, use
service:
POST fs/config
(operation ID:configWrite
)parameters
content (mandatory): the XJSON
container (mandatory): the layer container name
path (optional): an xjsonpath target subpath
options
merge: false
Delete configuration (write delete files and/or remove files) with a XJSON
To patch a configuration layer with an XJSON, to delete configuration properties of the above layers or remove configuration properties from this layer, use
service:
DELETE fs/config
(operation ID:configDelete
)parameters
content (mandatory): the XJSON
In that mode, the XJSON is not lenient, because arrays are used to specify the mode. In this array, specify the desired options amongDELETE (or D, or DEL, insentive case)
to write a file with delete suffixREMOVE (or R, or REM, insentive case)
to remove the property
for example:{ a: [delete], b: [remove], c: [delete, remove] }
the file a.delete will be created
all the files and directories for the property b will be removed
all the files and directories for the property c will be removed, then the file c.delete will be created
container (mandatory): the layer container name
path (optional): an xjsonpath target subpath
Service to write configuration
POST fs/config
(operation ID: configWrite
)
Command name: fs/config/write
This service allows to modify (patch or replace) the configuration in a container, or in a subfolder of a container.
Parameters
container, (see Basic file operatirons/Parameters for details), mandatory
denotes the configuration containerpath, (see Basic file operatirons/Parameters for details), optional, can be single or multiple, depending on the presence of content
specifies the relative xjsonpath (to the configuration container) where to writecontent, string or file(multipart/formdata), optional
The XJSON (lenient) to write. If this parameter is not specified, multiple paths can be specified. If this parameter is specified, only one path or none can be specified (in this case, we write directly to the container)wip, boolean, optional(default is false)⛔
True to write to wip datadelete, boolean, optional(default is false)⛔
True to write delete overrides. In this mode, the primitive values in the xjson (if present) are ignored.options, JSON with the following properties
merge, boolean, optional (true by default)
True to keep the other properties already existing in the namespace we are writing. If false, All other properties in the written namespace will be removedFor example, the name space is currently
/a /b /c c1.json = "c1" c2.json = "c2" /d d1.json = "d1"
We write this XJSON:
{ "a": "b": { "c": { "c2": "c2>modified", "c3": "new" } } } }
With merge=true, the result is
/a /b /c c1.json = "c1" c2.json = "c2>modified" c3.json = "new" /d d1.json = d1
With merge=false, the result is
/a /b /c c2.json = "c2>modified" c3.json = "new"
mkContainers, boolean, optional(false by default)
True to create container if it doesn’t existskeepFormat, boolean, optional(false by default)
By default, only JSon is written to files (or empty content for .delete files). If keepFormat is true, and the JSon value is string, and the target file is already existing, the original format (from the suffix) is kept.
Example
Here the current file system:/a /b /c c1.json = "c1" c2.txt= c2 /d d1.json = "d1"
XJSON to write:
{ "a": "b": { "c": { "c1": "c1>modified", "c2": "c2>modified" } } } }
Result with keepFormat=false
/a /b /c c1.json = "c1>modified" c2.json = "c2>modified" /d d1.json = "d1"
Result with keepFormat=true
/a /b /c c1.json = "c1>modified" c2.txt= c2>modified /d d1.json = "d1"
keepDelete, boolean (optional, true by default)
when a property is written, the files concerning this same property are deleted (the writing constitutes a replacement). This option indicates how the file with the delete extension is to be considered during this replacement: by default, it is not deleted (keepDelete=true). You can force the deletion by setting keepDelete to false.keepProperty, boolean (optional, true by default)
when you write .delete files in path mode, the files concerning the same property aren’t deleted. You can force deletion by setting keepProperty to false.
Delete (erase or write delete files)
DELETE fs/config
(operation ID: configDelete
)
Command name: fs/config/delete
container, (see Basic file operatirons/Parameters for details), mandatory
denotes the configuration containerpath, (see Basic file operatirons/Parameters for details), optional, can be single or multiple, depending on the presence of content
specifies the relative xjsonpath (to the configuration container) where to writecontent, string or file(multipart/formdata), optional
The XJSON to write. If this parameter is not specified, multiple paths can be specified. If this parameter is specified, only one path or none can be specified (in this case, we write directly to the container).
This XJSON is not lenient. Arrays are used to specify the operation (see details in the paragraph Delete configuration (write delete files and/or remove files) with a XJSON):DELETE
REMOVE
wip, boolean, optional(default is false)⛔
True to write to wip dataoptions, JSON with the following properties
deleteNotEmpty, boolean (optional, true by default)
if false, REMOVE option is not applyed on not empty directoriesmkContainers, boolean (optional, false by default)
Push
Commit
Rollback
Basic file operations
These are file manipulation operations, with minimal controls. An operation (a service call) is performed exclusively. Other concurrent operations are put on hold until the current operation is completed, or possibly rejected after a timeout.
Parameters
container, a string
denotes the configuration container (e.g._portal@club-wed@role-4
)path
specifies the relative path (to the configuration container) of the file. The suffix can be omitted: in this case, the best matching file will be used.string
There is no automatic escape or conversion: the value will be used as is. Slashes and backslashes can be used interchangeably and their successions are ignored. You can escape slashes o backslashes with a backslash before.
The path can't be an empty string or only made of spaces.
For examples:home/display-natural-search.json
home/display-natural-search
JSON array
Each value of the array is escaped (the method that is used isUtils.camel2Kebab()
(see Test.jsp), according to the rules indicated here). Then the path is reconstructed by joining these values, separating them with a slash. The JSON lenient syntax is supported. Values can be a string or an array of one string (in that case, the string is not escaped).
For examples:[home,[display-natural-search]]
[home,displayNaturalSearch]
JSON object
property path (mandatory)
string
JSON array
property suffix, string, the suffix of the file (optional, if ommited, the best matching file will be used)
property escape, boolean (optional, default is true)
if true, parts of file path will be escaped or converted.
The processing may differ depending on the type of service:
in file manipulation services, the path is considered to refer to file names. The escape/conversion is done with
Utils.camel2Kebab(input)
. Slashes or backslashes are used in string paths for splitting: to escape them you can use the character backslash or bracket escape sequence.in configuration manipulation services, the path is considered to refer xjson names. The escape/conversion is done with
Name.fromJsonName(input).toFileName()
. Slashes or backslashes are used in string paths for splitting: to escape them you can use the character backslash or bracket escape sequence.
pathMatcher
A path matcher, that uses the same syntax as pathMatcher (see pathMatcher), with an additional property in its object form:onlyName, boolean (optional, false by default)
If true, the filter is only applied to the file name.
content
The file contenta file (multipart/form-data)
a string
contentType
Indicates under which type (the value can be a MIME type or a file suffixe) the content provided by the content parameter should be considered. If
If there is no contentType parameter, it will be evaluated:either by analysis of the file suffixe when content is a file
or by a short analysis of the text if content is a string
if text is empty, it’s an empty file
if text is not empty,
we try to parse it as JSON (not lenient). If it doesn't parse, we go to the next step. If it doesn't make an error, we consider the content as JSON
Otherwise, it is plain text.
ignored files are supported only in the path: the file in multipart/form-data must have the true extension
options
A JSON object (lenient). All properties are optional with specific default values depending on the type of operation.
Best matching file
When reading (or for deletions), when it is not explicit, we determine the most suitable file extension by analyzing the existing files on the disk.
When writing, the contentType is used.
Read file
GET/HEAD /api/portalconfig/fs/file
(operation ID: fileGet
)
This service allows you to read a file (its content). This service does not allow to retrieve the content of a folder (use the dir service for that).
Parameters
container, mandatory, single value
path, mandatory, single value
Options
lookForBestMatching
, boolean (optional, true by default)
If false, disable looking for best matching file (suffixe becomes mandatory)
Response
The content of the file is returned in the body of the response, with the status 200. If the file is empty, a status 204 (No Content) is returned, with no body. The Content-Type header gives the type of content. The Content-Length header gives its size.
Write file
POST/PUT /api/portalconfig/fs/file
Command name: fs/file/write
This service allows you to write a file (create or replace) or create a directory.
You can't create just any file:
If a non-empty content is present, the file is a text file of one of the following types:
plain text
The suffix must betxt
(ortext
) (or specify the typetext/plain
)HTML
The suffix must behtm
(orhtml
) (or specify the typetext/html
)JSON
The suffix must bejson
(or specify the typeapplication/json
)ignored file are supported
if empty content is present, the file will be an empty file of one of the following types:
delete
The suffix must bedelete
ignored files are supported
if no content is present, the file will be a directory
Parameters
container, mandatory, single value
path, mandatory, single value
content, the file content if any
contentType, the content type
Options
replace
, boolean (optional, false by default)
If false, if the file already exists, the operation returns an error. If true, the existing file (or directory) is replaced.mkdirs
, boolean (optional, false by default)
If false, if the directory doesn’t exists, the operation returns an error. If true, the directories are created.mkcontainers
, boolean (optional, false by default)
If false, if the container doesn’t exists, the operation returns an error. If true, the container directory is created.clear
, boolean (optional, false by default)
Other files with the same base name in the same directory will be deleted automatically.
Delete file⛔
DELETE /api/portalconfig/fs/file
(operation ID: fileDelete
)
This service allows you to delete files or directories.
Command name: fs/file/delete
Parameters
container, mandatory, single value
path, multiple values
pathMatcher, mutiple values
options
recursive
onlyDir
onlyFile
onlyContent
At least one path or one pathMatcher must be specified.
Create containers
POST /api/portalconfig/fs/container
Command name: fs/container/write
(operation ID: containerWrite
)
This service allows you to create one or several container (root configuration directories)
Parameters
container, mandatory, multiple values
Response
The response, when no error is returned, is a JSON array of objects with the following properties:
container: the name of the container
state: the state among:
INVALID: the container name contains invalid characters
BASE: the container name is identified as the base name
VARIABLE: the container name is identified as being dependent on variables (postprocessors)
ALREADY_EXISTS: a container of this name already exists
CREATED: the container has been created
ERROR: There was an error when creating the container
If at least one container has been created, the code 201 is returned. If all creations have failed, the code 400 is returned. Otherwise code 200 is returned.
Example
[ { "container": "_portal@testcreate", "state": "ALREADY_EXISTS" }, { "container": "_portal@testcreate1", "state": "ALREADY_EXISTS" }, { "container": "_portal@testcreate2", "state": "CREATED" } ]
Errors
Some errors are not raised in error if there are several container names. In this case, see the state property in the response.
HTTP status | When | State when several containers |
---|---|---|
400 - Bad request | no container name (missing mandatory parameter) | |
400 - Bad request | a container name is a base | BASE |
400 - Bad request | a container name contains forbidden char (slash, backslash, dollars, or file forbidden chars) | INVALID |
500 - Internal Server error | An error occurred while creating the container | ERROR |
Example
curl --request POST \ --url 'http://<host>/api/portalconfig/fs/container?container=_portal%40testcreate&container=_portal%40testcreate1&container=_portal%40testcreate2'
curl --request POST \ --url http://<host>/api/portalconfig/fs/container \ --data container=_portal@testcreate \ --data container=_portal@testcreate1 \ --data container=_portal@testcreate2
Delete containers⛔
DELETE /api/portalconfig/fs/container
(operation ID: containerDelete
)
Command name: fs/container/delete
This service allows you to create one or several container (root configuration directories).
Parameters
container, mandatory, multiple values
options:
recursive: boolean, default is false
if false, deleting a non-empty container will cause an error. if true, a non-empty container will be deleted with all its contents.
Response
The response, when no error is returned, is a JSON array of objects with the following properties:
container: the name of the container
state: the state among:
INVALID: the container name contains invalid characters
BASE: the container name is identified as the base name (not deletable)
VARIABLE: the container name is identified as being dependent on variables (postprocessors)
NOT_FOUND: a container of this name hasn’t been found
DELETED: the container has been deleted
NOT_EMPTY: the container can’t be deleted because it’s not empty
ERROR: There was an error when deleting the container
Rename container
TO DOCUMENT
Convert JSON to XJSON
GET/POST /api/portalconfig/xjson/to
(operation ID: xjsonTo
)
Parameters
json: JSON or JSON file (multipart/form-data)
Convert XJSON to JSON
GET/POST /api/portalconfig/xjson/from
(operation ID: xjsonFrom
)
Parameters
json: JSON or JSON file (multipart/form-data)
lenient: boolean (optional, false by default). If true, non xjson structures (like arrays) do not cause errors.
Cache generation
POST /api/portalconfig/cache/flush
(operation ID: cacheFlush
)
Regenerate cache from current configuration directories state
Cache status
GET /api/portalconfig/cache
(operation ID: cacheStatus
)
Get cache status
Info
GET /api/portalconfig/info
(operation ID: info
)
Get some information about the plugin.
Response
version, version of the plugin
env, type of environment, among
DEV
PROD
PREPROD
security, true, if security is enabled
status, plugin status
label, status of the plugin, among
OK
Startup error
Startup
Shutdown
Shutting down
code, status code color, among
GREEN
YELLOW
RED
Filtering
Path
JSON filtering is done by path. A path is defined as a sequence of :
field names
array cell indexes between bracket
separators, as slash (
/
)
A path can be absolute or relative. An absolute path always starts with a separator (so a slash). If the path does not start with a slash, it is relative. Field names are separated by a slash. Array indexes are not.
Examples :
{ "a": 1, "b": 2, "c": { "d": 3, "e": 4, "f": 5 }, "d": [ 6, 7, 8 ] }
The value 1 has absolute path
/a
;The value 4 has absolute path
/c/e
;The value 7 has absolute path
/d[1]
.
{ "a": { "c": 1, "d": 2, "e": 3, }, "b": { "c": 3, "d": 4, "e": 5, }, "c": { "c": 6, "d": 7, "e": 8, } }
The values 2, 4 and 7 have relative paths
d
.
{ "a":[ [1,2], [3,4], [5,6] ] }
The value 3 has absolute path
/a[1][0]
.
{ "a":[ { "b": 1, "c": 2, }, { "d": 3, "e": 4, } ] }
The value 3 has the absolute path
/a[0]/d
.
Multipath
You can combine several paths by one or, by separating them with a pipe (|
).
/a/b|/a/c
will select the elements corresponding to the paths/a/b
and/a/c
;/a/b||0]
will select the elements corresponding to the paths/a/b
and[0]
.
Escaping
To escape a reserved character, use a backslash (\
).
Reserved characters:
slash (
/
)opening bracket (
[
)closing bracket
(]
)pipe (or) (
|
)antislash (escape character) (
\
)
Syntax tolerance
It is preferable to respect the syntax scrupulously, but some syntaxes are tolerated and will be converted automatically.
slash before an array index is useless and will be ignored.
/a/[0]
will be replace by/a[0]
slash is mandatory between an array index and before a fieldname, but could be ommited.
/[0]a
will be replaced by/[0]/a
.brackets must be escaped if then don’t define an array index (so if characters between brackets aren’t only digits), but you can avoir to escape them (the opening, the closing or the both).
/a[b]c
will replaced by/a\[b\]c
./a[b\]c
will be replaced by/a\[b\]c
./a\[b]c
will be replaced by/a\[b\]c
.array indexes are defined in square brackets with numbers and only numbers. Any other character will cause them to be considered part of a field name.
[0]
is an array index and[ 0 ]
is a field name. If it is necessary to reference a field name that contains a number part in square brackets, it will be necessary to escape the square brackets so that it is not considered as an array index.
Filtering a JSon
You can retrieve a part of a JSON by a path.
For example, for this JSON :
{ "a": { "b": 1, "c": 2, "d" : { "e": { "f": 3, "g": 4 }, "h": { "i": 5, "j": 6 } } }, "k": [7,8,9], "l": { "m": 10, "n": 11 } }
with the path
/a/d/h
you can retrieve the following part:{ "i": 5, "j": 6 }
with the path
/k
, you will retrieve the following part:[7,8,9]
Filtering mode
There are two filtering modes:
FILTER (by default)
NODE
NODES
PATHS
In the FILTER mode, you will get a version of the JSON in all its depth, with only the elements corresponding to the filter.
In NODE mode, you will get the first element selected by the filter
In NODES mode, you will get an array of elements corresponding to the filter
in PATHS mode you will have the same result as in NODES mode, without the node information, and with nodeWithPaths
implicitly set to true (the value is ignored), i.e. the paths part of NODES mode with nodeWithPaths=true
.
For example, with the following JSON and path /a/d/h
{ "a": { "b": 1, "c": 2, "d" : { "e": { "f": 3, "g": 4 }, "h": { "i": 5, "j": 6 } } }, "k": [7,8,9], "l": { "m": 10, "n": 11 } }
you'll get the following result in FILTER mode:
{ "a": { "d": { "h": { "i": 5, "j": 6 } } } }
you’ll get the following result in NODE mode:
{ "i": 5, "j": 6 }
you’ll get the following result in NODES mode:
[ { "i": 5, "j": 6 } ]
with the path
b|c
, you'll get in FILTER mode:{ "a": { "b": 1, "c": 2 } }
with the path
b|c
, you'll get in NODES mode[ 1, 2 ]
with the path
b|c
, you'll get in NODE mode1
The option nodesWithPaths
will export paths also, embedding the elements found in a structure as follows
{ "node": the node, "path": the path of the node, "pathArray": the path of the node decomposed in an array, "JSONPath": the JSONPath of the node, "JSONPathArray": the JSONPath of the node decomposed in an array, "XJSonPath": the XJsonPath of the node, "XJSonPathArray": the xjson path of the node decomposed in an array }
Configuration files and folders
The configuration consists of configuration files and folders.
Configuration containers
This is a folder that contains folders and configuration files. It is a configuration layer that will override a base or other configuration containers if eventually. It can be a file or a folder.
If it is a file, it is
either a JSON file (even if it is preferable that it has the json suffix, we will try to load it as JSON even if it does not have it)
or an XJSON file. It must have the xjson suffix to be considered as such.
If it is a folder, we will load its components as indicated below, in the "folders and files" section.
Base configuration container
It is a container that is provided by the product, or projects. The bases are not modifiable by the API. They can be provided in the WXM_CONFIG_RESOLVER plugin or other plugins provided by the product. Projects can provide their own bases per plugin (see WXM_CONFIG_RESOLVER plugin configuration).
Principle
A final configuration, a JSON file, is the fusion of several configuration containers. The base is used first, then different containers come to redefine or overload (add, delete, modify properties).
Folders and files
A configuration container, if it is a folder, contains folders and files, which will be
either considered as elements of the final configuration JSON
or ignored
or in error if they are not readable or incorrect
Ignored and unsupported files
The following files are ignored:
Configuration containers that are not JSON objects
The JSON bases that are not compatible with the type (object or array) of the property that it defines
Folders or files that define an array value that is not an index (a number)
JSON bases in the form of a folder, or with a suffix, or as wip, or inherit
Hidden folders and files
i.e. whose name begins with a dot
including if they are marked wip or inherit (i.e. if their name starts with
~.
or^.
)
if the suffix starts with ignore
wip files (and thus inherit) outside a wip access context.
Ignored files are ignored at the base, when retrieving the contents of a folder. They are never involved in the interpretation of the final configuration. It is as if they do not exist. However, we can have a list of them, through the explain function, in the ignored section (except wip files excluded in non-wip mode).
Reasons
In explain mode, if the includesIgnored option (in ExplainVerbosity) is true, we get the list of ignored files (in the ignored section). For each ignored file, we have the reason. Here is the list of possible reasons:
NOT_FOUND
occurs when you try to load a configuration directory (or file) that is not found (for example, you try to load the portal mapping defined by _portal@config@custom, and the _portal@config folder does not exist)NOT_JSON_OBJECT
occurs when you try to load a json base (a file with the name _json) in a folder that defines an object and the loaded JSON is not an object
occurs also when you try to load a configuration from a file configuration container and the JSON is not an object (a configuration container must always be an object, as the root configuration is an object).
NOT_JSON_ARRAY
occurs when you try to load a json base (a file with the name _json) in a folder that defines an array and the loaded JSON is not an arrayFILE_WITHOUT_SUFFIX
files that define properties of type primitive or null (so except array and object) must have a suffix to determine how to read the content: json, text (or txt) or html (or htm).DIR_WITH_SUFFIX
folders with suffix are ignored.FILE_WITH_UNKNOWN_SUFFIX
only the following suffixes are supported, others are ignored:json, text, txt, html, htm
delete
ignore
JSON_BASE_AS_DIR
a folder with name _json is always ignoredJSON_BASE_WIP_OR_INHERIT
json base (file with name _json) can’t be a wip or an inherit type.HIDDEN_FILE
all files and folders whose name starts with a dot are ignoredNOT_INDEX
a file or folder that defines a property in the context of an array must be a number, otherwise it will be ignored.IGNORE_SUFFIX
you can add the ignore suffix to any file or folder so that it is ignoredNOT_SUPPORTED
any file with an extension other than those supported (like jpeg for example, or rtf, or doc, zip, etc) are ignoredINHERITED
override cancelled by an inherit fileINHERIT_WITH_SUFFIX
an inherit file or folder must not have an extension. Preferably it should be an empty file, with a simple name, just preceded by the caret character (^
).INHERIT_ARRAY
an inherit file or folder must not end with[]
. Preferably it should be an empty file, with a simple name, just preceded by the caret character (^
).DUPLICATE_NAME
When there are multiple files that could be interpreted as defining the same property (for example, ana.json
file and a folder with namea[]
), they are all ignored.DUPLICATE_INDEX
When there are several files that point to the same array index (e.g.,1.json
,01.json
,0001.json
, etc.), they are all ignored)INHERIT_WITHOUT_NAME
an inherit file will be ignored if there is no corresponding property in the same folderWIP_AND_INHERIT_TOGETHER
you can only have either a wip file or an inherit file. If you have both at the same time, then they are both ignored.DUPLICATE_WIP
There should be only one wip for a property. If there are several, one is processed, the others are ignored.DUPLICATE_INHERIT
There should be only one inherit for a property. If there are several, one is processed, the others are ignored.ERROR
When a file cannot be read due to an error, the file is ignored. In this case, in addition to the reason, the error will be given (see ExplainVerbosity options for details).UNKNOWN
If the reason for ignoring a file cannot be determined.WIP_FILE
INHERIT_FILE
JSON bases
These are files with the name _json, without suffix. The _json file is a file that contains JSON (not XJSON). It defines a JSON base for the object or array defined by the folder in which it is located.
The JSON that corresponds to the folder in which the file is located is initialized by its content.
Folders with this name are ignored.
A file with the name _json and a suffix, like json for example, is not a json base, it’s a property file with the property name _json.
Override a property
To redefine a property (an object field, an array value), simply put a file or a folder in the folder of the object or array that contains this property.
For example:
Base json:
{ "a": { "b": 1, "c": 2 } "e": 3 }
File tree (in a configuration container):
Final JSON:
{ "a": { "b": 42 "c": true "d": "abc" }, "e": 3 }
Override an array
To be able to replace and especially insert values in an array, an object structure is used to store an array. The name of the folder that corresponds to the array property must end with []. Inside, the file names correspond to indexes. The indexes of the values of the initial array are redefined in order to allow the insertion of values: we start at index 1000 and repeat from 1000 to 1000, thus leaving 1000 possibilities of insertions between each one.
Thus, for example, the following JSON
{ "a": [1,2,3] }
will be considered in the form
{ "a[]": { "000001000": 1, "000002000": 2, "000003000": 3 } }
File tree (in a configuration container):
Merged temporary JSON:
{ "a[]": { "000000500": 42, "000001000": 1, "000002000": true, "000003000": 3, "000004000": "abc" } }
Final JSON:
{ "a": [42,1,true,3,"abc"] }
Value file
3 types of content are supported:
if the suffix is
json
, then the content will be read by a JSON parser. If the parser fails, the file will be ignored.if the suffix is
html
(orhtm
), the file will be read in text mode, line by line.if the suffix is
text
(ortxt
), the file will be read in text mode, line by line.
Storage encoding is always UTF-8.
Names
In the folders, the file names are encoded:
they must always contain only lower case letters
to support capital letters, the kebab-case format is used: the capital letters are lower case preceded by a dash
the first character is special
if it is a tilde (
~
), then the file is considered as wipif it is a circumflex (
^
), then the file is considered as wip inherit
if the last two characters are the sequence
[]
, then the file is an array propertythe last dot (
.
) is always considered as a suffix separatorif one of the above reserved characters (tilde, circumflex, dot, opening or closing bracket) is part of the name of a property and is in a position where it will be interpreted as indicated above, it will be escaped. Characters that cannot be used in a file name are also escaped.
To escape an opening bracket, we double it
For example, the field with nameabc[12]
will be stored in a file with nameabc[[12].json
.To escape another character, put the name corresponding to the character in brackets, or the corresponding hexadecimal sequence.
SLASH for the character
/
BACKSLASH for the character
\
GT for the character
>
LT for the character
<
QUOTE for the character
'
PIPE for the character
|
QUESTION for the character
?
STAR for the character *
COLUMN for the character
:
TILDE for the character
~
DASH for the character
-
DOT for the character
.
CARET for the character
^
Any character can be escaped by a hexadecimal sequence, on 4 hexadecimal digits. For example, the non-breaking space will be escaped like this:
[000A]
.Any escape sequences that cannot be unescaped are retained as is.
Some examples:
abc-def
🡆abc[DASH]def
abc[0]def
🡆abc[[0]def
abc🡆def
🡆abc[f09f][a186]def
.
Delete a property
Ignore a property (comment)
XJSON
NodePath and JSONPath
JSONpath
JSONpath est une syntaxe standard de requêtes dans du JSON similaire à du XPath pour le XML. L’API supporte le uniquement le standard Jayway.
NodePath
NodePath est une syntaxe simplifiée de chemin d'élément JSON qui est utilisée pour faire du filtrage.
Name
Array index
Absolute path and relative path
Or
Escape
Security
The security of the services is based on three actions of the ConfigResolver domain.
read
To test the reading rights
parameter
surfer, the surfer
write
To test the writing rights
parameter
surfer, the surfer
writeLayer
To test the writing right in a layer (or of a layer), i.e. a configuration container.
parameter
surfer, the surfer
layer, the name of the layer
delivery
The plugin comes with the domain and the three actions. For the read action, a passing rule is set. For the write and writeLayer actions, a blocking rule is set.
Services accessibles only with administrator (tomcat) account
Service inventory
Get the list of services and associated security actions by calling the GET /api/portalconfig/services
service (only in tomcat administrator or developer role)
Tools
this path allows the access to the services accessible in user account, by extension of the path (we concatenate the URI of the user end point to the uri /api/portalconfig/tools). Not all services are accessible. Security is not applied in this type of invocation.
Services available:
/xjson/to
Configuration file manipulation services
It is a set of end points intended to write or delete configuration files. It is not a service to be used in the configuration editing application, but a build support.
These endpoints do not honor security. There is no management of access locks (in case of concurrent access, risk of conflicts, errors, etc). There is no control over the content of the files. Writing a file or folder replaces the previous one without warning.
Parameters
The parameters for writing, deleting and reading are almost the same.
target
This parameter allows you to choose the type of location from
project (default value)
customer
path
This optional parameter allows to specify a common root path for all processed files. If this parameter is not specified, the root of the location corresponding to the target parameter is used directly.
files and content
For GET and DELETE, the file parameter (several possible values) is used to indicate the file or files to be processed. They can be either regular files or directories.
For the POST, we will use more parameters to distinguish the different cases:
Indexed parameters are used to designate paths or contents. The form of an indexed parameter is <name>_<index>. The index can be any string.
If the name is
file
, the content is designated. The value of the parameter is the final content of the file.If the name is
filename
, we designate the name (or path).The
file
and thefilename
are associated by the same index value. Sofile_myfile=42
andfilename_myfile=/myfolder/myfile.json
designates a json file containing42
of relative path/myfolder/myfile.json
.A
filename
parameter without an associatedfile
parameter will create an empty file (but you can also indicate an emptyfile
parameter value)If a
file
parameter does not have an associatedfilename
, we will use the index to determine the file name if possible. Thusfile_test.json=42
, withoutfilename_test.json
allows to create the filetest.json
containing the value42
.To create folders, use the
dir
parameter.
escape
By default, the paths (in the parameters path, file, filename, etc) are relative physical file paths. Paths can be specified as property names of type xjsonpath, using escape=true
. In this case, slashes, backslashes and dots must be escaped (by preceding them with a backslash) so as not to be considered as name separators or extensions.
dir
Used with a POST to designate directory paths to be created.
depth
Used with a GET to get the contents of directories: represents the recursion depth.
Write files
POST /api/portalconfig/tools/file
Delete files
DELETE /api/portalconfig/tools/file
List files (test existence and list content)
GET /api/portalconfig/tools/file
Links
The “Urls” page of the plugin gives access to the following links:
See the main log of the plugin
See the log concerning the access to the cache
See the security log
Debug Toolkit
Cache debugging
API Documentation (ReDoc)
Services
The list of services (the available information is obtained from the service inventory).
JSP
Include configuration in your own JSP
You can include the configuration corresponding to a mapping using the URL /_plugins/wxm_config_resolver/page/config.jspz?mappingID=<mappingID>
Debug Toolkit
You can test the different conversion and detection methods via the JSP for testing these methods, at URL /_plugins/wxm_config_resolver/page/toolkit.jspz
(login by backoffice user).
This page provides access to three testing tools (do not use the associated services as API):
A page to test the escapement and the different conversions between file names and property names.
A page to test the detection of the type of a text (if the service considers it to be JSON, HTML or text).
A page allowing to see the files and folders contained in the different configuration containers, and how these files are considered by the plugin
Escapement tests
This page shows the result of applying different functions to a string. Depending on the case this string can be
a property name in a JSon
a property name in an XJson
a file (or folder) name (without the extension)
There are three types of functions:
escaping functions
These are basic character escaping functions for JSon properties when used as filenames in configuration layers (escapement to convert a property name into a json to be used as a file name). TheescapeNotSuffix
version isolates the suffix (the file extension) and does not escape it (in particular to keep the separating dot).string to name (and name to string) conversion functions.
For each type of conversion of a String into a Name, we have three conversion functions that allow us to obtain:a String representation
a name in a XJson
a file name
In addition, we can see the property name in the final JSon as well as the associated states (wip, inherit and array).
case conversion functions
kebab to camel calse
camel to kebab case
Content type detection
This page allows to see how a text content will be considered by the plugin when it comes to store it in a file (in JSon or plain text)
Folders content
This page allows you to consult all the files currently stored and to have information on these files.
It is a version 0 which does not manage progressive loading : all the tree structure is loaded at once
Cache debugging
This page displays the currently cached files. It allows you to
know the state of the cache (up to date, being generated, etc)
know the different variations (depending on the mappings, post processors, etc)
consult each cached file
refresh the cache
In a cluster, this is the cache for the current node.
List of services
** Procédure d’installation version test
j’ai créé un plugin wxm_config_test_portal
dans le dossier config, j’ai créé un config_resolver/bases
j’ai copié _portal.json dedans
dans wxm_config_resolver, dans config_settings, j’ai ajouté :
"baseLocations": { "_portal":"wxm_config_test_portal" }
** Tests Insomnia