com.zepben.evolve.streaming.get.CustomerConsumerClient.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of evolve-sdk Show documentation
Show all versions of evolve-sdk Show documentation
SDK for interaction with the evolve platform
/*
* Copyright 2020 Zeppelin Bend Pty Ltd
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.zepben.evolve.streaming.get
import com.zepben.evolve.cim.iec61968.customers.Customer
import com.zepben.evolve.cim.iec61970.base.core.EquipmentContainer
import com.zepben.evolve.services.common.BaseService
import com.zepben.evolve.services.common.translator.mRID
import com.zepben.evolve.services.customer.CustomerService
import com.zepben.evolve.services.customer.translator.CustomerProtoToCim
import com.zepben.evolve.services.customer.translator.mRID
import com.zepben.evolve.streaming.grpc.GrpcChannel
import com.zepben.evolve.streaming.grpc.GrpcResult
import com.zepben.protobuf.cc.*
import com.zepben.protobuf.cc.CustomerIdentifiedObject.IdentifiedObjectCase.*
import com.zepben.protobuf.metadata.GetMetadataRequest
import com.zepben.protobuf.metadata.GetMetadataResponse
import io.grpc.CallCredentials
import io.grpc.Channel
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
/**
* Consumer client for a [CustomerService].
*
* WARNING: The [MultiObjectResult] operations below are not atomic upon a [CustomerService], and thus if processing fails partway through, any previously
* successful additions will have been processed by the service, and thus you may have an incomplete service. Also note that adding to the service may not
* occur for an object if another object with the same mRID is already present in service. [MultiObjectResult.failed] can be used to check for mRIDs that
* were retrieved but not added to service. This should not be the case unless you are processing things concurrently.
*
* @property stub The gRPC stub to be used to communicate with the server
* @param executor An optional [ExecutorService] to use with the stub. If provided, it will be cleaned up when this client is closed.
*/
class CustomerConsumerClient @JvmOverloads constructor(
private val stub: CustomerConsumerGrpc.CustomerConsumerStub,
override val service: CustomerService = CustomerService(),
override val protoToCim: CustomerProtoToCim = CustomerProtoToCim(service),
executor: ExecutorService? = null
) : CimConsumerClient(executor) {
init {
executor?.also { stub.withExecutor(it) }
}
/**
* Create a [CustomerConsumerClient]
*
* @param channel [Channel] to build a stub from.
* @param callCredentials [CallCredentials] to be attached to the stub.
*/
@JvmOverloads
constructor(channel: Channel, callCredentials: CallCredentials? = null) :
this(
CustomerConsumerGrpc.newStub(channel).apply { callCredentials?.let { withCallCredentials(it) } },
executor = Executors.newSingleThreadExecutor()
)
/**
* Create a [CustomerConsumerClient]
*
* @param channel [GrpcChannel] to build a stub from.
* @param callCredentials [CallCredentials] to be attached to the stub.
*/
@JvmOverloads
constructor(channel: GrpcChannel, callCredentials: CallCredentials? = null) : this(channel.channel, callCredentials)
/**
* Get the [Customer]s in the [EquipmentContainer] represented by [mRID].
*
* @param mRID The mRID of the [EquipmentContainer]s to fetch [Customer]s for.
* @return a [GrpcResult] with a result of one of the following:
* - When [GrpcResult.wasSuccessful], a map containing the retrieved objects keyed by mRID, accessible via [GrpcResult.value]. If an item was not found, or
* couldn't be added to [service], it will be excluded from the map and its mRID will be present in [MultiObjectResult.failed] (see [BaseService.add]).
* - When [GrpcResult.wasFailure], the error that occurred retrieving or processing the object, accessible via [GrpcResult.thrown].
* Note the [CustomerConsumerClient] warning in this case.
*/
fun getCustomersForContainer(mRID: String): GrpcResult = getCustomersForContainers(setOf(mRID))
/**
* Get the [Customer]s in the [EquipmentContainer]s represented by their [mRIDs].
*
* @param mRIDs The mRIDs of the [EquipmentContainer]s to fetch [Customer]s for.
* @return a [GrpcResult] with a result of one of the following:
* - When [GrpcResult.wasSuccessful], a map containing the retrieved objects keyed by mRID, accessible via [GrpcResult.value]. If an item was not found, or
* couldn't be added to [service], it will be excluded from the map and its mRID will be present in [MultiObjectResult.failed] (see [BaseService.add]).
* - When [GrpcResult.wasFailure], the error that occurred retrieving or processing the object, accessible via [GrpcResult.thrown].
* Note the [CustomerConsumerClient] warning in this case.
*/
fun getCustomersForContainers(mRIDs: Set): GrpcResult = handleMultiObjectRPC {
processCustomersForContainers(mRIDs)
}
override fun processIdentifiedObjects(mRIDs: Sequence): Sequence {
val extractResults = mutableListOf()
val streamObserver = AwaitableStreamObserver { response ->
response.identifiedObjectsList.forEach {
extractResults.add(extractIdentifiedObject(it))
}
}
val request = stub.getIdentifiedObjects(streamObserver)
val builder = GetIdentifiedObjectsRequest.newBuilder()
batchSend(mRIDs, builder::addMrids) {
if (builder.mridsList.isNotEmpty())
request.onNext(builder.build())
builder.clearMrids()
}
request.onCompleted()
streamObserver.await()
return extractResults.asSequence()
}
private fun processCustomersForContainers(
mRIDs: Set,
): Sequence {
val extractResults = mutableListOf()
val streamObserver = AwaitableStreamObserver { response ->
response.identifiedObjectsList.forEach {
extractResults.add(extractIdentifiedObject(it))
}
}
val request = stub.getCustomersForContainer(streamObserver)
val builder = GetCustomersForContainerRequest.newBuilder()
batchSend(mRIDs.asSequence(), builder::addMrids) {
if (builder.mridsList.isNotEmpty())
request.onNext(builder.build())
builder.clearMrids()
}
request.onCompleted()
streamObserver.await()
return extractResults.asSequence()
}
private fun extractIdentifiedObject(io: CustomerIdentifiedObject): ExtractResult {
return when (io.identifiedObjectCase) {
ORGANISATION -> extractResult(io.organisation.mRID()) { addFromPb(io.organisation) }
CUSTOMER -> extractResult(io.customer.mRID()) { addFromPb(io.customer) }
CUSTOMERAGREEMENT -> extractResult(io.customerAgreement.mRID()) { addFromPb(io.customerAgreement) }
PRICINGSTRUCTURE -> extractResult(io.pricingStructure.mRID()) { addFromPb(io.pricingStructure) }
TARIFF -> extractResult(io.tariff.mRID()) { addFromPb(io.tariff) }
OTHER, IDENTIFIEDOBJECT_NOT_SET, null -> throw UnsupportedOperationException("Identified object type ${io.identifiedObjectCase} is not supported by the customer service")
}
}
override fun runGetMetadata(getMetadataRequest: GetMetadataRequest, streamObserver: AwaitableStreamObserver) {
stub.getMetadata(getMetadataRequest, streamObserver)
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy