{"id":21740158,"url":"https://github.com/bserdar/jcliff","last_synced_at":"2025-07-29T22:37:14.942Z","repository":{"id":7717851,"uuid":"9083383","full_name":"bserdar/jcliff","owner":"bserdar","description":"Manage JBossAS 7/EAP6/Wildfly with modular configuration files from command line, puppet, ansible, chef, etc.","archived":false,"fork":false,"pushed_at":"2022-01-07T10:10:54.000Z","size":85666,"stargazers_count":44,"open_issues_count":17,"forks_count":26,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-04-13T03:46:05.003Z","etag":null,"topics":["ansible","configuration-management","jboss","jboss-eap","puppet","wildfly"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bserdar.png","metadata":{"files":{"readme":"README.markdown","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-03-28T18:15:57.000Z","updated_at":"2025-04-03T03:26:54.000Z","dependencies_parsed_at":"2022-09-13T03:35:17.030Z","dependency_job_id":null,"html_url":"https://github.com/bserdar/jcliff","commit_stats":null,"previous_names":[],"tags_count":66,"template":false,"template_full_name":null,"purl":"pkg:github/bserdar/jcliff","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bserdar%2Fjcliff","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bserdar%2Fjcliff/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bserdar%2Fjcliff/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bserdar%2Fjcliff/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bserdar","download_url":"https://codeload.github.com/bserdar/jcliff/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bserdar%2Fjcliff/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267772539,"owners_count":24142091,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-29T02:00:12.549Z","response_time":2574,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","configuration-management","jboss","jboss-eap","puppet","wildfly"],"created_at":"2024-11-26T06:12:25.415Z","updated_at":"2025-07-29T22:37:14.895Z","avatar_url":"https://github.com/bserdar.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JCliff\n## What does it do?\n\nJcliff configures a running instance of EAP6/JBoss7 using modular\nconfiguration files.\n\n## How to install it?\n\nJCliff is simple Java app, you can build it from the source code:\n\n    $ mvn clean install\n\nIf you are using Linux and RPM to manage your software (RHEL, CentOS, Fedora...), there is a copr repos available:\n\n    $ yum install yum-plugin-copr  # to ensure copr is available to yum\n    $  dnf copr enable ansiblemiddleware/jcliff \u0026\u0026 dnf install jcliff -y\n\n### But I can configure EAP6/JBoss7 by editing the configuration XML file....\n\nThere are several problems with that:\n  * It is not easily maintainable, especially if you have many hosts with different configurations.\n  * It requires a bounce. JCliff uses jboss-cli.sh to invoke\nconfiguration commands, so many configuration modifications can be\ndone without bouncing the server.\n\n### I can use scripts that call jboss-cli.sh to configure the server\n\nJCliff modifies the configuration incrementally. Only necessary parts\nof the configuration is modified, and if the required changes are already \napplied, nothing is done.\n\n### How do I use Puppet?\n\nUse puppet to lay down configuration files, and then have puppet\nexecute jcliff. This way, you can define datasources, logging,\netc. using puppet code and templates, and configure only what's\nnecessary.\n\n### How do I use it with Ansible\n\nJCliff has been integrated into Ansible as part of its own\n[JCliff Collection](https://github.com/wildfly-extras/ansible_collections_jcliff),\nplease refers to this project documentation.\n\n### Can I use another configuration management tool?\n\nThere's nothing puppet specific in jcliff. You can use jcliff as a\ncommand line tool, or from any configuration management system than\ncan install files, and execute other programs.\n\n### What does jcliff configuration files look like?\n\nJCliff uses the same JSON-like language used by jboss-cli.sh (jboss-dmr library).\nA configuration file that sets the root level logging looks like\n\n{\n  \"logging\" =\u003e { \n    \"root-logger\" =\u003e {\n       \"ROOT\" =\u003e {\n          \"level\" =\u003e \"debug\"\n       }\n    }\n  }\n}\n\n### How do I install JCliff on my system ?\n\nFirst of all, build the project using Maven:\n\n    $ mvn clean install\n\nThen create a directory and associate a environment variable called JCLIFF_HOME\nto it\n\n    $ mkdir -p /usr/local/jcliff\n    $ export JCLIFF_HOME=/usr/local/jcliff\n\nCopy the jcliff jar and its dependency to this directory:\n\n    $ cp -Rv target/dependency/ \"${JCLIFF_HOME}\"\n    $ cp target/jcliff*.jar \"${JCLIFF_HOME}\"\n\nFrom there, you can use the scripts provided in src/main/scripts to use jcliff.\n\n# Operation\n\nEAP6 configuration is difficult if you intend to use puppet. The\ncommand line client provides an interactive front-end for\nconfiguration tasks, not easily called from puppet scripts. There is\nno easy way to retrieve what's already configured, find the\ndifferences between the current state and the desired state, and come\nup with a way to implement those. Jcliff does exactly that. User\nsupplies the desired configuration, jcliff executes the jboss client\nto retrieve the current state, derive deltas, and apply them. What\nkind of delta results in what kind of action is defined using a\nproperty file based rule language.\n\n## JBoss configuration model:\n\nThe JBoss DMR library is used to represent jboss configuration in a\nhierarchical markup language. \n\nLook at this logging configuration fragment as example:\n\n    \u003e /subsystem=logging:read-resource(recursive=true)\n\n    {\n        \"outcome\" =\u003e \"success\",\n        \"result\" =\u003e {\n            \"custom-handler\" =\u003e undefined,\n            \"async-handler\" =\u003e {\n                \"blah\" =\u003e {\n                    \"encoding\" =\u003e undefined,\n                    \"filter\" =\u003e undefined,\n                    \"formatter\" =\u003e \"%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n\",\n                    \"level\" =\u003e undefined,\n                    \"overflow-action\" =\u003e \"BLOCK\",\n                    \"queue-length\" =\u003e 1000,\n                    \"subhandlers\" =\u003e undefined\n                },\n                \"ASYNC\" =\u003e {\n                    \"encoding\" =\u003e undefined,\n                    \"filter\" =\u003e undefined,\n                    \"formatter\" =\u003e \"%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n\",\n                    \"level\" =\u003e undefined,\n                    \"overflow-action\" =\u003e \"BLOCK\",\n                    \"queue-length\" =\u003e 1000,\n                    \"subhandlers\" =\u003e [\"FILE\"]\n                }\n            },\n         ...\n      }\n    }\n\nThe command \n\n    /subsystem=logging:read-resource(recursive=true)\n\nis parsed as follows:\n\n  - Select the subsytem whose name is logging. That's a node in the\n  configuration tree\n  - `:read-resource` is an operation defined on that node. Invoke the\n  operation with attributes `(recursive=true)`\n\nAs for the return result:\n\n  - Anything between `{` and `}` is an object. So the return result is an\n  object containing two items, `outcome` and `result`.\n  - `result` is another object, containing `custom-handler`,\n  `async-handler`, etc. all of which are objects\n  - `async-handler` contains objects `ASYNC` and `blah`.\n  - `ASYNC/subhandlers` is a list of strings. Anything between `[` and `]`\n  are lists.\n\nEvery node in the configuration tree defines a set of operations that\ncan be run on that node. For instance, to add a new `async-handler`, you\nhave to invoke:\n\n    /subsystem=logging/async-handler=newHandler:add(queue-length=someNumber)\n\nHere's the primary reasons why it is not easy to automate the\nconfiguration tasks:\n\n   - Every node defines a separate set of operations.\n   - Every operation has a different set of required parameters\n\nThat is, there is no standard way of adding/removing nodes to the\nconfiguration tree. For instance, to add an element to the handlers\nlist of a logger, you have to call assign-subhandler on that node. To\nassign a handler to root logger, you have to call\n`root-logger-assign-subhandler` on that root logger.\n\n`/subsystem` is not a universal prefix. That would be too easy. For\ninstance, to get system properties:\n\n    /core-service=platform-mbean/type=runtime:read-attribute(name=system-properties)\n\n## Puppet configuration model:\n\nThe idea is to have puppet lay configuration files to a given\ndirectory, and then run jcliff on those files. Jcliff loads the\npuppetized configuration files, talks to JBoss, determines what needs\nto be changed, and changes them. Each puppetized configuration file\nhas to tell what it is configuring. For instance, a logging\nconfiguration file looks like:\n\n    { \"logging\" =\u003e\n       {\n            \"async-handler\" =\u003e { \n              \"ASYNC\" =\u003e {\n                \"subhandlers\" =\u003e [ \"FILE\" ],\n                \"queue-length\" =\u003e 1000,\n               },\n            },\n            \"size-rotating-file-handler\" =\u003e { \n              \"SFILE\" =\u003e { }\n            }\n        }\n    }\n          ...\n\nSimilarly, jdbc drivers:\n\n    { \"jdbc-driver\" =\u003e  \n      { \"oracle\" =\u003e {\n            \"driver-name\" =\u003e \"oracle\",\n            \"driver-module-name\" =\u003e \"oracle.jdbcx\",\n            \"driver-xa-datasource-class-name\" =\u003e \"oracle.jdbc.XADataSource\"\n        }\n      }\n    }\n\nDatasources:\n\n    {\n        \"datasource\" =\u003e {\n               \"BSProduct\" =\u003e { \n                 \"jndi-name\" =\u003e \"java:/BSProduct\",\n                 \"connection-url\" =\u003e \"jdbc:oracle:oci@web\",\n                 \"driver-name\" =\u003e \"oracle\",\n                 \"user-name\" =\u003e \"web\",\n                 \"password\" =\u003e \"web_dev0\",\n               }\n         }\n    }\n\nSystem properties:\n\n    { \"system-property\" =\u003e {\n       \"foo\" =\u003e \"bar\",\n       \"bah\" =\u003e \"gah\"\n      }\n    }\n\nJcliff does not delete anything from the existing configuration unless\nexplicitly required. Therefore, not specifying certain properties of\nobjects will leave them untouched. If you want to delete them, assign\nobjects/values to `\"deleted\"`, or undefine them, by assigning them to\n`undefined`.\n\n## Deployments:\n\nJcliff can be used to deploy applications. After applying all the\nconfiguration changes, Jcliff attempts to process deployments of the form:\n\n    { \"deployments\" =\u003e {\n        \"myApp-v2.1.ear\" =\u003e {\n         \"NAME\" =\u003e \"myApp-v2.1.ear\",\n         \"path\" =\u003e \"/var/lib/redhat/deploy/myApp-v2.1.ear\",\n         \"replace-name-regex\" =\u003e \"\\\\QmyApp-v\\\\E\\\\..*\",\n         }\n      }\n    }\n\nJcliff runs `deploy -l` to retrieve the list of deployed packages. The\nidea is to have Jcliff first undeploy older versions of the same\napplication, and then to redeploy the new version. The\n`replace-name-regex` and `replace-runtime-name-regex` regular expressions\nare used to locate applications that the new application will\nreplace. Any applications whose name matches `replace-name-regex`, or\nwhose runtime name matches `replace-runtime-name-regex` will be\nundeployed before redeploying the new application. In the above\nexample, `myApp-v2.1.ear` would replace an existing `myApp-v2.0.ear`.\n\nIf `myApp-v2.1.ear` already is deployed, Jcliff will not attempt to\nredeploy it, unless `--redeploy` flag is passed. So, after deploying all\nthe applications, running Jcliff without the `--redeploy` flag with the\nexisting deployment list will not alter any of the deployments.\n\n## The delta and the rules:\n\nJcliff reads all configuration files, and builds a list of\npaths. Every value in the configuration tree is represented by a path\ncontaining all the object names up to that value. For instance:\n\n    { \"system-property\" =\u003e {\n       \"foo\" =\u003e \"bar\",\n       \"bah\" =\u003e \"gah\"\n      }\n    }\n\nPaths:\n\n    system-property\n    system-property/foo\n    system-property/bah\n\nFor the datasource example:\n\n    {\n        \"datasource\" =\u003e {\n               \"BSProduct\" =\u003e { \n                 \"jndi-name\" =\u003e \"java:/BSProduct\",\n                 \"connection-url\" =\u003e \"jdbc:oracle:oci@web\",\n                 \"driver-name\" =\u003e \"oracle\",\n                 \"user-name\" =\u003e \"web\",\n                 \"password\" =\u003e \"web_dev0\",\n               }\n         }\n    }\n\nPaths:\n\n    /datasource\n    /datasource/BSProduct\n    /datasource/BSProduct/jndi-name\n    /datasource/BSProduct/connection-url\n    /datasource/BSProduct/driver-name\n    /datasource/BSProduct/user-name\n    /datasource/BSProduct/password\n\nSame thing is also done for the configurations retrieved from JBoss. For instance, when datasource configuration is read, \n\n    \"result\" =\u003e {\n        \"ExampleDS\" =\u003e {\n                \"allocation-retry\" =\u003e undefined,\n                \"allocation-retry-wait-millis\" =\u003e undefined,\n                \"allow-multiple-users\" =\u003e undefined,\n                \"background-validation\" =\u003e undefined,\n                \"background-validation-millis\" =\u003e undefined,\n                \"blocking-timeout-wait-millis\" =\u003e undefined,\n                \"check-valid-connection-sql\" =\u003e undefined,\n                \"connection-properties\" =\u003e undefined,\n                \"connection-url\" =\u003e \"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1\",\n                \"datasource-class\" =\u003e undefined,\n                \"driver-class\" =\u003e undefined,\n                \"driver-name\" =\u003e \"h2\",\n                \"enabled\" =\u003e true,\n                \"exception-sorter-class-name\" =\u003e undefined,\n                \"exception-sorter-properties\" =\u003e undefined,\n                \"flush-strategy\" =\u003e undefined,\n                \"idle-timeout-minutes\" =\u003e undefined,\n                \"jndi-name\" =\u003e \"java:jboss/datasources/ExampleDS\",\n                \"jta\" =\u003e true,\n                \"max-pool-size\" =\u003e undefined,\n                \"min-pool-size\" =\u003e undefined,\n                \"new-connection-sql\" =\u003e undefined,\n                \"password\" =\u003e \"sa\",\n                \"pool-prefill\" =\u003e undefined,\n                \"pool-use-strict-min\" =\u003e undefined,\n                \"prepared-statements-cache-size\" =\u003e undefined,\n                \"query-timeout\" =\u003e undefined,\n                \"reauth-plugin-class-name\" =\u003e undefined,\n                \"reauth-plugin-properties\" =\u003e undefined,\n                \"security-domain\" =\u003e undefined,\n                \"set-tx-query-timeout\" =\u003e false,\n                \"share-prepared-statements\" =\u003e false,\n                \"spy\" =\u003e false,\n                \"stale-connection-checker-class-name\" =\u003e undefined,\n                \"stale-connection-checker-properties\" =\u003e undefined,\n                \"track-statements\" =\u003e \"NOWARN\",\n                \"transaction-isolation\" =\u003e undefined,\n                \"url-delimiter\" =\u003e undefined,\n                \"url-selector-strategy-class-name\" =\u003e undefined,\n                \"use-ccm\" =\u003e true,\n                \"use-fast-fail\" =\u003e false,\n                \"use-java-context\" =\u003e true,\n                \"use-try-lock\" =\u003e undefined,\n                \"user-name\" =\u003e \"sa\",\n                \"valid-connection-checker-class-name\" =\u003e undefined,\n                \"valid-connection-checker-properties\" =\u003e undefined,\n                \"validate-on-match\" =\u003e false,\n                \"statistics\" =\u003e {\n                    \"jdbc\" =\u003e undefined,\n                    \"pool\" =\u003e undefined\n                }\n            }\n      }\n\nJcliff uses the value of `result`, that is, the object containing the\n`ExampleDS`. Some hacking is required here, because the configuration\ntree starts with `datasource`, but the JBoss tree does not. We either\nhave to remove `datasource` from the configuration tree, or add\n`datasource` to JBoss tree. The definition of datasource rules has\nthis property:\n\n    server.preprocess.prepend=/datasource\n\nThat is, once loaded the jboss configuration is converted into:\n\n    \"datasource\" =\u003e {\n                      \"ExampleDS\" =\u003e {...}\n                    }\n\nAll four options are possible:\n\n    server.preprocess.strip\n    server.preprocess.prepend\n    client.preprocess.strip\n    client.preprocess.prepend\n\nThese directives either insert, or remove levels from the client or\nserver configuration tree.\n\nAfter the preprocessing, the paths are built, and a difference is\ncomputed. The differences are:\n\n   - `add`: Add a new configuration item to JBoss tree\n   - `modify`: Modify an existing item in JBoss tree. Only the leaf\n   modified paths appear in the delta. That is, if a datasource\n   attribute is modified, the datasource node itself is not in the\n   delta, only the modified attribute is.\n   - `remove`: Remove an item from JBoss tree. This is done by assigning\n   the value of an object to `\"deleted\"`.\n   - `undefine`: Undefine item in JBoss tree.\n   - `listAdd`: Add a new element in a list in JBoss tree.\n   - `listRemove`: Remove an element from a JBoss list.\n   - `reorder`: Reorder the attributes of an object\n\nHack: you can't add a nontrivial object, and set its attributes. The\nattributes of the nontrivial object don't exist until the object is\ncreated, which results in attribute add operations. Attributes cannot\nbe added, only modified. So,\n\n  1) You have to run the rules that add objects before the ones that\n  modify the objects properties\n  2) Once you add a nontrivial object, you have to refresh the JBoss\n  configuration tree, so that you have a representation of the\n  existing configuration with all the default values of the newly\n  added object.\n\nSo, after adding a new object, you have to re-read the relevant\nconfiguration from JBoss. This is done by the `refresh` directive. For\ninstance:\n\n    match.addConsoleHandler=add:/console-handler/*\n    addConsoleHandler.precedence=50\n    addConsoleHandler.rule=/subsystem=logging/console-handler:${name(.)}:add\n    addConsoleHandler.refresh=true\n\n    match.modifyConsoleHandler=modify:/console-handler/*/*\n    modifyConsoleHandler.precedence=55\n    modifyConsoleHandler.rule=/subsystem=logging/console-handler=${name(..)}:write-attribute(name=${name(.)},value=${value(.)})\n\n`addConsoleHandler` will add a new console handler by only specifying\nits name. Once added, all the attributes of the new handler will be\nset to their default values. Jcliff will re-read the configuration,\nretrieving all the attributes. Then, attribute modification rules are\nrun. Rules with lower precedence value run before rules with higher\nprecedence value.\n\n\nNow the rules themselves:\n\n - The configurable subsytems are defined in the rules file:\n\n        configurable.1=system-properties\n        configurable.2=logging\n        configurable.3=jdbc-driver\n        configurable.4=datasource\n        configurable.5=xadatasource\n\nEach configurable defines a rule file defining the rules to deal with\nthat particular configurable. The explicit ordering defines the order\nin which the subsystems will be configured.\n\nEach rule file contains at least the following:\n\n    name=xadatasource\n    getContents=/subsystem=datasources:read-children-resources(child-type=xa-data-source)\n    server.preprocess.prepend=/xadatasource\n\n - `name`: name of the configurable\n - `getContents`: The statement to run to retrieve the contents of this\n configurable from JBoss\n - preprocessing directives: optional\n `server/client.preprocess.prepend/strip`, defining what to add/remove\n from the server/client configuration so that a meaningfull delta can\n be computed. One server and one client operation can be specified,\n but you can't specify two server or client operations.\n\nEach rule is defined using a `match` property:\n\n    match.addDatasource=add:/datasource/*\n\nThis match property defines a rule name `addDatasource`. It matches\nthe node on the delta where a path of the form `/datasource/\u003cName\u003e` is\nadded to the JBoss configuration. That is, a datasource exists in the\npuppetized configuration, but not in JBoss. So, you define how to add\na new datasource:\n\n    addDatasource.rule.1=data-source add --name=${name(.)} --jndi-name=${value(jndi-name)} --driver-name=${value(driver-name)} --connection-url=${value(connection-url)}\n    addDatasource.rule.2=data-source enable --name=${name(.)}\n    addDatasource.refresh=true\n\nThe construct `${name(\u003cpath\u003e)}` evaluates to the name of the last\nelement in `\u003cpath\u003e`. Path can be relative. A relative path is evaluated\nwith respect to the matched node. Above, if the matching node is\n`/datasource/BSProduct`, `${name(.)}` evaluates to `BSProduct`.\n\nThe construct `${value(\u003cpath\u003e)}` evaluates to the value of the node\ndenoted by `\u003cpath\u003e`. In the above example, the expression\n`${value(jndi-name)}` evaluates to the content of the path\n`/datasource/BSProduct/jndi-name`, which should give the JNDI name of\nthe datasource in the puppetized configuration.\n\nMultiple commands can be provided in a rule. In the above example,\n`addDatasource.rule.1` will create the datasource, and\n`addDatasource.rule.2` will enable it.\n\n`addDatasource.refresh` will reload the JBoss configuration for\ndatasources. This is required after an add operation. The refresh\nconfiguration will have all the datasource attributes initialized to\ntheir default values, and any datasource attribute modification rule\nwill match after a refresh.\n\n## Conditionals\n\nIt is possible, as of v2.6, to have conditionals in rules:\n\n  ${if-defined (path), (true-case) \u003c, (false-case) \u003e }\n\nIf `path` is defined, then `true-case` is evaluated, otherwise\n`false-case` is evaluated if it exists. For example:\n\n{ \n  \"jdbc-driver\" =\u003e {\n   { \"MyDriver\" =\u003e {\n      ...\n      \"module-slot\" =\u003e \"2.0\"\n    }\n  }\n\nAbove, \"module-slot\" is an optional parameter. The rule for inserting\na jdbc driver is written taking this into account:\n\n  addDriver.rule.1=/subsystem=datasources/jdbc-driver=${name(.)}:add( \\\n      driver-name=${value(driver-name)}, \\\n      driver-module-name=${value(driver-module-name)}, \\\n      driver-xa-datasource-class-name=${value(driver-xa-datasource-class-name)} \\\n      ${if-defined (module-slot),(,module-slot=${value(module-slot)})} \\\n      ${if-defined (driver-class-name),(,driver-class-name=${value(driver-class-name)})})\n\nNote that the argument has a starting comma. This is required to build a correct command.\n\n## Iteration\n\n ${foreach-cfg (path), (cmd1), (cmd2),...}\n ${foreach-server (path), (cmd1), (cmd2),...}\n\nIn foreach-cfg, \"path\" refers to a path in the input configuration\nfile. In foreach-server, \"path\" refers to a path in the current server\nconfiguration.  The \"path\" is evaluated based on the matched path of\nthe rule. The $foreach command iterates the immediate children of\n\"path\", and executes all commands for each of the elements. The\ncommands \"cmdN\" are evaluated based on the iterated path. For example:\n\n{\n   \"jgroups\" =\u003e {\n      \"stack\" =\u003e {\n         \"udp\" =\u003e {\n            \"protocol\" =\u003e {\n               \"PING\" =\u003e {...},\n               \"MERGE3\" =\u003e {...},\n               \"FD_SOCK\" =\u003e {...}.\n\nThere is no way to insert or reorder protocols, so we remove all protocols from jgroups/stack/udp/protocol, and reinsert them:\n\nmatch.addProtocol=add:/stack/*/protocol/*\naddProtocol.rule.1=batch\naddProtocol.rule.2=${foreach-server (/stack/${name(../..)}/protocol), (/subsystem=jgroups/stack=${name(../..)}:remove-protocol(type=${name(.)}))}\naddProtocol.rule.3=${foreach-cfg (/stack/${name(../..)}/protocol), (/subsystem=jgroups/stack=${name(../..)}:add-protocol(type=${name(.)} ${if-defined (socket-binding),(,socket-binding=${value(socket-binding)})} ${if-defined (property), (,properties=${value(properties)})} ))}\naddProtocol.rule.4=run-batch\n\n * The \"match\" rule matches any insertions to the protocol object. This rule will be evaluated when a new node is added to protocol.\n * The first rule starts a batch (jboss-cli directive)\n * The second rule iterates already defined protocols at the server, and removes them one by one.\n * The third rul iterates the protocols defined in the input configuration file, and inserts them one by one\n * The fourth rule runs the batch\n\n\n## Prefix Rules\n\nIt is inefficient and error prone to keep writing rules of the form:\n\n  match.modifyProp=modify:/webservices/*\n  modifyProp.rule.1=/subsystem=webservices:write-attribute(name=${name(.)},value=${value(.)})\n\nChanging an attribute is done the same way for all configuration\nlevels. So, instead of repeating this rule for every configuration\nlevel, it can be written as a prefix rule that applies to a set of\nnodes:\n\n  prefix.modifyProp=modify:/webservices\n\nThe above rule declaration will make modifyProp match any\nmodifications of a path with prefix '/webservices'.\n\n  modifyProp.rule.1=/subsystem=webservices${cmdpath(${path(..)})}:write-attribute(name=${name(.)},value=${value(.)})\n\n${cmdpath($path(..))} writes the path in the form /componen1=component2/component3=component4/...\n\n${cmdpath(=$path(..))} writes the path in the form =component1/component2=component3/component4=component5...\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbserdar%2Fjcliff","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbserdar%2Fjcliff","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbserdar%2Fjcliff/lists"}