What loads first in the ThingHandlerFactory... @Activate or protected void activate?

With miio binding we get several users reporting issues with the binding after the upgrade.
Whereas same code was running before.

One of the things I can imagine causes the reported issues if the loading sequence is slightly changed… This is in the miio thingfactory:

as you can see @Override protected void activate(ComponentContext componentContext) { is dependent on the @Activate MiIoHandlerFactory as that is initiating the cloudConnector.

Can it be that after an upgrade this sequence has changed? Is indeed @Activate run before the void activate? or is that just the case for the majority of users, but not certain?

  @Activate
    public MiIoHandlerFactory(@Reference MiIoDatabaseWatchService miIoDatabaseWatchService,
            @Reference CloudConnector cloudConnector) {
        this.miIoDatabaseWatchService = miIoDatabaseWatchService;
        this.cloudConnector = cloudConnector;
    }

    @Override
    protected void activate(ComponentContext componentContext) {
        super.activate(componentContext);
        Dictionary<String, Object> properties = componentContext.getProperties();
        @Nullable
        String username = (String) properties.get("username");
        @Nullable
        String password = (String) properties.get("password");
        @Nullable
        String country = (String) properties.get("country");
        cloudConnector.setCredentials(username, password, country);
        scheduler.submit(() -> cloudConnector.isConnected());
    }

@wborn maybe has good idea? As you are one of the Karaf guru’s :slight_smile:

You probably have to add the @Activate annotation to the activate() method too. Otherwise I am not sure if it will be called for sure. It is allowed to have as many activation methods as needed. The constructor will be called first but as you annotated it to be the activation for the component it will wait for all referenced services to be available too.

I agree with @cweitkamp. From my understanding your activate method will only be called if it is annotated @Activate. But I wonder why you don‘t integrate it in the constructor.

the activate() comes from the BaseThingHandlerFactory, looking in there I don’t directly see indeed how it is invoked… but I’m sure it runs :slight_smile: … and in all of my testing it runs after the @Activate.

The reason it is not integrated in the first @Activate one is because I need to get the binding properties, as I saw the examples that the properties needs to come from the ComponentContext componentContext.

If there is another way to get the ComponentContext with the binding properties, I would have no need to override it at all. Is there a @Reference to get to those properties?

In general you do not need the ComponentContext to access the properties. They could be passed to an activate() as Map (e.g. activate(Map<String, Object> properties)).

Either ComponentContext or properties Map can be accessed in any activation method. IIRC even the constructor. You can just amend it to the list of passed parameters (e.g MiIoHandlerFactory(@Reference MiIoDatabaseWatchService miIoDatabaseWatchService, @Reference CloudConnector cloudConnector, Map<String, Object> properties)). OSGI is “smart” enough to identify what the service needs.

2 Likes

Thanks that would be a good solution!