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.
...
_portal
_portal@config
_portal@config@picker
The path _portal@$config@picker designates a configuration defined in 3 folders whose relative paths are successively :
...
For each plugin, if a config-resolver-postprocessors.json
file is present in its configuration folder (config
), it is loaded to add one or more post processors. The format is the same as the postProcessors
section of the config_settings
plugin parameter, but you can additionally indicate that postprocessor is defined in the plugin itself using object syntax without indicating a plugin property (if you indicate a null plugin property, the default contribution plugin will be used).
If a post processor already exists, it is ignored (note that you cannot control the order of the plugins).
Un exemple complet de contribution de mappings et postprocessors
La configuration du plugin WXM_CONFIG_RESOLVER est
Code Block | ||
---|---|---|
| ||
{
"mappings": {
"portal": "_portal@club-wed@:surferRole@:userAgent",
"picker": "_portal@club-wed@:picker"
},
"postProcessors": {
"surferRole": "fr.wedia.confres.core.model.processor.SurferRolePostProcessor",
"userAgent": {
"processor": "fr.wedia.confres.core.model.processor.UserAgentPostProcessor",
"config": [
{
"pattern": ".*Mobi.*",
"name": "mobile"
}
]
}
}
} |
Le service GET /api/portalconfig/mappings
(liste des mappings) retourne :
Code Block | ||
---|---|---|
| ||
[
"portal",
"picker"
] |
Le service GET api/portalconfig/postprocessors/list?options=%7B%0A%09withMappings%3A%20true,%0A%09withValues%3A%20true%0A%7D
(liste des postprocessors, avec leurs mappings associés et valeurs) retourne :
Code Block | ||
---|---|---|
| ||
[
{
"name": "surferrole",
"mappings": [
"portal"
],
"values": [
"",
"role-1",
"role-4",
"role-27",
"role-31",
"role-32",
"role-33"
]
},
{
"name": "useragent",
"mappings": [
"portal"
],
"values": [
"",
"mobile"
]
}
] |
Je créé un plugin de contribution WXM_CONFIG_RESOLVER_GPP tel que
📁 WXM_CONFIG_RESOLVER_GPP
📁 config
📄 config.xml
📄 config-resolver-mappings.json
📄 config-resolver-postprocessors.json
📁 res
📁 gpp
📄 CustomProcessor.groovy
📄 CustomProcessorWithConfig.groovy
(le plugin d’exemple contient d’autres processors groovy non utilisés dans cet exemple)
View file | ||
---|---|---|
|
Le fichier config-resolver-mappings.json définit des mappings supplémentaires :
Code Block | ||
---|---|---|
| ||
{
"mapping_GPP_1": "_empty",
"mapping_GPP_2": "_empty@:gppProcessor",
"mapping_GPP_3": "_empty@:gppProcessor@:gppProcessorWithConfig"
} |
Le fichier config-resolver-postprocessors.json définit des postprocessors supplémentaires :
Code Block | ||
---|---|---|
| ||
{
"gppProcessor": {
"processor": "/res/gpp/CustomProcessor.groovy"
},
"gppProcessorWithConfig": {
"processor": "/res/gpp/CustomProcessorWithConfig.groovy",
"config": {
"values": ["x","y" ]
}
}
} |
On utilise ici la syntaxe “objet” sans propriété “plugin”, ce qui détermine que le fichier groovy sera cherché dans ce plugin (WXM_CONFIG_RESOLVER_GPP), avec un path relatif à sa racine.
On installe et active ce plugin et on redémarre WXM_CONFIG_RESOLVER.
Le service GET /api/portalconfig/mappings
(liste des mappings) retourne :
Code Block | ||
---|---|---|
| ||
[
"portal",
"picker",
"mapping_GPP_1",
"mapping_GPP_2",
"mapping_GPP_3"
] |
Le service GET api/portalconfig/postprocessors/list?options=%7B%0A%09withMappings%3A%20true,%0A%09withValues%3A%20true%0A%7D
(liste des postprocessors, avec leurs mappings associés et valeurs) retourne :
Code Block | ||
---|---|---|
| ||
[
{
"name": "surferrole",
"mappings": [
"portal"
],
"values": [
"",
"role-1",
"role-4",
"role-27",
"role-31",
"role-32",
"role-33"
]
},
{
"name": "useragent",
"mappings": [
"portal"
],
"values": [
"",
"mobile"
]
},
{
"name": "gppprocessor",
"mappings": [
"mapping_GPP_2",
"mapping_GPP_3"
],
"values": [
"V1",
"V2",
"V3",
"V4",
"V5"
]
},
{
"name": "gppprocessorwithconfig",
"mappings": [
"mapping_GPP_3"
],
"values": [
"x",
"y"
]
}
] |
Standard postprocessors
Surfer role
...
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()
Info |
---|
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). |
...
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:Code Block language groovy 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:
Code Block language json "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.
...
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.
...
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:Code Block language json { "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:Code Block language json { 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 layerIn this case, the path field (mandatory) is the path of the configuration layer
ExampleCode Block language json { 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
ExampleCode Block { type: base, mappingID: portal }
dir
To get a filesystem view of a configuration folder.
...
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.
...
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 layers, 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
...
** 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é :
...