Skip to content

Commit

Permalink
Allow ot use a different UpdateExecutor for MongoDB to avoid having a tx
Browse files Browse the repository at this point in the history
  • Loading branch information
loicmathieu committed Mar 23, 2021
1 parent 5ea2ff5 commit 3b1122a
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.jboss.jandex.IndexView;
import org.jboss.jandex.Type;

import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
import io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor;
import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
Expand All @@ -21,6 +22,7 @@
import io.quarkus.hibernate.orm.rest.data.panache.PanacheEntityResource;
import io.quarkus.hibernate.orm.rest.data.panache.PanacheRepositoryResource;
import io.quarkus.hibernate.orm.rest.data.panache.runtime.RestDataPanacheExceptionMapper;
import io.quarkus.hibernate.orm.rest.data.panache.runtime.jta.TransactionalUpdateExecutor;
import io.quarkus.rest.data.panache.deployment.ResourceMetadata;
import io.quarkus.rest.data.panache.deployment.RestDataResourceBuildItem;
import io.quarkus.resteasy.common.spi.ResteasyJaxrsProviderBuildItem;
Expand All @@ -43,6 +45,11 @@ ResteasyJaxrsProviderBuildItem registerRestDataPanacheExceptionMapper() {
return new ResteasyJaxrsProviderBuildItem(RestDataPanacheExceptionMapper.class.getName());
}

@BuildStep
AdditionalBeanBuildItem registerTransactionalExecutor() {
return AdditionalBeanBuildItem.unremovableOf(TransactionalUpdateExecutor.class);
}

/**
* Find Panache entity resources and generate their implementations.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package io.quarkus.rest.data.panache.runtime.jta;
package io.quarkus.hibernate.orm.rest.data.panache.runtime.jta;

import java.util.function.Supplier;

import javax.inject.Singleton;
import javax.transaction.Transactional;

import io.quarkus.rest.data.panache.runtime.UpdateExecutor;

@Singleton
public class TransactionalExecutor {
public class TransactionalUpdateExecutor implements UpdateExecutor {

@Override
@Transactional
public <T> T execute(Supplier<T> supplier) {
return supplier.get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;

import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
import io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor;
import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
Expand All @@ -24,6 +25,7 @@
import io.quarkus.gizmo.Gizmo;
import io.quarkus.mongodb.rest.data.panache.PanacheMongoEntityResource;
import io.quarkus.mongodb.rest.data.panache.PanacheMongoRepositoryResource;
import io.quarkus.mongodb.rest.data.panache.runtime.NoopUpdateExecutor;
import io.quarkus.mongodb.rest.data.panache.runtime.RestDataPanacheExceptionMapper;
import io.quarkus.rest.data.panache.deployment.ResourceMetadata;
import io.quarkus.rest.data.panache.deployment.RestDataResourceBuildItem;
Expand All @@ -47,6 +49,11 @@ ResteasyJaxrsProviderBuildItem registerRestDataPanacheExceptionMapper() {
return new ResteasyJaxrsProviderBuildItem(RestDataPanacheExceptionMapper.class.getName());
}

@BuildStep
AdditionalBeanBuildItem registerTransactionalExecutor() {
return AdditionalBeanBuildItem.unremovableOf(NoopUpdateExecutor.class);
}

@BuildStep
void findEntityResources(CombinedIndexBuildItem index,
BuildProducer<GeneratedBeanBuildItem> implementationsProducer,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.quarkus.mongodb.rest.data.panache.runtime;

import java.util.function.Supplier;

import javax.inject.Singleton;

import io.quarkus.rest.data.panache.runtime.UpdateExecutor;

@Singleton
public class NoopUpdateExecutor implements UpdateExecutor {

@Override
public <T> T execute(Supplier<T> supplier) {
return supplier.get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import org.jboss.resteasy.links.impl.EL;

import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
import io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor;
import io.quarkus.deployment.Capabilities;
Expand All @@ -29,15 +28,9 @@
import io.quarkus.rest.data.panache.runtime.hal.HalLink;
import io.quarkus.rest.data.panache.runtime.hal.HalLinkJacksonSerializer;
import io.quarkus.rest.data.panache.runtime.hal.HalLinkJsonbSerializer;
import io.quarkus.rest.data.panache.runtime.jta.TransactionalExecutor;

public class RestDataProcessor {

@BuildStep
AdditionalBeanBuildItem registerTransactionalExecutor() {
return AdditionalBeanBuildItem.unremovableOf(TransactionalExecutor.class);
}

@BuildStep
void implementResources(CombinedIndexBuildItem index, List<RestDataResourceBuildItem> resourceBuildItems,
List<ResourcePropertiesBuildItem> resourcePropertiesBuildItems, Capabilities capabilities,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import io.quarkus.rest.data.panache.deployment.ResourceMetadata;
import io.quarkus.rest.data.panache.deployment.properties.ResourceProperties;
import io.quarkus.rest.data.panache.deployment.utils.ResponseImplementor;
import io.quarkus.rest.data.panache.runtime.jta.TransactionalExecutor;
import io.quarkus.rest.data.panache.runtime.UpdateExecutor;

public final class UpdateMethodImplementor extends StandardMethodImplementor {

Expand Down Expand Up @@ -59,7 +59,7 @@ public UpdateMethodImplementor(boolean withValidation) {
* )
* public Response update(@PathParam("id") ID id, Entity entityToSave) {
* try {
* Object newEntity = transactionalExecutor.execute(() -> {
* Object newEntity = updateExecutor.execute(() -> {
* if (resource.get(id) == null) {
* return resource.update(id, entityToSave);
* } else {
Expand Down Expand Up @@ -110,15 +110,16 @@ protected void implementInternal(ClassCreator classCreator, ResourceMetadata res
ResultHandle id = methodCreator.getMethodParam(0);
ResultHandle entityToSave = methodCreator.getMethodParam(1);

// Invoke resource methods inside a supplier function which will be given to a transactional executor to make
// Invoke resource methods inside a supplier function which will be given to an update executor.
// For ORM, this update executor will have the @Transactional annotation to make
// sure that all database operations are executed in a single transaction.
TryBlock tryBlock = implementTryBlock(methodCreator, "Failed to update an entity");
ResultHandle transactionalExecutor = getTransactionalExecutor(tryBlock);
ResultHandle updateExecutor = getUpdateExecutor(tryBlock);
ResultHandle updateFunction = getUpdateFunction(tryBlock, resourceMetadata.getResourceClass(), resource, id,
entityToSave);
ResultHandle newEntity = tryBlock.invokeVirtualMethod(
ofMethod(TransactionalExecutor.class, "execute", Object.class, Supplier.class),
transactionalExecutor, updateFunction);
ResultHandle newEntity = tryBlock.invokeInterfaceMethod(
ofMethod(UpdateExecutor.class, "execute", Object.class, Supplier.class),
updateExecutor, updateFunction);

BranchResult createdNewEntity = tryBlock.ifNotNull(newEntity);
createdNewEntity.trueBranch()
Expand Down Expand Up @@ -172,18 +173,18 @@ private void updateAndReturn(BytecodeCreator creator, String resourceClass, Resu
creator.returnValue(creator.loadNull());
}

private ResultHandle getTransactionalExecutor(BytecodeCreator creator) {
private ResultHandle getUpdateExecutor(BytecodeCreator creator) {
ResultHandle arcContainer = creator.invokeStaticMethod(ofMethod(Arc.class, "container", ArcContainer.class));
ResultHandle instanceHandle = creator.invokeInterfaceMethod(
ofMethod(ArcContainer.class, "instance", InstanceHandle.class, Class.class, Annotation[].class),
arcContainer, creator.loadClass(TransactionalExecutor.class), creator.newArray(Annotation.class, 0));
arcContainer, creator.loadClass(UpdateExecutor.class), creator.newArray(Annotation.class, 0));
ResultHandle instance = creator.invokeInterfaceMethod(
ofMethod(InstanceHandle.class, "get", Object.class), instanceHandle);

creator.ifNull(instance)
.trueBranch()
.throwException(RuntimeException.class,
TransactionalExecutor.class.getSimpleName() + " instance was not found");
UpdateExecutor.class.getSimpleName() + " instance was not found");

return instance;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import io.quarkus.rest.data.panache.deployment.ResourceMetadata;
import io.quarkus.rest.data.panache.deployment.properties.ResourceProperties;
import io.quarkus.rest.data.panache.deployment.utils.ResponseImplementor;
import io.quarkus.rest.data.panache.runtime.jta.TransactionalExecutor;
import io.quarkus.rest.data.panache.runtime.UpdateExecutor;

public final class UpdateHalMethodImplementor extends HalMethodImplementor {

Expand Down Expand Up @@ -52,7 +52,7 @@ public UpdateHalMethodImplementor(boolean withValidation) {
* &#64;Produces({"application/hal+json"})
* public Response updateHal(@PathParam("id") ID id, Entity entityToSave) {
* try {
* Object newEntity = transactionalExecutor.execute(() -> {
* Object newEntity = updateExecutor.execute(() -> {
* if (resource.get(id) == null) {
* return resource.update(id, entityToSave);
* } else {
Expand Down Expand Up @@ -103,15 +103,16 @@ protected void implementInternal(ClassCreator classCreator, ResourceMetadata res
ResultHandle id = methodCreator.getMethodParam(0);
ResultHandle entityToSave = methodCreator.getMethodParam(1);

// Invoke resource methods inside a supplier function which will be given to a transactional executor to make
// Invoke resource methods inside a supplier function which will be given to an update executor.
// For ORM, this update executor will have the @Transactional annotation to make
// sure that all database operations are executed in a single transaction.
TryBlock tryBlock = implementTryBlock(methodCreator, "Failed to update an entity");
ResultHandle transactionalExecutor = getTransactionalExecutor(tryBlock);
ResultHandle updateExecutor = getUpdateExecutor(tryBlock);
ResultHandle updateFunction = getUpdateFunction(tryBlock, resourceMetadata.getResourceClass(), resource, id,
entityToSave);
ResultHandle newEntity = tryBlock.invokeVirtualMethod(
ofMethod(TransactionalExecutor.class, "execute", Object.class, Supplier.class),
transactionalExecutor, updateFunction);
ResultHandle newEntity = tryBlock.invokeInterfaceMethod(
ofMethod(UpdateExecutor.class, "execute", Object.class, Supplier.class),
updateExecutor, updateFunction);

BranchResult createdNewEntity = tryBlock.ifNotNull(newEntity);
ResultHandle wrappedNewEntity = wrapHalEntity(createdNewEntity.trueBranch(), newEntity);
Expand Down Expand Up @@ -167,18 +168,18 @@ private void updateAndReturn(BytecodeCreator creator, String resourceClass, Resu
creator.returnValue(creator.loadNull());
}

private ResultHandle getTransactionalExecutor(BytecodeCreator creator) {
private ResultHandle getUpdateExecutor(BytecodeCreator creator) {
ResultHandle arcContainer = creator.invokeStaticMethod(ofMethod(Arc.class, "container", ArcContainer.class));
ResultHandle instanceHandle = creator.invokeInterfaceMethod(
ofMethod(ArcContainer.class, "instance", InstanceHandle.class, Class.class, Annotation[].class),
arcContainer, creator.loadClass(TransactionalExecutor.class), creator.newArray(Annotation.class, 0));
arcContainer, creator.loadClass(UpdateExecutor.class), creator.newArray(Annotation.class, 0));
ResultHandle instance = creator.invokeInterfaceMethod(
ofMethod(InstanceHandle.class, "get", Object.class), instanceHandle);

creator.ifNull(instance)
.trueBranch()
.throwException(RuntimeException.class,
TransactionalExecutor.class.getSimpleName() + " instance was not found");
UpdateExecutor.class.getSimpleName() + " instance was not found");

return instance;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.rest.data.panache.runtime;

import java.util.function.Supplier;

public interface UpdateExecutor {
<T> T execute(Supplier<T> supplier);
}

0 comments on commit 3b1122a

Please sign in to comment.