1

I need to build a small Microservice which receives a REST Request and stores data (Devices, Measurements etc.) in Cumulocity.

For me it is not very clear from the documentation how the platformApi can be easily injected to my Spring Boot Application. Especially the Scope (TenantScope & UserScope) usage is not clear.

Can you give a very simple "hello-world" example how to autowire the platformApi (e.g. inventory) and on application startup doing something (print out all devices) within the tenant scope and using a RestControler RequestMapping doing something within a user scope?

Here is a Code Snippet:

package c8y.example;

import com.cumulocity.microservice.autoconfigure.MicroserviceApplication;  
import com.cumulocity.microservice.context.inject.TenantScope;
import com.cumulocity.sdk.client.inventory.InventoryApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;

@MicroserviceApplication
@RestController
public class App{

@Autowired
InventoryApi inventoryApi;

public static void main(String[] args) {
    SpringApplication.run(App.class, args);
}

@PostConstruct
public void init() {
    System.out.println("Devices: " + inventoryApi.getManagedObjects());
}

@RequestMapping("devices")
public String greeting() {
    return "Devices: " + inventoryApi.getManagedObjects();
}
}

Everything I tried so far result in error on startup that the beans couldn't been injected or that they are not in the required scope or not within context. I have a application.properties which contains the bootstrap credentials.

Switschel
  • 42
  • 4
  • The internal platform api is injected into your project when you are using the MicroserviceApplication annotation. This annotation uses the EnableMicroservicePlatformInternalApi annotation which is responsible for actually injecting the api. Have a look at the CumulocityClientFeature class which is actual responsible for providing different APIs. I think the errors you receive are related to another issue – BrickTop Mar 28 '18 at 13:37
  • Can you provide a working example or state what seems wrong in my example above? Otherwise it is not very clear what is wrong. Fact is just using the microservice annotation seems to be not enough to inject the platform api because if I do so I always get scope related errors etc. – Switschel Mar 28 '18 at 15:13
  • sorry but I've confused something in my first comment. The CumulocityClientFeature registers the different APIs as beans which can be accessed by autowiring the necessary API you need. So actually your example is correct. I think the issue is that the context is never created in the first place and therefore can't be retrieved when the app tries to autowire for example the inventory API. But this is just an assumption from my side as I'm also trying to get this working ... – BrickTop Mar 29 '18 at 08:59

1 Answers1

1

I found a first solution but I'm still not sure what the difference is between tenant and user scope and when a scope is being used. But maybe this helps a little bit.

I was not able to autowire the inventory API but I was able to autowire the platform API from which you can use the inventory API.

package c8y.example;

import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.cumulocity.microservice.autoconfigure.MicroserviceApplication;
import com.cumulocity.model.idtype.GId;
import com.cumulocity.rest.representation.inventory.ManagedObjectRepresentation;
import com.cumulocity.sdk.client.Platform;
import com.cumulocity.sdk.client.inventory.InventoryApi;

@MicroserviceApplication
@RestController
public class App {
    private static final Logger log = org.slf4j.LoggerFactory.getLogger(App.class);

    @Autowired(required = true)
    @Qualifier("userPlatform")
    private Platform platformApi;

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

    @RequestMapping("/")
    public String greeting() {
        if (platformApi != null && platformApi.getInventoryApi() != null) {
            final InventoryApi inventoryApi = platformApi.getInventoryApi();
            final ManagedObjectRepresentation managedObjectRepresentation = inventoryApi.get(new GId("5749"));

            log.info(managedObjectRepresentation.toString());
            return "device: " + managedObjectRepresentation.getName();
        }

        return "hello world";
    }
}

Initially there is a scope available which is the UserScope but when you have a look at the CumulocityClientFeature class you can see that the class sets the PlatformImpl for Tenant Scope as Primary. This means when you autowire the PlatformApi it will automatically use the TenantScoped Platform instead of the UserScoped. This will fail as the current Scope is the UserScope. To autowire the correct PlatformApi you have to use the Qualifier with the value userPlatform in order to autowire the UserScoped PlatformAPI. From the platform API you can access the inventory API.

Trying to autowire the Inventory API didn't work for me as the App can't find the UserScoped Inventory API. No idea why.

BrickTop
  • 230
  • 2
  • 9
  • That is a good solution for the userScope. What I still need is to know how this can be accomplished using the tenantScope (see my postconstruct method). Can anybody provide an example how to get the platform API with tenantScope? – Switschel Apr 17 '18 at 08:14