groovy grails async promise execute immediately - java

In the below code, inside controllerMethod , onComplete event execute immediately without waiting for the finishing of promiseList in the callApisInParallel method in groovy/grails
import grails.async.Promise
import grails.async.PromiseList
class asyncProgram {
def getReportTask() {
return task {
def res = reportService.fetchReport()
// api request
res
}
}
private def callApisInParallel() {
def promiseList = new PromiseList()
def reportTask = getReportTask()
promiseList << reportTask
//def apiResults = waitAll(promiseList)
//def results = apiResults[0]
// def res = results[0]
promiseList
}
def execute() {
Promise p = task {
def promiseList = callApisInParallel()
promiseList.onComplete { result ->
println "Promise returned $result"
//manipulate the data and then return the result
//resolve()
}
}
return p
}
def controllerMethod() {
Promise p = execute()
p.onComplete { result ->
}
}
}
I need something like "resolve" method in javascript which can tells the onComplete event of execute method that the onComplete is done and mark the current promise complete
I found one link
Groovy/Grails promises/futures. There is no .resolve(1,2,3) method. Strange?
but I am not able to understand in the above approach properly

If you are creating a promiseList with task here:
def promiseList = callApisInParallel()
then why are you not using it here?
p.onComplete { result ->
println "Promise returned $result"
//manipulate the data and then return the result
//resolve()
}
Change p.onComplete to promiseList.onComplete

Related

Reflection to get default value of parameter

I am trying to use reflection to get all the optional fields in a class and their default values (if any). This is my attempt:
fun getOptionalFields(componentType: KClass<out Any>): Map<String, DefaultValueData> {
val cons = componentType.primaryConstructor
val constructorSetup = cons?.parameters
?.filterNot { it.isOptional }
?.associate { it to getValueForNonOptional(it) } ?: error("Something went wrong when choosing default val")
val constructorInst = (cons.callBy(constructorSetup)::class as KClass<Any>)
val conParams = (componentType.primaryConstructor?.parameters ?: emptyList())
.filter { p -> p.isOptional }
.associate { p ->
Pair(p.name ?: "",
DefaultValueData(
p.type,
// the below line crashes
constructorInst.memberProperties.first { m -> m.name == p.name }.get(constructorInst)
)
)
}
return conParams
}
The error: Exception in thread "main" java.lang.IllegalArgumentException: object is not an instance of declaring class
I am a bit puzzled at what get() wants me to pass if not the instance to get the value from?
You are trying to get the value by providing a KClass instead of the actual instance.
This is a working solution based on your method signature and your code above:
data class Test(
val required: String,
val optional: Int = 7
)
val componentType = Test::class
val constructorInst = Test("required") // i skipped constructing the class via constructor
val conParams = (componentType.primaryConstructor?.parameters ?: emptyList())
.filter { p -> p.isOptional }
.associate { p ->
Pair(p.name ?: "",
Pair(
p.type,
componentType.memberProperties.first { m -> m.name == p.name }.get(constructorInst)
)
)
}
println(conParams) // <- OUTPUTS: {optional=(kotlin.Int, 7)}
Why have i removed this code?
val constructorSetup = cons?.parameters
?.filterNot { it.isOptional }
?.associate { it to getValueForNonOptional(it) } ?: error("Something went wrong when choosing default val")
val constructorInst = (cons.callBy(constructorSetup)::class as KClass<Any>)
The resulting object cons.callBy(constructorSetup) is unused because calling ::class on the expression rendered it useless. Additionally it is not required to perform the requested task in your question.
When updating your above code, result will look like
fun getOptionalFields(componentType: KClass<out Any>): Map<String, DefaultValueData> {
val cons = componentType.primaryConstructor
val constructorSetup = cons?.parameters
?.filterNot { it.isOptional }
?.associate { it to getValueForNonOptional(it) } ?: error("Something went wrong when choosing default val")
val constructorInst = cons.callBy(constructorSetup) // <- removed ::class and cast
val conParams = (componentType.primaryConstructor?.parameters ?: emptyList())
.filter { p -> p.isOptional }
.associate { p ->
val value = constructorInst::class.memberProperties.first { m -> m.name == p.name }.get(constructorInst) as KProperty1<out Any, out Any>
Pair(p.name ?: "",
DefaultValueData(
p.type,
value
)
)
}
return conParams
}

What is the return type for multiple possible types in Kotlin?

fun getSummary(id: String): List<Summary> {
val request = GetSummaryRequest(id)
val response = client.getSummary(request) as GetSummaryResponse
return when (val result = response.result) {
is GetSummarySuccessResponse-> result.summaryList
is GetSummaryFailResponse-> throw TreasuryRpcException("There was an error calling getSummary")
else -> "No message"
}
}
it gives me a red line for :List<Summary> because return can be List<Summary>, Exception,String, I know I probably can use Any as return type.
Just want to know the best practice in this case. Thanks!
The exception is thrown so it is not part of the return type. You should return either emptyList() or null for the else condition so the return type can still be List<Summary> or at least List<Summary>?. You only need nullability if you need to distinguish that condition from a successful result.
You probably need to use sealed class in this case.
First of all create a sealed class as follows:
sealed class Resource<out R>
data class Success<out R>(val data: R) : Resource<R>()
data class Failed(val t: Throwable? = null) : Resource<Nothing>()
data class Info(val message: String = "Something went wrong") : Resource<Nothing>()
In your code change the return type from List<Summary> to Resource<List<Summary>>. After changing, the code will look like following:
fun getSummary(id: String): Resource<List<Summary>> {
val request = GetSummaryRequest(id)
val response = client.getSummary(request) as GetSummaryResponse
return when (val result = response.result) {
is GetSummarySuccessResponse-> Success(result.summaryList)
is GetSummaryFailResponse-> Failed(TreasuryRpcException("There was an error calling getSummary"))
else -> Info("No message")
}
}
The code where you call getSummary() should look like following:
val summaryResource = getSummary(id)
when(summaryResource) {
is Success -> {
val summary = summaryResource.data
// Do something with summary
}
is Failed -> {
val t = summaryResource.t
println(t?.message)
// Do something with t
}
is Info -> {
val msg = summaryResource.message
println(msg)
// Do something with msg
}
}

Stubbed object method value not returned in Spock test

I am new to the Spock framework and writing a test case in which I am trying to Mock a class called QueryDatabase
public class QueryDatabase {
public BigInteger countRecords(Instant start, Instant end) {
Flux<CountRecord> countValue = query("select * from users");
Optional<Object> value = Optional.ofNullable(countValue.blockFirst()).map(CountRecord::getValue);
BigInteger count = value.filter(BigInteger.class::isInstance)
.map(BigInteger.class::cast).orElse(BigInteger.valueOf(0));
return count
}
public Flux<CountRecord> query(String query) {
}
}
but the below test case which is to check the value returned by countRecords(Instant, Instant) always gives 0, so that means the value returned in the when section
recordCount.query(_) >> Flux.just(CountRecord.builder().value(new BigInteger(133)).build())
is not getting used, seems like recordCount.query(_) >> Flux.empty() also does not have any impact and it always returns the default BigInteger value 0
def "record count"() {
given:
def now = Instant.now()
def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
def recordCount = Stub(QueryDatabase)
when: "query returning empty flux"
recordCount.query(_) >> Flux.empty()
then:
recordCount.countRecords(last10Minutes, now) == 0
when: "query returning the count record"
recordCount.query(_) >> Flux.just(CountRecord.builder().value(new BigInteger(133)).build())
then:
recordCount.countRecords(last10Minutes, now) == 133
}
Am I doing anything wrong here?
There are several issues with your code.
You try to set up some stubbing in the when block
You perform your action in the then block
You try to redefine stubs
See Combining Mocking and Stubbing on how this works.
def "record count"() {
given:
def now = Instant.now()
def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
def recordCount = Spy(QueryDatabase)
when: "query returning empty flux"
def result = recordCount.countRecords(last10Minutes, now)
then:
1 * recordCount.query(_) >> Flux.empty()
result == 0
when: "query returning the count record"
def 2ndResult = recordCount.countRecords(last10Minutes, now) == 133
then:
1 * recordCount.query(_) >> Flux.just(CountRecord.builder().value(new BigInteger(133)).build())
2ndResult == 133
}
Alternatively, you could split it up into a data driven feature
def "record count"(BigInteger result, Flux input) {
given:
def now = Instant.now()
def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
def recordCount = Spy(QueryDatabase)
recordCount.query(_) >> input
expect:
recordCount.countRecords(last10Minutes, now) == result
where:
result | input
0 | Flux.empty()
133 | Flux.just(CountRecord.builder().value(new BigInteger(133)).build())
}
Normally, you'd order the parameters the other way around, but since the fluxes are so verbose I find this better readable.
--
EDIT:
I missed that you are trying to stub that same object that you are testing, this can only be done with partial mocking and often indicates, that the code should be refactored. So replace Mock/Stub with Spy for partial mocking.
What about this way when you override the query method to return an expected Flux. In this case I would recommend to have 2 tests:
def "record count when empty Flux"() {
given:
def now = Instant.now()
def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
def recordCount = new QueryDatabase() {
#Overriden
public Flux<CountRecord> query(String query) {
Flux.empty()
}
}
expect:
recordCount.countRecords(last10Minutes, now) == 0
}
def "record count when non empty Flux"() {
given:
def now = Instant.now()
def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
def recordCount = new QueryDatabase() {
#Overriden
public Flux<CountRecord> query(String query) {
Flux.just(CountRecord.builder().value(new BigInteger(133)).build())
}
}
expect:
recordCount.countRecords(last10Minutes, now) == 133
}

Getting a substring using method does not work

I am trying to introduce a method in my program which should result into a substring. I wrote the following code but why would not this work?
class testmethod {
String FQDN = "TEST.domain.local"
def sname = shortname(FQDN);
println $sname
def shortname(Longname)
{
shortname1 = Longname.substring(0, Longname.indexOf('.'))
return shortname1
}
}
First of all the code should be(for better readability) :-
def shortname(String Longname) not def shortname(Longname).
Also shortname1 = Longname.substring(0, Longname.indexOf('.')) in this shortname1 is not defined.
Moreover you can try :-
def shortname(String Longname)
{
String[] shortnameArr = Longname.split("\\.");
return shortnameArr[0];// will return TEST
}
You're mixing both script and class concepts of the Groovy in one single piece of code.
Just remove the class definition and $ sign to use the script way:
String FQDN = "TEST.domain.local"
def sname = shortname(FQDN);
println sname
def shortname(Longname)
{
shortname1 = Longname.substring(0, Longname.indexOf('.'))
return shortname1
}
Or add class initialization and local variable declaration to use the class way:
class testmethod {
String FQDN = "TEST.domain.local"
def sname = shortname(FQDN);
def shortname(Longname)
{
def shortname1 = Longname.substring(0, Longname.indexOf('.'))
return shortname1
}
}
def tc = new testmethod()
println tc.sname

building async httpbuilder similar to httpbuilder

Might be the wrong place to post this but I have been messing around with async http builders trying to get basic cypher queries to work. It works with Http Builders but can't get it to work with the async version.
#Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.6' )
#Grab(group='net.sf.json-lib', module='json-lib', version='2.4', classifier='jdk15' )
import groovyx.net.http.*
import static groovyx.net.http.ContentType.*
import static groovyx.net.http.Method.*
def query(statement, params,success, error) {
def http = new HTTPBuilder( 'http://localhost:7474' )
http.request( POST, JSON ) {
uri.path = '/db/data/cypher/'
headers.'X-Stream' = 'true'
requestContentType = JSON
body = [ query : statement , params : params ?: [:] ]
// uri.query = [ param : 'value' ]
response.success = { resp, json ->
if (success) success(json)
else {
println "Status ${resp.statusLine} Columns ${json.columns}\nData: ${json.data}"
}
}
response.failure = { resp, message ->
def result=[status:resp.statusLine.statusCode,statusText:resp.statusLine.reasonPhrase]
result.headers = resp.headers.collect { h -> [ (h.name) : h.value ] }
result.message = message
if (error) {
error(result)
} else {
println "Status: ${result.status} : ${result.statusText} "
println 'Headers: ${result.headers}'
println 'Message: ${result.message}'
}
}
}
}
query("MATCH n RETURN n;",[],{ println "Success: ${it}" },{ println "Error: ${it}" })
However I have tried this with the AsyncHttpBuilder. Couldn't get it to work. Now I am trying a simple thing and have been unable to get it to give anytype of useful result.
#Test
public void testQueue()
{
def http = new AsyncHTTPBuilder( poolSize : 1 ,
uri : 'http://localhost:7474/db/data/cypher' )
def responses = []
responses << http.post(query : [q: "MATCH n RETURN n;"]) {return it}
if (!responses.every{it.done})
{
println 'waiting...'
Thread.sleep(2000)
}
responses.each {
println(it)
}
http.shutdown()
}
Any thoughts? Thanks!
for reference: I've answered this at https://groups.google.com/forum/?fromgroups#!topic/neo4j/5Cle5vBsMXQ
you need to pass in the cypher query in the request's body and not as
query param. See https://gist.github.com/sarmbruster/8114445 for a
working example

Categories