{"id":20569548,"url":"https://github.com/apache/aries-component-dsl","last_synced_at":"2025-04-14T16:35:19.142Z","repository":{"id":35127200,"uuid":"176955835","full_name":"apache/aries-component-dsl","owner":"apache","description":"Apache Aries component DSL","archived":false,"fork":false,"pushed_at":"2023-09-12T22:54:50.000Z","size":526,"stargazers_count":5,"open_issues_count":7,"forks_count":7,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-04-10T11:58:30.815Z","etag":null,"topics":["aries","java","library"],"latest_commit_sha":null,"homepage":"https://aries.apache.org/","language":"Java","has_issues":false,"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/apache.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-03-21T13:58:13.000Z","updated_at":"2022-07-15T23:05:18.000Z","dependencies_parsed_at":"2024-01-25T23:05:38.199Z","dependency_job_id":"b3e5a14b-4978-4171-9293-e067b66ee507","html_url":"https://github.com/apache/aries-component-dsl","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apache%2Faries-component-dsl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apache%2Faries-component-dsl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apache%2Faries-component-dsl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apache%2Faries-component-dsl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apache","download_url":"https://codeload.github.com/apache/aries-component-dsl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248666923,"owners_count":21142344,"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","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":["aries","java","library"],"created_at":"2024-11-16T05:08:43.138Z","updated_at":"2025-04-14T16:35:19.117Z","avatar_url":"https://github.com/apache.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# osgi-component-dsl\n\n[![Build Status](https://builds.apache.org/buildStatus/icon?job=Aries-component-dsl-master)](https://builds.apache.org/job/Aries-component-dsl-master)\n[![CI Build](https://github.com/rotty3000/aries-component-dsl/actions/workflows/maven.yml/badge.svg)](https://github.com/rotty3000/aries-component-dsl/actions/workflows/maven.yml)\n[![Maven Central](https://img.shields.io/maven-central/v/org.apache.aries.component-dsl/org.apache.aries.component-dsl.component-dsl.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22org.apache.aries.component-dsl%22%20AND%20a:%22org.apache.aries.component-dsl.component-dsl%22)\n\nA lightweight functional DSL to interact with OSGi registry.\n\nThis DSL provides a set of operations to fetch service references and\nconfigurations from OSGi, as well as to register services back into OSGi\nregistry. It also provides a way to create new custom operations.\n\n   *This documentation is still work in progress*\n\n## Why should I use it?\n\nOne of the benefits of using this DSL is that operations are automatically bound\nto the service or configuration intances that triggered their execution. This\nallows them to automatically undo (or clean) when those instances are no longer\navailable. This way the user of the DSL does not need to manually account for\nthe tracked instances and ensure the proper cleaning, which is a source of\nmistakes. For those cases in which manual assistance is needed, such as side\neffects management, the DSL facilitates specifying the undo operation together\nwith the side effect. This allows for better reutilization.\n\nThe DSL runs without the need for any additional runtime.\n\n## Quick start\n\nThe foundation of the DSL is one type `OSGi\u003cT\u003e`. There exist several static\nfunctions defined on the `OSGi` class that provide us with instances of the\ntype. Let's start getting a reference to a service:\n\n```java\nOSGi\u003cService\u003e program = OSGi.service(OSGi.serviceReferences(Service.class));\n```\n\nif we allow static imports from `OSGi` class we can type the former as:\n\n```java\nOSGi\u003cService\u003e services = service(serviceReferences(Service.class));\nOSGi\u003cDictionary\u003cString, ?\u003e\u003e configurations = configurations(\"factory-pid\");\n```\n\n### Combining operations\n\nOnce we have instances of `OSGi` we can combine them. We can use `flatMap` to\nspecify that one operation depends on a previous one. For example we could need\nto specify a filter for the services that comes in the configuration:\n\n```java\nOSGi\u003cService\u003e services = configurations(\"factory-pid\").flatMap(conf -\u003e\n\tservice(serviceReferences(Service.class, conf.get(\"service.filter\").toString()))\n);\n```\n\nwe can also register instances. For this purpose let's create a new class that\nwill hold instances of both `Dictionary\u003cString, ?\u003e` and `Service`.\n\n```java\nclass Holder {\n\n\tDictionary\u003cString, ?\u003e properties;\n\tService service;\n\n\tpublic Holder(Dictionary\u003cString, ?\u003e properties, Service service) {\n\t\tthis.properties = properties;\n\t\tthis.service = service;\n\t}\n\n}\n```\n\nand we can register instances of that class with:\n\n```java\nOSGi\u003cServiceRegistration\u003cHolder\u003e\u003e program = configurations(\"factory-pid\").flatMap(conf -\u003e\n\t\tservice(serviceReferences(Service.class, conf.get(\"service.filter\").toString())).flatMap(service -\u003e\n\t\t\tregister(Holder.class, new Holder(conf, service), new HashMap\u003c\u003e())));\n```\n\nin this example we are tracking factory configurations from pid\n`factory-pid`. For each configuration factory that's there, or that's created in\nthe future, we get the property `service.filter` and use it's value to track\nservices of type `Service` that match the filter in the configuration. Then, for\neach service that matches that filter and each configuration factory\ncombination we register one `Holder` instance.\n\nIf any of the configuration factories goes away, or any of the tracked services\ngoes away, the corresponding `Holder` instances will be unregistered\nautomatically, since the DSL tracks the effects each instance has produced.\n\n### Running the _program_\n\nIn the previous section we have gone through combining different operations to\nproduce new instances. These instances are values that describe how we are going\nto interact with OSGi and are immutable. You can use them to produce new\nprograms like reusable components.\n\nOnce you have a complete specification you can run it passing a `BundleContext`\nto it:\n\n```java\nOSGi\u003cT\u003e program;\nBundleContext bundleContext;\n\nOSGiResult result = program.run(bundleContext);\n```\n\nthe `OSGiResult` instance references the execution of the program. To stop and\nclean it we call:\n\n```java\nresult.close()\n```\n\n### Combinations without dependency\n\nwe can also specify combinations when there exist no dependencies between the\noperations. For instance we can declare we want to register a `Holder` for every\nconfiguration + service combination using `OSGi.combine`:\n\n```java\nOSGi\u003cHolder\u003e holders = combine(Holder::new, configurations(\"factory.pid\"), services(Service.class));\n```\n\n## Predefined Operations\n\nthe DSL comes with some common operations defined on the OSGi type. All these\noperations produce values of a type and keep track of the next operations. When\na tracked value goes away all the associated operations will be cleaned as well.\n\n### Configurations\n\nThere are two operations to deal with `Configuration Admin` configurations:\n`OSGi.configuration` to deal with singleton configurations and\n`OSGi.configurations` to deal with factory configurations.\n\n### Services\n\n`OSGi.serviceReferences` is a set of overloaded functions that return operations\nof type `OSGi\u003cCachingServiceReference\u003e`:\n\n```java\nOSGi\u003cCachingServiceReference\u003cT\u003e\u003e serviceReferences(Class\u003cT\u003e clazz)\n\nOSGi\u003cCachingServiceReference\u003cObject\u003e\u003e serviceReferences(String filterString)\n\nOSGi\u003cCachingServiceReference\u003cT\u003e\u003e serviceReferences(Class\u003cT\u003e clazz, String filterString)\n\nOSGi\u003cCachingServiceReference\u003cT\u003e\u003e serviceReferences(\n\tClass\u003cT\u003e clazz, String filterString,\n\tRefresher\u003c? super CachingServiceReference\u003cT\u003e\u003e onModified)\n\nOSGi\u003cCachingServiceReference\u003cT\u003e\u003e serviceReferences(\n\tClass\u003cT\u003e clazz, Refresher\u003c? super CachingServiceReference\u003cT\u003e\u003e onModified)\n\nOSGi\u003cCachingServiceReference\u003cObject\u003e\u003e serviceReferences(\n\tString filterString,\n\tRefresher\u003c? super CachingServiceReference\u003cObject\u003e\u003e onModified)\n```\n\n#### CachingServiceReference\u003cT\u003e\n\n This class is an explicit wrapper around `ServiceReference` (it DOES NOT\n implement `ServiceReference`) and provides methods to access underlying\n `ServiceReference` properties and caches them so future access to the\n same properties return the same values.\n\n Property values are cached *on demand*. Values that have never been\n queried through the method are not cached.\n\n Properties that did not exist when queried will no longer exist even though\n they were available at a later time in the underlying `ServiceReference`.\n\n This class was introduced because `ServiceReference` is mutable, which made it\n very difficult to operate on it within the DSL in a safe manner.\n\n#### Refresher\u003cT\u003e\n\nThis class is just an alias for `Predicate\u003cT\u003e`. `serviceReferences` operations\nwill invoke the `Refresher` to know if the modified instance needs to be\nretracted and reintroduced in the execution. If no refresher is passed\n`serviceReferences` will check `CachingServiceReference.isDirty()`.\n\n#### Getting services from `ServiceReference`\n\nThere are two sets of overloaded operations that allow to get services from\n`CachingServiceReference` or `ServiceReference`: `service` and `prototypes`.\n\n`service` will get services invoking `bundleContext.getService` and unget them\nusing `bundleContext.ungetServices`. `prototypes`, on the other hand, will\nproduce a `ServiceObjects` instance. It will be the responsability of the user\nto properly balance `getService` and `ungetService` calls to `ServiceObjects`.\n\n### BundleContext\n\n`bundleContext` operation will produce the `BundleContext` in use by that piece\nof program. It will normally be the one used to invoke `OSGi.run` unless it is\nchanged using `OSGi.changeContext(BundleContext bundleContext, OSGi\u003cT\u003e program)`\nfor that particular program.\n\n### Just and nothing\n\n`just` set of operations allows to wrap any value inside a `OSGi` type. It is\noverloaded to support `Supplier` and `Collection`. If a collection is passed it\nwill produce the elements of the list in the order given by the collection.\n\n`nothing`, as it name suggests, is a termination operation. Anything depending\non the result of `nothing` operation should never be executed.\n\n### Service Registration\n\nOne common operation when using OSGi is service registration. For that purpose\nthe library offers `register` set of functions. When the associated instances\nare retracted, `register` set of functions also unregister their instances as a\nresult.\n\n```java\nOSGi\u003cServiceRegistration\u003cT\u003e\u003e register(\n\tClass\u003cT\u003e clazz, ServiceFactory\u003cT\u003e service,\n\tMap\u003cString, Object\u003e properties)\n\n\nOSGi\u003cServiceRegistration\u003c?\u003e\u003e register(\n\tString[] classes, Object service, Map\u003cString, ?\u003e properties)\n\nOSGi\u003cServiceRegistration\u003cT\u003e\u003e register(\n\tClass\u003cT\u003e clazz, Supplier\u003cT\u003e service,\n\tSupplier\u003cMap\u003cString, ?\u003e\u003e properties)\n\nOSGi\u003cServiceRegistration\u003cT\u003e\u003e register(\n\tClass\u003cT\u003e clazz, ServiceFactory\u003cT\u003e service,\n\tSupplier\u003cMap\u003cString, ?\u003e\u003e properties)\n\nOSGi\u003cServiceRegistration\u003c?\u003e\u003e register(\n\tString[] classes, Supplier\u003cObject\u003e service,\n\tSupplier\u003cMap\u003cString, ?\u003e\u003e properties)\n```\n\n## Combinators\n\n### All\n\n`OSGi\u003cT\u003e all(OSGi\u003cT\u003e ... programs)` will execute all given programs and produce\nall the elements that the given programs produce.\n\n### Coalesce\n\n`OSGi\u003cT\u003e coalesce(OSGi\u003cT\u003e ... programs)`, just as its homonymous SQL function,\n`coalesce` will produce the value of the first producing program that is being\ngiven as argument, from left to right. Since OSGi is a dynamic environment\n`coalesce` will retract and reintroduce instances when needed. For example:\n\n```java\nOSGi\u003cDictionary\u003cString, ?\u003e\u003e props = coalesce(\n\tconfiguration(\"some.config.pid\"),\n\tjust(Hashtable::new)\n);\n```\n\nthis operation will return an empty Hashtable while no configuration is\navailable. If, at any moment, there is a configuration available the operation\nwill retract the empty `Hashtable` and introduce the incoming configuration. If,\nat any moment, the configuration is deleted, the operation will retract the\n`Dictionary` associated with that configuration and reintroduce the empty\n`Hashtable`.\n\nThis is very useful to model defaults or to model different level for preferred\nservices, from more specific to more general.\n\n### Combine\n\n`OSGi.combine` set of functions is the `Applicative` implementation for `OSGi`\nclass. It produces the result of the invocation to the given function with all\nthe combinations of the values produced by the given operations.\n\n### Once\n\n`OSGi.once` will just let the first instance produced by the given operation to\npass. Further instances won't be published. Actually `once` does not support any\norder so it can't decide that any instance is more suitable than any other.\n\n`once` will update a counter with the instances that it encounters and that are\nretracted. It won't retract the instance it produces until all the instances it\nhas _seen_ are gone.\n\n## License\n```\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapache%2Faries-component-dsl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapache%2Faries-component-dsl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapache%2Faries-component-dsl/lists"}