OSGI Factory Configuration implementation

OSGI Factory configuration is used to have many instances of an OSGI config (represented/identified via an identifier) for the single OSGI service/PID.

Most often used OOB Factory configurations for example:
  • Logger Factory/writer configuration (for log statements)
  • Service user Mapper service Amendment (for using service resource resolver in projects)
Few sample real time use case for the need of OSGI factory config:
  • For multi tenant projects, if we have generic service used across tenants with properties/attributes specific to tenant.
  • For single tenant, generic service targeting all locales with properties/attributes specific to locale. (where generic service -> holds logic in the lines of calling third party service for retrieving/updating information.)
Implementation: (In terms of OSGI R6 annotations):
  • Create Object Class Definition(OCD) defining desired properties for the OSGI service. - OSGIFactoryConfigOCD.java
  • OSGI Service/Factory service to retrieve config values. - OSGIFactoryConfigDemo/OSGIFactoryConfigDemoImpl.java
  • Business logic to be developed as OSGI service/Servlet/Sling Model or any java class where OSGI factory service(created in #2) can be referenced. - In this example, have used servlet, OSGIFactoryConfigDemoServlet.java
OCD:
For the sample real time use case mentioned above, lets say
  • We need to configure API end point and AppId/any similar properties to access the same.
  • Configure another property named sitename or locale or any identifier based on the actual requirement and existing project set up.

OSGI/ OSGI Factory service:
  • OSGI service can be declared as factory service as below (factory=true on @Designate annotation)
  • Defines methods to retrieve the config values which will be available once the service is activated. (config in the below snippet holds the entire OSGI config values)
At this stage when we build and deploy the code, we are ready to create multiple OSGI configs via Felix console or in the config folders by creating node of type sling:OsgiConfig in the name of Service PID with unique identifier, say -> Service PID-identifier. In this example, it is learnings.core.serviceimpl.OSGiFactoryConfigDemoImpl-demosite

Java class referencing Factory service:
Targeting specific instance:
  • Lets say we have created 5 OSGI configs of the same PID with unique identifier, one each for tenant and if there is a need to target one such tenant, we can reference as below.
  • Out of 5, config which has sitenameIdentifier property value as demosite will be picked up.
@Reference(target="(siteNameIdentifier=demosite)")
private OSGIFactoryConfigDemo osgiDemo;
    Multiple instance reference:
    • bind method will be called when the factory service is available and configs are stored in collection. In this case, map is used where “key” -> sitename, one of the config property and “value” -> entire config object.
    • Let say, we have created 5 OSGI configs of this PID and if the service is active -> All 5 configs will be available in the map object.
    private Map<String,OSGIFactoryConfigDemo> configMap;
    @Reference(name = "osgiFactoryConfigDemo", cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
    protected synchronized void bindOSGIFactoryConfigDemo(final OSGIFactoryConfigDemo config) {       
    if (configMap == null) {
        configMap = new HashMap<>();
    }
    configMap.put(config.getSiteName(), config);
    }
    protected synchronized void unbindOSGIFactoryConfigDemo(final OSGIFactoryConfigDemo config) {
    configMap.remove(config.getSiteName());
    }
    Let say, we are able to extract the sitename(key used in the map) from servlet request. (Changes to be taken care in the way we call the servlet accordingly) Using that, we can the retrieve the respective map value(its entire config) and use it accordingly.
    On the similar lines, based on the overall requirement + existing project set up + with understanding of factory config implementation, we can decide on the ways of retrieving multiple configs of same PID and arriving at generic service.

    Code on GitHub Repo: 

    Comments

    1. import random

      class WhiteLabelCryptoExchange:

      def __init__(self, name, currencies):
      self.name = name
      self.currencies = currencies

      def trade(self, currency1, currency2, amount):
      price = random.randint(1, 1000)
      commission = random.randint(1, 10)

      if amount > 0:
      # Buy
      cost = price * amount + commission
      return cost
      else:
      # Sell
      profit = price * amount - commission
      return profit

      exchange = WhiteLabelCryptoExchange("My Exchange", ["BTC", "ETH", "USDT"])

      print(exchange.trade("BTC", "ETH", 10))
      # Output: 1000.5

      print(exchange.trade("ETH", "USDT", -10))
      # Output: 90.5
      This code snippet defines a simple white label crypto exchange. The exchange has a name and a list of supported currencies. The trade() method allows users to buy and sell cryptocurrencies. The price of a cryptocurrency is randomly generated, and a commission is charged for each trade.

      This is just a simple example of a white label crypto exchange. In a real-world application, the white label exchange software code would be more complex and would include additional features such as order book management, trade history, and user accounts.

      The code snippet is written in Python, but it could be easily translated into other programming languages.

      ReplyDelete

    Post a Comment

    Popular posts from this blog

    Embedding Third party dependency/OSGi bundle in AEM application hosted in AEMasCS

    Embed Third party dependency using bnd-maven-plugin