{"id":38699105,"url":"https://github.com/research-virtualfortknox/msb-client-websocket-java","last_synced_at":"2026-01-17T10:44:45.060Z","repository":{"id":41225920,"uuid":"192681993","full_name":"research-virtualfortknox/msb-client-websocket-java","owner":"research-virtualfortknox","description":"The java client library to connect to the websocket interface of the MSB (Manufacturing Service Bus)","archived":false,"fork":false,"pushed_at":"2025-11-03T10:32:25.000Z","size":609,"stargazers_count":5,"open_issues_count":10,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-11-03T12:17:14.703Z","etag":null,"topics":["java","msb","msb-client","msb-client-websocket","websocket-interface"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/research-virtualfortknox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":".github/MAINTAINERS.md","copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-06-19T07:31:48.000Z","updated_at":"2025-07-08T13:10:01.000Z","dependencies_parsed_at":"2023-11-29T16:52:00.115Z","dependency_job_id":"9da8c009-c395-4dd5-93e3-42f7dd73d4c0","html_url":"https://github.com/research-virtualfortknox/msb-client-websocket-java","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/research-virtualfortknox/msb-client-websocket-java","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/research-virtualfortknox%2Fmsb-client-websocket-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/research-virtualfortknox%2Fmsb-client-websocket-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/research-virtualfortknox%2Fmsb-client-websocket-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/research-virtualfortknox%2Fmsb-client-websocket-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/research-virtualfortknox","download_url":"https://codeload.github.com/research-virtualfortknox/msb-client-websocket-java/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/research-virtualfortknox%2Fmsb-client-websocket-java/sbom","scorecard":{"id":355521,"data":{"date":"2025-08-11","repo":{"name":"github.com/research-virtualfortknox/msb-client-websocket-java","commit":"5e9f22d22099a2470fd39df1b7a191b1cb98eefe"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.5,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/17 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":10,"reason":"14 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'contents' permission set to 'read': .github/workflows/codeql.yml:17","Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql.yml:16","Warn: no topLevel permission defined: .github/workflows/codeql.yml:1","Warn: no topLevel permission defined: .github/workflows/label.yml:1","Warn: no topLevel permission defined: .github/workflows/maven-central-publish.yml:1","Warn: no topLevel permission defined: .github/workflows/maven-publish.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/research-virtualfortknox/msb-client-websocket-java/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:30: update your workflow using https://app.stepsecurity.io/secureworkflow/research-virtualfortknox/msb-client-websocket-java/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:36: update your workflow using https://app.stepsecurity.io/secureworkflow/research-virtualfortknox/msb-client-websocket-java/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:39: update your workflow using https://app.stepsecurity.io/secureworkflow/research-virtualfortknox/msb-client-websocket-java/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/label.yml:10: update your workflow using https://app.stepsecurity.io/secureworkflow/research-virtualfortknox/msb-client-websocket-java/label.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven-central-publish.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/research-virtualfortknox/msb-client-websocket-java/maven-central-publish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven-central-publish.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/research-virtualfortknox/msb-client-websocket-java/maven-central-publish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven-publish.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/research-virtualfortknox/msb-client-websocket-java/maven-publish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven-publish.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/research-virtualfortknox/msb-client-websocket-java/maven-publish.yml/master?enable=pin","Warn: downloadThenRun not pinned by hash: .github/workflows/maven-publish.yml:48","Info:   0 out of   9 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 downloadThenRun dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":10,"reason":"SAST tool detected","details":["Info: SAST configuration detected: CodeQL","Info: SAST configuration detected: Sonar","Warn: 0 commits out of 24 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":5,"reason":"5 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-5mg8-w23w-74h3","Warn: Project is vulnerable to: GHSA-7g45-4rm6-3mm3","Warn: Project is vulnerable to: GHSA-j288-q9x7-2f5v","Warn: Project is vulnerable to: GHSA-4gc7-5j7h-4qph","Warn: Project is vulnerable to: GHSA-4wrc-f8pq-fpqp"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T09:28:58.872Z","repository_id":41225920,"created_at":"2025-08-18T09:28:58.872Z","updated_at":"2025-08-18T09:28:58.872Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28506593,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T10:25:30.148Z","status":"ssl_error","status_checked_at":"2026-01-17T10:25:29.718Z","response_time":85,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["java","msb","msb-client","msb-client-websocket","websocket-interface"],"created_at":"2026-01-17T10:44:44.212Z","updated_at":"2026-01-17T10:44:45.048Z","avatar_url":"https://github.com/research-virtualfortknox.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Apache 2.0 License](https://img.shields.io/:license-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.research-virtualfortknox/msb-client-websocket/badge.svg?color=blue)](https://maven-badges.herokuapp.com/maven-central/com.github.research-virtualfortknox/msb-client-websocket)\n[![Javadoc](https://javadoc.io/badge2/com.github.research-virtualfortknox/msb-client-websocket/javadoc.svg?color=blue)](https://javadoc.io/doc/com.github.research-virtualfortknox/msb-client-websocket)\n[![SourceSpy Dashboard](https://sourcespy.com/shield.svg)](https://sourcespy.com/github/researchvirtualfortknoxmsbclientwebsocketjava/)\n\n[![Maven Package](https://github.com/research-virtualfortknox/msb-client-websocket-java/actions/workflows/maven-publish.yml/badge.svg)](https://github.com/research-virtualfortknox/msb-client-websocket-java/actions/workflows/maven-publish.yml)\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=research-virtualfortknox_msb-client-websocket-java\u0026metric=alert_status)](https://sonarcloud.io/dashboard?id=research-virtualfortknox_msb-client-websocket-java)\n[![Known Vulnerabilities](https://snyk.io/test/github/research-virtualfortknox/msb-client-websocket-java/badge.svg)](https://snyk.io/test/github/research-virtualfortknox/msb-client-websocket-java)\n[![Coverage Status](https://coveralls.io/repos/github/research-virtualfortknox/msb-client-websocket-java/badge.svg?branch=master)](https://coveralls.io/github/research-virtualfortknox/msb-client-websocket-java?branch=master)\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fresearch-virtualfortknox%2Fmsb-client-websocket-java.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fresearch-virtualfortknox%2Fmsb-client-websocket-java?ref=badge_shield)\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://research.virtualfortknox.de\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\n    \u003cimg src=\"https://research.virtualfortknox.de/static/cms/img/vfk_research_logo.png\" alt=\"VFK Research Logo\" height=\"70\" \u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n# MSB websocket client library for Java\n\n**Compatibility Matrix**\n\nClient version compatibility to MSB versions:\n\n| | **1.5.x-RELEASE** | **1.6.x-RELEASE** |\n|---|:---:|:---:|\n| 1.0.x       | x | x |\n\n## Welcome\n\nIf you want to contribute, please read the [Contribution Guidelines](.github/CONTRIBUTING.md).\n\nIf you want to test this client by using the example project.\n\nIf you want to know how to use this client in your own project, read below.\n\n## What is VFK MSB\n\nTODO: Link to general documentation about VFK MSB\n\nYou can use this client to connect a java app to VFK MSB.\n\n## Prerequisites\n\nImport to your application via maven\n\n```xml\n\u003cproperties\u003e\n    ...\n    \u003c!-- Use the latest version whenever possible. --\u003e\n    \u003cmsb-client-websocket.version\u003e1.0.6-RELEASE\u003c/msb-client-websocket.version\u003e\n    ...\n\u003c/properties\u003e\n\n\u003cdependencies\u003e\n    ...\n    \u003cdependency\u003e\n      \u003cgroupId\u003ecom.github.research-virtualfortknox\u003c/groupId\u003e\n      \u003cartifactId\u003emsb-client-websocket\u003c/artifactId\u003e\n      \u003cversion\u003e${msb-client-websocket.version}\u003c/version\u003e\n    \u003c/dependency\u003e\n    ...\n\u003c/dependencies\u003e\n```\n\n## Create self-description\n\nThe figure below shows a minimal required `self-description model` of a smart object / application.\nEvery smart object / application requires (must have) a uuid and a token.\nThe uuid is competent for identification\nand the token is used to verify the smart object / application for its owner on the MSB side.\n\n![Self Description](doc/images/self-description.png)\n\nThe data model of an application and smart object is identical, both are services.\nA smart object represents a physical object which is connected to MSB. \nAn application is a pure software solution which is connected.\n\nEach service is capable of triggering events and receiving function calls.\nThe declaration of these elements and the service can be done with the help of annotations or by the constructor.\n\nAn **annotation** is a form of syntactic metadata or a specific marker that can be added to Java source code but has no effect on a program construct at run time [see 1]. \nThe annotated instances can be classes, methods, variables, parameters, and packages. \nAnnotations are embedded in class files and may be retained by the Java VM to become retrievable at run time [see 2, S. 67].\n\nTODO: Here you can find more information about the `self-description structure` and `supported data formats`.\n\n#### Alternative 1 - By annotations:\n\nDeclaration of self description:\n\n  - Annotation `@SelfDescription` describes the service\n\n```java\n@SelfDescription(\n    uuid = \"df61a143-6dab-471a-88b4-8feddb4c9e71\",\n    name = \"Drill Machine\",\n    description = \"A small drill-machine, which reminding you of your last visit to the dentist.\",\n    token = \"57e721c9bcdf\",\n    type = SelfDescription.Type.SMART_OBJECT\n)\npublic class DrillMachine {\n    // …\n}\n```\n\n#### Alternative 2 - By constructor:\n\nIf you do not wan to use annotations, use the constructor to define the basic self-description.\n\n```java\npublic class DrillMachine {\n    // …\n    SmartObject smartObject = new SmartObject(uuid, name, description, token);\n    // …\n}\n```\n\n### Add Events\n\nAdd `events` to your smart object or application which can be send to MSB.\n\n#### Alternative 1 - By annotation:\n\nDeclaration of thrown events:\n\n  - Annotation `@Events` excepts a list of event declarations\n  - Annotation `@EventDeclaration` describes the event\n\n```java\n@Events({\n    @EventDeclaration(dataType = Date.class,description = \"Timestamp of start machine\",name = \"Start\", eventId = \"START\"),\n    @EventDeclaration(dataType = Date.class,description = \"Timestamp of stop machine\",name = \"Stop\", eventId = \"STOP\"),\n    @EventDeclaration(description = \"periodical transmitted event\", name = \"Event pulse\", eventId = \"PULSE\")\n})\n// …\npublic class DrillMachine {\n    // …\n}\n```\n\n#### Alternative 2 - By constructor:\n\nThe event declaration can be added directly to the created service instance.\n\n```java\npublic class DrillMachine {\n    // …\n    public void constructSelfDescription() {\n        SmartObject smartObject = new SmartObject(uuid, name, description, token);\n        smartObject.addEvent(new Event(\"TEMPERATURE\", \"Temperature\", \"Current temperature\", DataFormatParser.parse(float.class)));\n        // …\n    }\n}\n```\n\nOr it can be added via the `MsbClientHandler`.\n\n```java\npublic class DrillMachine {\n    // …\n    public void constructSelfDescription() {\n        // …\n        MsbClientHandler handler = msbClient.getClientHandler();\n        handler.addEvent(smartObject, \"TEMPERATURE\", \"Temperature\", \"Current temperature\", float.class, EventPriority.MEDIUM);\n        // …\n    }\n}\n```\n\n### Add Functions\n\nAdd `functions` and their implementations your smart object or application is able to handle.\n\n#### Alternative 1 - By annotation:\n\nDeclaration of callable functions:\n\n  - Annotation `@FunctionHandler` signs to a class for package scanning which contains the function calls\n  - Annotation `@FunctionCall` signs to a method of this class to make the method be callable over the MSB. \n    The combination of the `FunctionHandler` and `FunctionCall` path must be a unique identifier for this method. \n    An optional parameter are the responseEvents, which contains a list of before decelerated events. \n    This events are the possible return values of this method, which are pushed to the MSB.\n  - Annotation `@FunctionParam` sings to a parameter in question\n\n```java\n@FunctionHandler(path=\"/controller\")\npublic class DrillMachineController {\n\n    @FunctionCall(path=\"/start\", description = \"start processing\", responseEvents = {\"START\",\"STOP\"})\n    public MultipleResponseEvent startProcessing(@FunctionParam(name = \"drilling_depth\") int drillingDepth) {\n      MultipleResponseEvent multipleResponseEvent = new MultipleResponseEvent();\n      // …\n      if(started) {\n        multipleResponseEvent.addResponseEvent(\"START\",new Date());\n      } else {\n        multipleResponseEvent.addResponseEvent(\"STOP\",new Date());\n      }\n      return multipleResponseEvent;\n    }\n\n    @FunctionCall(path=\"/stop\", description = \"stop processing\", responseEvents = {\"STOP\"})\n    public Date stopProcessing() {\n      // …\n      return new Date();\n    }\n    \n    public void printString(String msg){\n        \n    }\n\n}\n```\n\nThe return value of the method call is used for publishing a response event. \nThis must therefore correspond to the defined `dataType` of the event referenced in the parameter `responseEvent` of the `FunctionCall` annotation.\nFor several possible response events there is a special wrapper object `MultipleResponseEvent`. \nWhen publishing the response events, the `correlationId` of the function call is automatically added to the event.\n\n#### Alternative 2 - By constructor:\n\nThe function declaration can be added to the constructed service instance directly.\nMethod invocation not possible in this way, use `FunctionCallsListener` to observe function calls.\n\n```java\npublic class DrillMachine {\n    // …\n    public void constructSelfDescription() {\n        SmartObject smartObject = new SmartObject(uuid, name, description, token);\n        smartObject.addFunction(new Function(\"printString\", \"printString\", \"print a string\", DataFormatParser.parse(\"msg\",String.class)));\n        // …\n        MsbClientHandler handler = msbClient.getClientHandler();\n        handler.addFunctionCallsListener(functionCallsListener);\n    }\n    \n    FunctionCallsListener functionCallsListener = new FunctionCallsListener() {\n        @Override\n        public void onCallback(String serviceUuid, String functionId, String correlationId, Map\u003cString,Object\u003e functionParameters) {\n            // …\n        }\n    };\n}\n```\n\nTo utilize the method invocation without annotations, the `MsbClientHandler` can be used as follows.\n\n```java\npublic class DrillMachine {\n    // …\n    public void constructSelfDescription() {\n        SmartObject smartObject = new SmartObject(uuid, name, description, token);\n        // …\n        MsbClientHandler handler = msbClient.getClientHandler();\n        // …\n        try {\n            Method stringMethod = TestClientFunctionHandler.class.getMethod(\"printString\", String.class);\n            handler.addFunction(smartObject, \"printString\", \"printString\", \"print a string\", new String[]{\"PULSE\"}, new DrillMachineController(), stringMethod);\n        } catch (NoSuchMethodException e) {\n            LOG.error(\"NoSuchMethodException\",e);\n        }\n\n       \n    }\n}\n```\n\n### Configuration parameters\n\nConfiguration parameters are a simple list of key value pairs for the smart object or application.\nIt is displayed and can be customized in the MSB UI to change your apps behaviour during runtime.\n\n#### Alternative 1 - By annotation:\n\nYou can add a configuration parameter declarative with the annotation `@ConfigParam` for a class attribute. \nNote that the class need be also annotated with `@SelfDescription`, `@EventDeclaration` or `@FunctionHandler`.\n\n```java\n@SelfDescription(\"...\")\npublic class DrillMachineController {\n\n    @ConfigurationParam(name = \"drilling_speed\")\n    public int drillingSpeed = 100;\n    // …\n}\n```\n\n#### Alternative 2 - By constructor:\n\nThe configurations parameters can be added to the constructed service instance directly or via the `MsbClientHandler`.\n\n```java\npublic class DrillMachine {\n    // …\n    public void constructSelfDescription() {\n        Map\u003cString, ParameterValue\u003e parameters = new HashMap\u003c\u003e();\n        parameters.put(\"drillingSpeed\", new ParameterValue(100, PrimitiveType.INTEGER, PrimitiveFormat.INT32));\n        parameters.put(\"scheduled\", new ParameterValue(true, PrimitiveType.BOOLEAN));\n        Configuration configuration = new Configuration(parameters);\n        \n        SmartObject smartObject = new SmartObject(uuid, name, description, token);\n        smartObject.setConfiguration(configuration);\n        // …\n        MsbClientHandler handler = msbClient.getClientHandler();\n        handler.addConfigParam(\"drillingSpeed\", \"100\", PrimitiveFormat.INT32);\n        // …\n    }\n}\n```\n\n#### React on configuration change:\n\nTo observe configuration parameter updates (after changed in MSB UI) to change your app behaviour, a `ConfigurationListener` implementation must be provided.\n\n```java\npublic class DrillMachine {\n    // …\n    public void constructSelfDescription() {\n        MsbClientHandler handler = msbClient.getClientHandler();\n        // …\n        handler.addConfigurationListener(configurationListener);\n    }\n    \n    ConfigurationListener configurationListener = new ConfigurationListener() {\n        @Override\n        public void configurationRemoteChanged(ConfigurationMessage configuration) {\n            // ...\n        }\n    };\n}\n```\n\n## Connect and Register Client\n\nThe `MsbClientHandler` provides register methods for passing a package path. \nThe package path specifies the root package from which the annotations are searched. \nSo it is a good idea to use this variant of registration if annotation is used to create the self-description of the service.\n\n```java\npublic class DrillMachine { \n    // …\n    public void startClient() {\n        final String url = \"ws://127.0.0.1:8085\";\n        MsbClient msbClient = new MsbClient.Builder().url(url).build();\n        Future\u003cMsbClientHandler\u003e future = msbClient.connect();\n        try {\n            MsbClientHandler handler = future.get();\n            handler.register(\"de.fhg.ipa.vfk.msb.client.websocket.test\");\n        } catch (InterruptedException | ExecutionException | IOException e){\n            // …\n      }\n      // …\n  }\n}\n```\n\nIf the self-description is created using constructor, the `MsbClientHandler` also provides register methods for it, as in the following example.\n\n```java\npublic class DrillMachine { \n    // …\n    public void startClient(SmartObject smartObject) {\n        // …\n        try {\n            handler.register(smartObject);\n        } catch (InterruptedException | ExecutionException | IOException e){\n            // …\n      }\n      // …\n  }\n}\n```\n\nTo use certain instances of the classes with `@FunctionHandler`annotation for the method invocation, these can also be passed during registration.\n\n```java\npublic class DrillMachine { \n    // …\n    public void startClient(SmartObject smartObject) {\n        // …\n        try {\n            handler.register(\"de.fhg.ipa.vfk.msb.client.websocket.test\", new Object[]{new DrillMachineController()});\n        } catch (InterruptedException | ExecutionException | IOException e){\n            // …\n      }\n      // …\n  }\n}\n```\n\nThese were only a few examples there are still more variants of the register method.\n\nYou will get an `IO_CONNECTED` and `IO_REGISTERED` event from MSB, if successful. \nThis can be observed by adding a `ConnectionListener` to the `MsbClientHandler` instance.\n\n## Event publishing\n\nFor publishing an event to a MSB websocket interface,\nonly the `eventId` and `data` are required of the already specified event (see above).\n\n```java\npublic class DrillMachine { \n    // …\n    public void publishStartEvent() {\n        MsbClientHandler handler = msbClient.getClientHandler();\n        handler.publish(\"START\", new Date()); \n    }\n    // …\n}\n```\n\nThe MSB responds with an `IO_PUBLISHED` event, if successful. \nThis can be observed by adding a `ConnectionListener` to the `MsbClientHandler` instance.\n\nBy default events are published with a low priority.\n\nIt is also possible to `set the priority` of an event.\n\nThere are three possible priorities for events like it is shown at the following table.\n\n| `Constant` | `Value` |\n|:---:|:---:|\n| LOW | 0 |\n| MEDIUM| 1 |\n| HIGH| 2 |\n\n```java\npublic class DrillMachine { \n    // …\n    public void publishHighStartEvent() {\n        MsbClientHandler handler = msbClient.getClientHandler();\n        handler.publish(\"START\", new Date(), EventPriority.HIGH);\n    }\n    // …\n}\n```\n\nAnother option is to publish an event as a cached event by setting the cache parameter to true or false, \nwhich deviates the behavior from the global cache setting.\n\nIf it is set to true, this means that the event is not deleted if the connection is broken.\n\n```java\npublic class DrillMachine { \n    // …\n    public void publishUncachedStartEvent() {\n        MsbClientHandler handler = msbClient.getClientHandler();\n        handler.publish(\"START\", new Date(), EventPriority.LOW, true);\n    }\n    // …\n}\n```\n\n## Function call handling\n\nAs shown above the methods of a `@FunctionHandler` annotated class, which are annotated with `@FunctionCall`, are invokable by the client library. \nThis is done via reflection. It is also possible to pass a specific instance of a function handler to the client during the registration. \nOtherwise the client will create an instance of the function handler by itself. \nTo allow this the default constructor is required at function handler class.\n\nAs shown above, the annotated methods `@FunctionCall` of an annotated class `@FunctionHandler` are called from the client library. \nThis is done by reflection. It is also possible to pass a particular instance of a function handler to the client during registration. \nOtherwise, the client itself creates an instance of the function handler. \nTo enable this, the default constructor is required in the function handler class.\n\nThe function invocation can be disabled and function calls can be handled by your own listener implementation.\n\n```java\npublic class DrillMachine { \n    // …\n    public void startClient() {\n        final String url = \"wss://127.0.0.1:8084\";\n        MsbClient msbClient = new MsbClient.Builder().url(url).disableFunctionCallsInvocation().build();\n       // …\n   }\n }\n ```\n\n## SSL/TLS connection configuration\n\nTo enable `SSL/TLS`, you need to specify wss:// or https:// in the URL instead of ws:// or http://.\n\nFurthermore, it is necessary to specify a trust store in the client,\nwhich contains the public certificate of the MSB interface, so that it is considered trustworthy.\n\n```java\npublic class DrillMachine { \n    // …\n    public void startClient() {\n        final String url = \"wss://127.0.0.1:8084\";\n        final String trustStore = \"./truststore.trs\";\n        final String password = \"password\";\n        MsbClient msbClient = new MsbClient.Builder().url(url).trustStore(trustStore, password).build();\n      // …\n  }\n}\n```\n\nOpen websocket interface in the browser and export the certificate. \nChoose the `X.509 Certificate (DER)` type, so the exported file has a der extension.\nAssuming the file is called msb.der, pick the alias 'msb' for this certificate.\n\nOr you use the `openssl s_client` to export the certificate (https://www.openssl.org/docs/man1.1.1/man1/s_client.html)\n\n```sh\n$ openssl s_client -host 127.0.0.1 -port 8084 -prexit -showcerts\n```\n\nNow you can create a new truststore and use it as shown above, e.g. with the following command.\n\n```sh\n$ keytool -import -file msb.der -alias msb -keystore CERTS.trs\n```\n\nOr you can import the certificate into the existing truststore of your local JVM installation that is used to run the client.\nYou will be asked for a password, the default is 'changeit'.\n\n```sh\n$ keytool -import -alias msb -keystore  \u003cpath-to-jre\u003e/lib/security/cacerts -file msb.der\n```\n\nIf you use an IP instead of a public url during development,\nit will be necessary to disable the hostname verification to connect via web socket secure.\n\n```java\npublic class DrillMachine { \n    // …\n    public void startClient() {\n        final String url = \"wss://127.0.0.1:8084\";\n        final String trustStore = \"./truststore.trs\";\n        final String password = \"password\";\n        MsbClient msbClient = new MsbClient.Builder().url(url).trustStore(trustStore, password).disableHostnameVerification().build();\n      // …\n  }\n}\n```\n\n## Connection recovery\n\nIf connection to the common websocket interface is broken the client performs a reconnect.\n\nAfter a reconnect the registration at the MSB will be redone automatically by the client.\n\nYou can also change this interval by setting an integer value in `ms` for the reconnect interval.\n\n```java\npublic class DrillMachine { \n    // …\n    public void startClient() {\n        final String url = \"ws://127.0.0.1:8085\";\n        MsbClient msbClient = new MsbClient.Builder().url(url).reconnectInterval(10000).build();\n      // …\n  }\n}\n```\n\nOr you can disable the automatic reconnect.\n\n```java\npublic class DrillMachine { \n    // …\n    public void startClient() {\n        final String url = \"ws://127.0.0.1:8085\";\n        MsbClient msbClient = new MsbClient.Builder().url(url).disableAutoReconnect().build();\n      // …\n  }\n}\n```\n\n## Event caching\n\nIf the client loses the connection, the published events are cached in a queue.\n\nAfter a successful reconnection, the queued events are published to MSB (FIFO principle).\nThe default size of the queue is 1000 entries. The size can be changed:\n\n```java\npublic class DrillMachine { \n    // …\n    public void startClient() {\n        final String url = \"ws://127.0.0.1:8085\";\n        MsbClient msbClient = new MsbClient.Builder().url(url).eventCacheSize(9999).build();\n      // …\n  }\n}\n```\n\nIf no event caching is needed, you can disable it.\n\n```java\npublic class DrillMachine { \n    // …\n    public void startClient() {\n        final String url = \"ws://127.0.0.1:8085\";\n        MsbClient msbClient = new MsbClient.Builder().url(url).disableEventCache().build();\n      // …\n  }\n}\n```\n\n## Debug mode\n\nIt might be also helpful to enable data format validation, to check if an event value is valid\n\n```java\npublic class DrillMachine { \n    // …\n    public void startClient() {\n        final String url = \"ws://127.0.0.1:8085\";\n        MsbClient msbClient = new MsbClient.Builder().url(url).enabledDataFormatValidation().build();\n\n      // …\n  }\n}\n```\n\n## Logging\n\nLogging is implemented with [SLF4J (Simple Logging Facade for Java)](http://www.slf4j.org), which gives access to many logging frameworks \nsuch as Log4j, Logback or java.util.logging. This allows the end user to plug-in the desired logging framework. \nThis section shows how to use Logback as logging functionality without making any change in application code.\n\nIf you want to use [Logback](http://logback.qos.ch) for logging, you only need to add the logback-classic jar to the project dependency.\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ech.qos.logback\u003c/groupId\u003e\n  \u003cartifactId\u003elogback-classic\u003c/artifactId\u003e\n  \u003cversion\u003e${logback.version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nTo configure the log output, the configuration file logback.xml must be available at the root resource \nfolder src\\main\\resources. \nThe following examples illustrate how to set the root logger to INFO and a specific logger to DEBUG, \nwhich causes info, warning and error messages from all loggers in the application to be logged and also DEBUG for the specific logger:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003c!-- set log level in the logback.xml file --\u003e\n\n\u003cconfiguration\u003e\n  \u003cappender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\"\u003e\n    \u003clayout class=\"ch.qos.logback.classic.PatternLayout\"\u003e\n      \u003cPattern\u003e\n        %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\n      \u003c/Pattern\u003e\n    \u003c/layout\u003e\n  \u003c/appender\u003e\n\n  \u003croot level=\"INFO\"\u003e\n    \u003cappender-ref ref=\"STDOUT\"/\u003e\n  \u003c/root\u003e\n\n  \u003clogger name=\"de.fhg.ipa.vfk\" level=\"DEBUG\" /\u003e\n\n\u003c/configuration\u003e\n```\n\n\n## License\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fresearch-virtualfortknox%2Fmsb-client-websocket-java.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fresearch-virtualfortknox%2Fmsb-client-websocket-java?ref=badge_large)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fresearch-virtualfortknox%2Fmsb-client-websocket-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fresearch-virtualfortknox%2Fmsb-client-websocket-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fresearch-virtualfortknox%2Fmsb-client-websocket-java/lists"}