Skip to content

Commit

Permalink
Merge branch '3.4.x' into 3.5.x
Browse files Browse the repository at this point in the history
  • Loading branch information
graemerocher committed Apr 29, 2022
2 parents 980fbe0 + 2b6eb45 commit c7a8872
Show file tree
Hide file tree
Showing 21 changed files with 472 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,8 @@ public Argument<?> returnTypeValue() {

@Override
public CompletableFuture<Object> interceptResultAsCompletionStage() {
CompletableFutureContinuation completableFutureContinuation;
if (continuation instanceof CompletableFutureContinuation) {
completableFutureContinuation = (CompletableFutureContinuation) continuation;
} else {
completableFutureContinuation = new CompletableFutureContinuation(continuation);
replaceContinuation.accept(completableFutureContinuation);
}
CompletableFutureContinuation completableFutureContinuation = new CompletableFutureContinuation(continuation);
replaceContinuation.accept(completableFutureContinuation);
Object result = context.proceed();
replaceContinuation.accept(continuation);
if (result != KotlinUtils.COROUTINE_SUSPENDED) {
Expand All @@ -117,13 +112,8 @@ public CompletableFuture<Object> interceptResultAsCompletionStage() {

@Override
public CompletableFuture<Object> interceptResultAsCompletionStage(Interceptor<?, ?> from) {
CompletableFutureContinuation completableFutureContinuation;
if (continuation instanceof CompletableFutureContinuation) {
completableFutureContinuation = (CompletableFutureContinuation) continuation;
} else {
completableFutureContinuation = new CompletableFutureContinuation(continuation);
replaceContinuation.accept(completableFutureContinuation);
}
CompletableFutureContinuation completableFutureContinuation = new CompletableFutureContinuation(continuation);
replaceContinuation.accept(completableFutureContinuation);
Object result = context.proceed(from);
replaceContinuation.accept(continuation);
if (result != KotlinUtils.COROUTINE_SUSPENDED) {
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ managed-micronaut-netflix = "2.1.0"
managed-micronaut-openapi = "4.0.0"
managed-micronaut-oraclecloud = "2.1.1"
managed-micronaut-picocli = "4.1.0"
managed-micronaut-problem = "2.2.2"
managed-micronaut-problem = "2.2.3"
managed-micronaut-rabbitmq = "3.1.0"
managed-micronaut-r2dbc = "2.1.0"
managed-micronaut-reactor = "2.2.2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,16 @@ private HttpToHttp2ConnectionHandler newHttpToHttp2ConnectionHandler() {
*/
void configureForAlpn() {
pipeline.addLast(new ApplicationProtocolNegotiationHandler(server.getServerConfiguration().getFallbackProtocol()) {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (routingInBoundHandler.isIgnorable(cause)) {
// just abandon ship, nothing can be done here to recover
ctx.close();
} else {
super.exceptionCaught(ctx, cause);
}
}

@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof SslHandshakeCompletionEvent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1419,7 +1419,15 @@ private ByteBuf encodeBodyAsByteBuf(
return byteBuf;
}

private boolean isIgnorable(Throwable cause) {
/**
* Is the exception ignorable by Micronaut.
* @param cause The cause
* @return True if it can be ignored.
*/
protected boolean isIgnorable(Throwable cause) {
if (cause instanceof ClosedChannelException || cause.getCause() instanceof ClosedChannelException) {
return true;
}
String message = cause.getMessage();
return cause instanceof IOException && message != null && IGNORABLE_ERROR_MESSAGE.matcher(message).matches();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public void setHttpVersion(HttpVersion httpVersion) {
}

/**
* Sets the {@link ThreadSelection} model to use for the server.
* Sets the {@link io.micronaut.scheduling.executor.ThreadSelection} model to use for the server. Default value MANUAL.
* @param threadSelection The thread selection model
*/
public void setThreadSelection(ThreadSelection threadSelection) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,17 @@ public int getTextOffset() throws IOException {

@Override
public byte[] getBinaryValue(Base64Variant b64variant) throws IOException {
JsonNode currentNode = currentNodeOrNull();

if (currentNode != null && currentNode.isNull()) {
return null;
}

String text = getText();
if (text != null) {
return b64variant.decode(text);
}

return null;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.micronaut.jackson.core.tree

import com.fasterxml.jackson.core.Base64Variant
import com.fasterxml.jackson.core.Base64Variants
import io.micronaut.json.tree.JsonNode
import spock.lang.Specification

class JsonNodeTraversingParserTest extends Specification {

def getBinaryValue() {
given:
def parser = new JsonNodeTraversingParser(jsonNode)

parser.nextToken()

def binaryValue = parser.getBinaryValue(Base64Variants.MIME)

expect:
binaryValue == expected?.bytes

where:
jsonNode || expected
JsonNode.createStringNode("YWJj") || "abc"
JsonNode.nullNode() || null
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,3 @@ NOTE: The default value for the number of threads is the value of the system pro
See the following table for configuring event loops:

include::{includedir}configurationProperties/io.micronaut.http.netty.channel.DefaultEventLoopGroupConfiguration.adoc[]

==== Blocking Operations

When dealing with blocking operations, Micronaut shifts the blocking operations to an unbound, caching I/O thread pool by default. You can configure the I/O thread pool using the api:scheduling.executor.ExecutorConfiguration[] named `io`. For example:

.Configuring the Server I/O Thread Pool
[source,yaml]
----
micronaut:
executors:
io:
type: fixed
nThreads: 75
----

The above configuration creates a fixed thread pool with 75 threads.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
When dealing with blocking operations, Micronaut shifts the blocking operations to an unbound, caching I/O thread pool by default. You can configure the I/O thread pool using the api:scheduling.executor.ExecutorConfiguration[] named `io`. For example:

.Configuring the Server I/O Thread Pool
[source,yaml]
----
micronaut:
executors:
io:
type: fixed
nThreads: 75
----

The above configuration creates a fixed thread pool with 75 threads.
4 changes: 3 additions & 1 deletion src/main/docs/guide/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ httpServer:
serverEvents: Server Events
serverConfiguration:
title: Configuring the HTTP Server
threadPools: Configuring Server Thread Pools
threadPools:
title: Configuring Server Thread Pools
blockingOperations: Blocking Operations
nettyPipeline: Configuring the Netty Pipeline
cors: Configuring CORS
https: Securing the Server with HTTPS
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2017-2020 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.docs.server.suspend.multiple

@MyRepository
interface CustomRepository {

suspend fun xyz(): String

suspend fun abc(): String

suspend fun count1(): String

suspend fun count2(): String

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2017-2019 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.docs.server.suspend.multiple

import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.ints.shouldBeExactly
import io.kotest.matchers.shouldBe
import io.micronaut.context.ApplicationContext
import kotlinx.coroutines.runBlocking

class InterceptorSpec : StringSpec() {

val context = autoClose(
ApplicationContext.run()
)

private var myService = context.getBean(MyService::class.java)

init {
"test correct interceptors calls" {
runBlocking {
myService.someCall()
MyService.events.size shouldBeExactly 8
MyService.events[0] shouldBe "intercept1-start"
MyService.events[1] shouldBe "intercept2-start"
MyService.events[2] shouldBe "repository-abc"
MyService.events[3] shouldBe "repository-xyz"
MyService.events[4] shouldBe "intercept2-end"
MyService.events[5] shouldBe "intercept1-end"
MyService.events[6] shouldBe "repository-count1"
MyService.events[7] shouldBe "repository-count2"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2017-2020 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.docs.server.suspend.multiple

import io.micronaut.aop.Introduction
import jakarta.inject.Singleton

@MustBeDocumented
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@Introduction
@Singleton
annotation class MyRepository()
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2017-2020 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.docs.server.suspend.multiple

import io.micronaut.aop.InterceptedMethod
import io.micronaut.aop.InterceptorBean
import io.micronaut.aop.MethodInterceptor
import io.micronaut.aop.MethodInvocationContext
import jakarta.inject.Singleton
import java.io.IOException
import java.util.concurrent.CompletableFuture

@InterceptorBean(MyRepository::class)
@Singleton
class MyRepositoryInterceptorImpl : MethodInterceptor<Any, Any> {
override fun intercept(context: MethodInvocationContext<Any, Any>?): Any? {
val interceptedMethod = InterceptedMethod.of(context)
return try {
if (interceptedMethod.resultType() == InterceptedMethod.ResultType.COMPLETION_STAGE) {
MyService.events.add("repository-" + context!!.methodName)
val cf: CompletableFuture<String> = CompletableFuture.supplyAsync{
Thread.sleep(1000)
context!!.methodName
}
interceptedMethod.handleResult(cf)
} else {
throw IllegalStateException()
}
} catch (e: Exception) {
interceptedMethod.handleException<Exception>(e)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.micronaut.docs.server.suspend.multiple

import jakarta.inject.Singleton
import java.util.*
import kotlin.collections.ArrayList

@Singleton
open class MyService(
private val repository: CustomRepository
) {

companion object {
val events: MutableList<String> = Collections.synchronizedList(ArrayList())
}

open suspend fun someCall() {
// Simulate accessing two different data-source repositories using two transactions
tx1()
// Call another coroutine
repository.count1()
repository.count2()
}

@Transaction1
open suspend fun tx1() {
tx2()
}

@Transaction2
open suspend fun tx2() {
repository.abc()
repository.xyz()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2017-2020 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.docs.server.suspend.multiple

import io.micronaut.aop.Around
import kotlin.annotation.AnnotationRetention.RUNTIME
import kotlin.annotation.AnnotationTarget.CLASS
import kotlin.annotation.AnnotationTarget.FILE
import kotlin.annotation.AnnotationTarget.FUNCTION
import kotlin.annotation.AnnotationTarget.PROPERTY_GETTER
import kotlin.annotation.AnnotationTarget.PROPERTY_SETTER

@MustBeDocumented
@Retention(RUNTIME)
@Target(CLASS, FILE, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
@Around
annotation class Transaction1

0 comments on commit c7a8872

Please sign in to comment.