{"id":23974644,"url":"https://github.com/hal/dmr.repl","last_synced_at":"2026-05-16T15:02:32.689Z","repository":{"id":11266932,"uuid":"13671155","full_name":"hal/dmr.repl","owner":"hal","description":"Scala REPL shell for managing WildFly server instances","archived":false,"fork":false,"pushed_at":"2014-07-10T08:30:06.000Z","size":296,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-24T16:39:33.918Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-10-18T07:00:07.000Z","updated_at":"2015-05-27T16:50:51.000Z","dependencies_parsed_at":"2022-09-08T08:11:37.203Z","dependency_job_id":null,"html_url":"https://github.com/hal/dmr.repl","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hal/dmr.repl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hal%2Fdmr.repl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hal%2Fdmr.repl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hal%2Fdmr.repl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hal%2Fdmr.repl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hal","download_url":"https://codeload.github.com/hal/dmr.repl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hal%2Fdmr.repl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":284902580,"owners_count":27081908,"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-11-17T02:00:06.431Z","response_time":55,"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":[],"created_at":"2025-01-07T05:48:00.143Z","updated_at":"2025-11-17T15:03:58.708Z","avatar_url":"https://github.com/hal.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/hal/dmr.repl.png)](https://travis-ci.org/hal/dmr.repl)\n\n# DMR.repl\n\nA REPL shell for managing WildFly server instances. Build on a Scala wrapper around \n[DMR]((https://docs.jboss.org/author/display/WFLY8/Detyped+management+and+the+jboss-dmr+library)), SBT and\nthe Scala REPL at it's core.\n\nFeatures:\n\n* DSL for creating DMR operations\n* Interact with model nodes in a more natural way\n\nFor an introduction to DMR please refer to the [WildFly Wiki](https://docs.jboss.org/author/display/WFLY8/Detyped+management+and+the+jboss-dmr+library).\n\n## Working with model nodes\n\nPlease make sure to import the following packages in order to bring the necessary implicit conversions into scope and\nto save you some keystrokes.\n\n```scala\nimport org.jboss.dmr.scala._\nimport org.jboss.dmr.scala.ModelNode\n```\n\n## Creating model nodes\n\nUse the factory methods in `org.jboss.dmr.scala.ModelNode` to create model nodes:\n\n```scala\n// creates an empty model node\nval node = ModelNode()\n\n// creates a new model node holding a simple value\nval node = ModelNode(42)\n\n// creates a new model node with structure\nval node = ModelNode(\n  \"flag\" -\u003e true,\n  \"hello\" -\u003e \"world\",\n  \"answer\" -\u003e 42,\n  \"child\" -\u003e ModelNode(\n    \"inner-a\" -\u003e 123,\n    \"inner-b\" -\u003e \"test\",\n    \"deep-inside\" -\u003e ModelNode(\"foo\" -\u003e \"bar\"),\n    \"deep-list\" -\u003e List(\n      ModelNode(\"one\" -\u003e 1),\n      ModelNode(\"two\" -\u003e 2),\n      ModelNode(\"three\" -\u003e 3)\n    ),\n    \"value-list\" -\u003e List(\n      ModelNode(1),\n      ModelNode(2),\n      ModelNode(3)\n    )\n  )\n)\n```\n\n## Addressing and operations\n\nYou can use a DSL like API to set the address and operation for a model node. To describe the \"read-resource\" operation\non \"/subsystem=datasources/data-source=ExampleDS\" use the following code:\n\n```scala\nModelNode() at (\"subsystem\" -\u003e \"datasources\") / (\"data-source\" -\u003e \"ExampleDS\") op 'read_resource(\n  'include_runtime -\u003e false,\n  'recursive_depth -\u003e 2\n)\n```\n\nAddresses can be written down as `(String, String)` tuples separated by \"/\". Operations are specified using\n`Symbol`s and an optional list of parameters. Each parameter is made up of another `Symbol` and a value. Using symbols\nmakes the DSL both more readable and extentable.\n\nHowever there's one drawback in using symbols: when using the short form `'someSymbol` characters like \"-\" are not allowed. `'read-resource` is therefore an illegal symbol. As most DMR operations and many parameters do contain \"-\", all\nunderscores will be replaced with dashes:\n\n```scala\nModelNode() op 'read_resource('include_runtime -\u003e true)\n// is exactly the same as\nModelNode() op Symbol(\"read-resource\")(Symbol(\"include-runtime\") -\u003e true)\n```\n\nHere are some more examples using addresses and operations:\n\n```scala\n// root is a constant for an empty address\nModelNode() at root op 'read_resource\nModelNode() at (\"subsystem\" -\u003e \"datasources\") / (\"data-source\" -\u003e \"ExampleDS\") op 'disable\n\n// parameters are specified as pairs (Symbol -\u003e Any)\nModelNode() at (\"core-service\" -\u003e \"platform-mbean\") / (\"type\" -\u003e \"runtime\") op 'read_resource(\n  'attributes_only -\u003e true,\n  'include_runtime -\u003e false,\n  'recursive_depth -\u003e 3,\n  'custom_parameter -\u003e \"custom-value\"\n)\n\n// unsupported parameter types will throw an IllegalArgumentException\nModelNode() at root op 'read_resource('proxies -\u003e Console.out)\n```\n\n## Reading Nodes\n\nReading values from a model node follows the sementics of a `Map[String, ModelNode]`, but instead of a string you have to\nprovide a `Path` as key. Thanks to an implicit conversion expressions like `\"a\" / \"b\" / \"c\"` are automatically converted\nto a path.\n\n```scala\nval node = ModelNode(\n  \"flag\" -\u003e true,\n  \"hello\" -\u003e \"world\",\n  \"answer\" -\u003e 42,\n  \"level0\" -\u003e ModelNode(\n    \"level1\" -\u003e ModelNode(\n      \"level2\" -\u003e ModelNode(\n        \"level3\" -\u003e ModelNode(\n          \"level4\" -\u003e ModelNode(\"foo\" -\u003e \"bar\")\n        )\n      )\n    )\n  )\n)\n\nval flag = node(\"flag\")\nval boom = node(\"gag\") // throws a NoSuchelementException\nval hello = node.get(\"hello\") // returns an Option[ModelNode]\nval x = node.getOrElse(\"nope\", ModelNode(\"y\"))\nval check = node.contains(\"level0\" / \"level1\" / \"level2\" / \"level3\")\nval level3 = node(\"level0\" / \"level1\" / \"level2\" / \"level3\")\nval level2 = for {\n  l0 \u003c- node.get(\"level0\")\n  l1 \u003c- l0.get(\"level1\")\n  l2 \u003c- l1.get(\"level2\")\n} yield l2\n```\n\nSince the result of `node.get(\"a\" / \"b\" / \"c\")` is `Option[ModelNode]`, reading nested model nodes is safe even if\nsome children in the path do not exist. In this case `None` wil be returned:\n\n```scala\nval nope = node.get(\"level0\" / \"oops\" / \"level2\" / \"level3\")\n```\n\n## Reading Values\n\nYou can use the folowing methods to read values from model nodes:\n\n- `ModelNode.asBoolean`\n- `ModelNode.asInt`\n- `ModelNode.asLong`\n- `ModelNode.asBigInt`\n- `ModelNode.asDouble`\n- `ModelNode.asString`\n\nThese methods return `Option` instances of the relevant type. This is because not all conversions make sense on all kind of\nmodel nodes:\n\n```scala\nval node = ModelNode(\n  \"flag\" -\u003e true,\n  \"child\" -\u003e ModelNode(\n    \"size\" -\u003e 0\n  )\n)\n\nval nonsense = node(\"child\").asDouble // None\n```\n\n## Writing\n\nSimple values can be set using `node(\"foo\") = \"bar\"`. If \"foo\" doesn't exist it will be created and updated\notherwise. As an alternative you can use the `+=` operator, which comes in handy if you want to add multiple\nkey / value pairs:\n\n```scala\nval node = ModelNode()\n\nnode(\"foo\") = \"bar\"\nnode += (\"foo\" -\u003e \"bar\")\n\nnode += (\n  \"flag\" -\u003e true,\n  \"hello\" -\u003e \"world\",\n  \"answer\" -\u003e 42,\n  \"child\" -\u003e ModelNode(\n    \"inner-a\" -\u003e 123,\n    \"inner-b\" -\u003e \"test\",\n    \"deep-inside\" -\u003e ModelNode(\n      \"foo\" -\u003e \"bar\"\n    ),\n    \"deep-list\" -\u003e List(\n      ModelNode(\"one\" -\u003e 1),\n      ModelNode(\"two\" -\u003e 2),\n      ModelNode(\"three\" -\u003e 3)\n    )\n  )\n)\n```\n\nReading and writing can also be combined in one call:\n\n```scala\nnode(\"child\" / \"deep-inside\") += (\"foo\" -\u003e \"xyz\")\n```\n\n## Collection Operations\n\nSince `ModelNode` mixes in `Traversable[(String, ModelNode)]` you can use all those nifty collection methods like\n`foreach`, `map` or `filter`:\n\n```scala\nval node = ModelNode(\n  \"flag\" -\u003e true,\n  \"hello\" -\u003e \"world\",\n  \"answer\" -\u003e 42\n)\n\n// turn all keys to upper case\nval shout = node.map(kv =\u003e kv._1.toUpperCase -\u003e kv._2)\n\n// filter for nodes\nval aa = node.filter(_._1 contains \"a\")\nval n42 = node.filter(_._2 == ModelNode(42))\n\n// combine nodes\nval node2 = node ++ ModelNode(\"abc\" -\u003e 1)\n```\n\nPlease note that these kind of methods only traverse over the direct children of a model node. If you want to traverse\nover all children in a deeply nested model node use the `inOrder` method which gives you a list\nof `(String, ModelNode)` tuples:\n\n```scala\nval node = ModelNode(\n  \"flag\" -\u003e true,\n  \"answer\" -\u003e 42,\n  \"child\" -\u003e ModelNode(\n    \"inner-a\" -\u003e 123,\n    \"inner-b\" -\u003e \"test\",\n    \"deep-inside\" -\u003e ModelNode(\"foo\" -\u003e \"bar\"),\n    \"deep-list\" -\u003e List(\n      ModelNode(\"one\" -\u003e 1),\n      ModelNode(\"two\" -\u003e 2)\n    ),\n    \"value-list\" -\u003e List(\n      ModelNode(1),\n      ModelNode(2)\n    )\n  )\n)\n\nnode.inOrder map { tpl =\u003e tpl._1 }\n// will result in List(flag, answer, child, inner-a, inner-b, deep-inside, foo, deep-list, one, two, value-list)\n```\n\n## Pattern Matching / Extractor\n\nModel nodes support pattern matching / extractor against their type:\n\n```scala\nval node = ModelNode(\n  \"flag\" -\u003e true,\n  \"hello\" -\u003e \"world\",\n  \"answer\" -\u003e 42,\n  \"one\" -\u003e 1,\n  \"two\" -\u003e 2\n)\n\nimport org.jboss.dmr.ModelType._\nfor ((key, node) \u003c- node) node match {\n  case ModelNode(INT) =\u003e println(s\"$key is an integer: $node\")\n  case ModelNode(t) =\u003e println(s\"$key is not an integer, but $t\")\n}\n\nval (key, firstNode) = node.head\nval ModelNode(booleanType) = firstNode\n// booleanType == org.jboss.dmr.ModelType.BOOLEAN\n\nval integerNodes = for {\n  (key, node) \u003c- node\n  ModelNode(t) = node\n  if t == INT\n} yield node\n// results in List(42, 1, 2)\n```\n\n## Composites\n\nA composite operation is setup using the `ModelNode.composite(n: ModelNode, xn: ModelNode*)` factory method:\n\n```scala\nModelNode.composite(\n  ModelNode() at (\"core-service\" -\u003e \"management\") / (\"access\" -\u003e \"authorization\") op 'read_resource(\n    'recursive_depth -\u003e 2),\n  ModelNode() at (\"core-service\" -\u003e \"management\") / (\"access\" -\u003e \"authorization\") op 'read_children_names(\n    'name -\u003e \"role-mapping\"),\n  ModelNode() at (\"subsystem\" -\u003e \"mail\") / (\"mail-session\" -\u003e \"*\") op 'read_resource_description,\n  ModelNode() at (\"subsystem\" -\u003e \"datasources\") / (\"data-source\" -\u003e \"ExampleDS\") op 'disable ,\n  ModelNode() at (\"core-service\" -\u003e \"platform-mbean\") / (\"type\" -\u003e \"runtime\") op 'read_attribute(\n    'name -\u003e \"start-time\")\n)\n```\n\n## Execute an operation\n\nTo execute DMR operations against a running WildFly instance use [DMR.repl](https://github.com/hal/dmr.repl).\nThe `Response` object has an extractor and constants to parse the DMR response using pattern matching. The pattern\nmatching variables `result` and `failure` are both model nodes containing the response payload or the wrapped error\ndescription:\n\n```scala\nval client = connect()\nval node = ModelNode() at (\"subsystem\" -\u003e \"datasources\") op 'read_resource\n\nimport org.jboss.dmr.repl.Response\nimport org.jboss.dmr.repl.Response.{Success, Failure}\n(client ! node) map {\n  case Response(Success, result) =\u003e ...\n  case Response(Failure, failure) =\u003e ...\n}\n\nimport scala.util.{Success, Failure}\n(client ? node).onComplete {\n  case Success(response) =\u003e ...\n  case Failure(ex) =\u003e ...\n}\n```\n\n# REPL Shell\n\n## Connect\n\nTo make use of DMR.repl, first thing you'll need is a client for a WildFly server.\n\n```scala\nimport org.jboss.dmr.repl.Client._\n\n// Creates a client and connects to 127.0.0.1:9999\nval client  = connect()\n\n// Connects to specified host:port\nval client = connect(\"homer\", 9876)\n```\n\n## Execute DMR Operations\n\nTo execute an operation you can choose between `!` for synchronous and `?` for asynchronous execution. The\nsynchronous method returns with a `Try[ModelNode]`, the asynchronous with a `Future[ModelNode]`.\n\n### Synchronous\n\n```scala\nimport org.jboss.dmr.repl.Response.{Success, Failure}\nval node = ModelNode() at (\"subsystem\" -\u003e \"datasources\") op 'read_resource\n\n(client ! node) map {\n  case Response(Success, result) =\u003e ...\n  case Response(Failure, failure) =\u003e ...\n}\n```\n\n### Asynchronous\n\n```scala\nimport scala.util.{Success, Failure}\nval node = ModelNode() at (\"subsystem\" -\u003e \"datasources\") op 'read_resource\n\n(client ? node).onComplete {\n  case Success(response) =\u003e ...\n  case Failure(ex) =\u003e ...\n}\n```\n\nWhen executing DMR operations, you can make use of some handy extractors which will return the actual payload of a DMR\nresponse / composite response. If you execute a DMR operation like this\n\n```scala\nval node = ModelNode() at (\"subsystem\" -\u003e \"datasources\") op 'read_resource\nval response = client ! node getOrElse ModelNode.Undefined\n```\n\n`response` will contain the full response:\n\n```\n{\n    \"outcome\" =\u003e \"success\",\n    \"result\" =\u003e {\n        \"data-source\" =\u003e {\"ExampleDS\" =\u003e undefined},\n        \"jdbc-driver\" =\u003e {\"h2\" =\u003e undefined},\n        \"xa-data-source\" =\u003e undefined\n    }\n}\n```\n\nIf you're just interested in the result, use\n\n```scala\nval Response(Success, result) = response\n```\n\nwhich will assign a model node to `result` containing just the payload:\n\n```\n{\n    \"data-source\" =\u003e {\"ExampleDS\" =\u003e undefined},\n    \"jdbc-driver\" =\u003e {\"h2\" =\u003e undefined},\n    \"xa-data-source\" =\u003e undefined\n}\n```\n\nThe same applies to composite operations:\n\n```scala\nval d1 = ModelNode() at (\"deployment\" -\u003e \"foo.war\") op 'read_resource\nval d2 = ModelNode() at (\"deployment\" -\u003e \"bar.war\") op 'read_resource\nval comp = ModelNode.composite(d1, d2)\nval response = client ! comp getOrElse ModelNode.Undefined\n```\n\nAgain `response` will contain the full response with the all steps and nested responses:\n\n```\n{\n    \"outcome\" =\u003e \"success\",\n    \"result\" =\u003e {\n        \"step-1\" =\u003e {\n            \"outcome\" =\u003e \"success\",\n            \"result\" =\u003e {\n                \"name\" =\u003e \"foo.war\",\n                ...\n            }\n        },\n        \"step-2\" =\u003e {\n            \"outcome\" =\u003e \"success\",\n            \"result\" =\u003e {\n                \"name\" =\u003e \"bar.war\",\n                ...\n            }\n        }\n    }\n}\n```\n\nTo extract just the nested result nodes, use the `Composite` extractor:\n\n```scala\nval Composite(Success, steps) = response\n```\n\nwhich will give you a `List[ModelNode]`:\n\n```scala\nList(\n{\n    \"name\" =\u003e \"foo.war\",\n    ...\n},\n{\n    \"name\" =\u003e \"bar.war\",\n    ...\n})\n\n```\n\n## DMR Scripts\n\nIf you have a more advanced use cases or want to chain several operations, scripts are the way to go. To write a script\ncreate a subclass of `Script` and override the `code` method. Scripts carry a type parameter for the expected result.\nFurthermore they rely on an implicit client instance which is brought into scope by the clients companion object. So\nplease make sure you `import org.jboss.dmr.repl.Client._` when you run your script.\n\n```scala\nimport scala.concurrent.duration._\nimport scala.util.Try\nimport org.jboss.dmr.scala._\nimport org.jboss.dmr.repl._\nimport org.jboss.dmr.repl.Response._\n\n/** Returns the uptime for the standalone server */\nclass Uptime extends Script[Duration] {\n  def code: Try[Duration] = {\n    val node = ModelNode() at (\"core-service\" -\u003e \"platform-mbean\") / (\"type\" -\u003e \"runtime\") op 'read_attribute('name -\u003e \"uptime\")\n    client ! node map {\n      case Response(Success, result) =\u003e result.asLong.get.millis\n      case Response(Failure, failure) =\u003e throw new ScriptException(failure)\n    }\n  }\n}\n```\n\nExecute a script using its run method:\n\n```scala\nimport org.jboss.dmr.repl.Client._\n\nconnect()\nval uptime = new Uptime().run()\n```\n\nPlease see the [samples](src/main/scala/org/jboss/dmr/repl/samples) package for more advanced\nsamples.\n\n## Local Storage\n\nYou can save and load model nodes to and from the local file system. By default they are written as base64\nto `~/.sbt/node_\u003ccounter\u003e`, but you can choose another folder and/or filename.\n\n```scala\nval node = ModelNode() at (\"core-service\" -\u003e \"platform-mbean\") / (\"type\" -\u003e \"runtime\") op 'read_resource(\n  'attributes_only -\u003e true,\n  'include_runtime -\u003e false,\n  'recursive_depth -\u003e 3,\n  'custom_parameter -\u003e \"custom-value\"\n)\n\n// Uses an implicit conversion and the default folder and filename\nnode.save()\n\n// Uses a storage using the folder 'nodes' in the current folder and saves the node as 'mbean'\nval storage = new Storage(new java.io.File(\"nodes\"))\nstorage.save(node, \"mbean\")\n\n// load by name\nval copy = storage.load(\"mbean\")\n\n// get rid of the saved node\nstorage.remove(\"mbean\")\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhal%2Fdmr.repl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhal%2Fdmr.repl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhal%2Fdmr.repl/lists"}