mirror of
https://github.com/usatiuk/dhfs.git
synced 2025-10-28 20:47:49 +01:00
seemingly working record data classes
This commit is contained in:
@@ -1,65 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-alloc-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>objects-alloc-deployment</artifactId>
|
||||
<name>DHFS objects allocation - Deployment</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-arc-deployment</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-alloc</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common-deployment</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5-internal</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-compile</id>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-extension-processor</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.deployment;
|
||||
|
||||
import org.jboss.jandex.DotName;
|
||||
|
||||
public record JDataFieldInfo(String name, DotName type) {
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.deployment;
|
||||
|
||||
import io.quarkus.builder.item.MultiBuildItem;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
|
||||
public final class JDataIndexBuildItem extends MultiBuildItem {
|
||||
public final ClassInfo jData;
|
||||
|
||||
public JDataIndexBuildItem(ClassInfo jData) {
|
||||
this.jData = jData;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.deployment;
|
||||
|
||||
import io.quarkus.builder.item.MultiBuildItem;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public final class JDataInfoBuildItem extends MultiBuildItem {
|
||||
public final ClassInfo klass;
|
||||
public final Map<String, JDataFieldInfo> fields;
|
||||
|
||||
public JDataInfoBuildItem(ClassInfo klass, Map<String, JDataFieldInfo> fields) {
|
||||
this.klass = klass;
|
||||
this.fields = fields;
|
||||
}
|
||||
}
|
||||
@@ -1,375 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.deployment;
|
||||
|
||||
import com.usatiuk.objects.alloc.runtime.ChangeTrackingJData;
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JDataAllocVersionProvider;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
|
||||
import io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor;
|
||||
import io.quarkus.deployment.GeneratedClassGizmoAdaptor;
|
||||
import io.quarkus.deployment.annotations.BuildProducer;
|
||||
import io.quarkus.deployment.annotations.BuildStep;
|
||||
import io.quarkus.deployment.builditem.ApplicationIndexBuildItem;
|
||||
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
|
||||
import io.quarkus.gizmo.*;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.DotName;
|
||||
import org.jboss.jandex.MethodInfo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.lang.reflect.Modifier.*;
|
||||
|
||||
class ObjectsAllocProcessor {
|
||||
@BuildStep
|
||||
void collectJDatas(BuildProducer<JDataIndexBuildItem> producer, ApplicationIndexBuildItem jandex) {
|
||||
var jdatas = jandex.getIndex().getAllKnownSubinterfaces(JData.class);
|
||||
|
||||
// Collect the leaves
|
||||
for (var jdata : jdatas) {
|
||||
System.out.println("Found JData: " + jdata.name());
|
||||
if (jandex.getIndex().getAllKnownSubinterfaces(jdata.name()).isEmpty()) {
|
||||
System.out.println("Found JData leaf: " + jdata.name());
|
||||
producer.produce(new JDataIndexBuildItem(jdata));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String KEY_NAME = "key";
|
||||
private static final String VERSION_NAME = "version";
|
||||
private static final List<String> SPECIAL_FIELDS = List.of(KEY_NAME, VERSION_NAME);
|
||||
|
||||
String propNameToFieldName(String name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
String propNameToGetterName(String name) {
|
||||
return "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
}
|
||||
|
||||
String propNameToSetterName(String name) {
|
||||
return "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
}
|
||||
|
||||
DotName getDataClassName(ClassInfo jData) {
|
||||
return DotName.createComponentized(jData.name().packagePrefixName(), jData.name().local() + "Data");
|
||||
}
|
||||
|
||||
DotName getCTClassName(ClassInfo jData) {
|
||||
return DotName.createComponentized(jData.name().packagePrefixName(), jData.name().local() + "CTData");
|
||||
}
|
||||
|
||||
DotName getImmutableClassName(ClassInfo jData) {
|
||||
return DotName.createComponentized(jData.name().packagePrefixName(), jData.name().local() + "ImmutableData");
|
||||
}
|
||||
|
||||
@BuildStep
|
||||
void generateDataClass(List<JDataInfoBuildItem> jDataItems, BuildProducer<GeneratedClassBuildItem> generatedClasses) {
|
||||
var gizmoAdapter = new GeneratedClassGizmoAdaptor(generatedClasses, true);
|
||||
for (var item : jDataItems) {
|
||||
try (ClassCreator classCreator = ClassCreator.builder()
|
||||
.className(getDataClassName(item.klass).toString())
|
||||
.interfaces(JData.class)
|
||||
.interfaces(item.klass.name().toString())
|
||||
.interfaces(Serializable.class)
|
||||
.classOutput(gizmoAdapter)
|
||||
.build()) {
|
||||
|
||||
|
||||
var fieldsMap = createFields(item, classCreator);
|
||||
|
||||
for (var field : fieldsMap.values()) {
|
||||
if (!SPECIAL_FIELDS.contains(field.getName())) {
|
||||
try (var setter = classCreator.getMethodCreator(propNameToSetterName(field.getName()), void.class, field.getType())) {
|
||||
setter.writeInstanceField(field, setter.getThis(), setter.getMethodParam(0));
|
||||
setter.returnVoid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try (var constructor = classCreator.getConstructorCreator(JObjectKey.class, long.class)) {
|
||||
constructor.invokeSpecialMethod(MethodDescriptor.ofConstructor(Object.class), constructor.getThis());
|
||||
constructor.writeInstanceField(fieldsMap.get(KEY_NAME), constructor.getThis(), constructor.getMethodParam(0));
|
||||
constructor.writeInstanceField(fieldsMap.get(VERSION_NAME), constructor.getThis(), constructor.getMethodParam(1));
|
||||
constructor.returnVoid();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String MODIFIED_FIELD_NAME = "_modified";
|
||||
private static final String ON_CHANGE_METHOD_NAME = "onChange";
|
||||
|
||||
@BuildStep
|
||||
void generateCTClass(List<JDataInfoBuildItem> jDataItems, BuildProducer<GeneratedClassBuildItem> generatedClasses) {
|
||||
var gizmoAdapter = new GeneratedClassGizmoAdaptor(generatedClasses, true);
|
||||
for (var item : jDataItems) {
|
||||
try (ClassCreator classCreator = ClassCreator.builder()
|
||||
.className(getCTClassName(item.klass).toString())
|
||||
.interfaces(JData.class, ChangeTrackingJData.class)
|
||||
.interfaces(item.klass.name().toString())
|
||||
.interfaces(Serializable.class)
|
||||
.classOutput(gizmoAdapter)
|
||||
.build()) {
|
||||
var modified = classCreator.getFieldCreator(MODIFIED_FIELD_NAME, boolean.class);
|
||||
modified.setModifiers(PRIVATE | TRANSIENT);
|
||||
|
||||
try (var modifiedGetter = classCreator.getMethodCreator("isModified", boolean.class)) {
|
||||
modifiedGetter.returnValue(modifiedGetter.readInstanceField(modified.getFieldDescriptor(), modifiedGetter.getThis()));
|
||||
}
|
||||
|
||||
try (var onChanged = classCreator.getMethodCreator(ON_CHANGE_METHOD_NAME, void.class)) {
|
||||
onChanged.writeInstanceField(modified.getFieldDescriptor(), onChanged.getThis(), onChanged.load(true));
|
||||
onChanged.returnVoid();
|
||||
}
|
||||
|
||||
try (var wrapped = classCreator.getMethodCreator("wrapped", item.klass.name().toString())) {
|
||||
wrapped.returnValue(wrapped.getThis());
|
||||
}
|
||||
|
||||
try (var wrapped = classCreator.getMethodCreator("wrapped", JData.class)) {
|
||||
wrapped.returnValue(wrapped.getThis());
|
||||
}
|
||||
|
||||
var fieldsMap = createFields(item, classCreator);
|
||||
|
||||
for (var field : fieldsMap.values()) {
|
||||
if (!SPECIAL_FIELDS.contains(field.getName())) {
|
||||
try (var setter = classCreator.getMethodCreator(propNameToSetterName(field.getName()), void.class, field.getType())) {
|
||||
setter.writeInstanceField(field, setter.getThis(), setter.getMethodParam(0));
|
||||
setter.invokeVirtualMethod(MethodDescriptor.ofMethod(classCreator.getClassName(), ON_CHANGE_METHOD_NAME, void.class), setter.getThis());
|
||||
setter.returnVoid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try (var constructor = classCreator.getConstructorCreator(item.klass.name().toString(), long.class.getName())) {
|
||||
constructor.invokeSpecialMethod(MethodDescriptor.ofConstructor(Object.class), constructor.getThis());
|
||||
constructor.writeInstanceField(modified.getFieldDescriptor(), constructor.getThis(), constructor.load(true)); // FIXME:
|
||||
for (var field : fieldsMap.values()) {
|
||||
if (!Objects.equals(field.getName(), VERSION_NAME))
|
||||
constructor.writeInstanceField(field, constructor.getThis(), constructor.invokeInterfaceMethod(
|
||||
MethodDescriptor.ofMethod(item.klass.name().toString(), propNameToGetterName(field.getName()), field.getType()),
|
||||
constructor.getMethodParam(0)
|
||||
));
|
||||
}
|
||||
constructor.writeInstanceField(fieldsMap.get(VERSION_NAME), constructor.getThis(), constructor.getMethodParam(1));
|
||||
constructor.returnVoid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@BuildStep
|
||||
void generateImmutableClass(List<JDataInfoBuildItem> jDataItems, BuildProducer<GeneratedClassBuildItem> generatedClasses) {
|
||||
var gizmoAdapter = new GeneratedClassGizmoAdaptor(generatedClasses, true);
|
||||
for (var item : jDataItems) {
|
||||
try (ClassCreator classCreator = ClassCreator.builder()
|
||||
.className(getImmutableClassName(item.klass).toString())
|
||||
.interfaces(JData.class, ChangeTrackingJData.class)
|
||||
.interfaces(item.klass.name().toString())
|
||||
.interfaces(Serializable.class)
|
||||
.classOutput(gizmoAdapter)
|
||||
.build()) {
|
||||
|
||||
var fieldsMap = createFields(item, classCreator);
|
||||
|
||||
for (var field : fieldsMap.values()) {
|
||||
try (var setter = classCreator.getMethodCreator(propNameToSetterName(field.getName()), void.class, field.getType())) {
|
||||
setter.throwException(UnsupportedOperationException.class, "Immutable object");
|
||||
}
|
||||
}
|
||||
|
||||
try (var constructor = classCreator.getConstructorCreator(item.klass.name().toString())) {
|
||||
constructor.invokeSpecialMethod(MethodDescriptor.ofConstructor(Object.class), constructor.getThis());
|
||||
for (var field : fieldsMap.values()) {
|
||||
constructor.writeInstanceField(field, constructor.getThis(), constructor.invokeInterfaceMethod(
|
||||
MethodDescriptor.ofMethod(item.klass.name().toString(), propNameToGetterName(field.getName()), field.getType()),
|
||||
constructor.getMethodParam(0)
|
||||
));
|
||||
}
|
||||
constructor.returnVoid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Map<String, FieldDescriptor> createFields(JDataInfoBuildItem item, ClassCreator classCreator) {
|
||||
return item.fields.values().stream().map(jDataFieldInfo -> {
|
||||
var fc = classCreator.getFieldCreator(propNameToFieldName(jDataFieldInfo.name()), jDataFieldInfo.type().toString());
|
||||
|
||||
if (SPECIAL_FIELDS.contains(jDataFieldInfo.name())) {
|
||||
fc.setModifiers(PRIVATE | FINAL);
|
||||
} else {
|
||||
fc.setModifiers(PRIVATE);
|
||||
}
|
||||
|
||||
try (var getter = classCreator.getMethodCreator(propNameToGetterName(jDataFieldInfo.name()), jDataFieldInfo.type().toString())) {
|
||||
getter.returnValue(getter.readInstanceField(fc.getFieldDescriptor(), getter.getThis()));
|
||||
}
|
||||
return Pair.of(jDataFieldInfo, fc.getFieldDescriptor());
|
||||
}).collect(Collectors.toUnmodifiableMap(i -> i.getLeft().name(), Pair::getRight));
|
||||
}
|
||||
|
||||
List<ClassInfo> collectInterfaces(ClassInfo type, ApplicationIndexBuildItem jandex) {
|
||||
return Stream.concat(Stream.of(type), type.interfaceNames().stream()
|
||||
.flatMap(x -> {
|
||||
var ret = jandex.getIndex().getClassByName(x);
|
||||
if (ret == null) {
|
||||
System.out.println("Interface not found! " + x);
|
||||
return Stream.empty();
|
||||
}
|
||||
return Stream.of(ret);
|
||||
})
|
||||
.flatMap(i -> collectInterfaces(i, jandex).stream()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
Map<String, MethodInfo> collectMethods(List<ClassInfo> types) {
|
||||
return types.stream()
|
||||
.flatMap(x -> x.methods().stream())
|
||||
.filter(x -> x.name().startsWith("get") || x.name().startsWith("set"))
|
||||
.collect(Collectors.toMap(MethodInfo::name, x -> x));
|
||||
}
|
||||
|
||||
@BuildStep
|
||||
void collectData(BuildProducer<JDataInfoBuildItem> producer, List<JDataIndexBuildItem> items, ApplicationIndexBuildItem jandex) {
|
||||
for (var item : items) {
|
||||
var methodNameToInfo = collectMethods(collectInterfaces(item.jData, jandex));
|
||||
|
||||
var reducableSet = new TreeSet<>(methodNameToInfo.keySet());
|
||||
|
||||
var fields = new TreeMap<String, JDataFieldInfo>();
|
||||
if (reducableSet.contains(propNameToGetterName(KEY_NAME))) {
|
||||
reducableSet.remove(propNameToGetterName(KEY_NAME));
|
||||
var methodInfo = methodNameToInfo.get(propNameToGetterName(KEY_NAME));
|
||||
if (!methodInfo.returnType().name().equals(DotName.createSimple(JObjectKey.class.getName()))) {
|
||||
throw new RuntimeException("Key getter must return JObjectKey");
|
||||
}
|
||||
fields.put(KEY_NAME, new JDataFieldInfo(KEY_NAME, methodNameToInfo.get(propNameToGetterName(KEY_NAME)).returnType().name()));
|
||||
} else {
|
||||
// throw new RuntimeException("Missing key getter");
|
||||
System.out.println("Missing key getter for " + item.jData);
|
||||
// FIXME!: No matter what, I couldn't get JData to get indexed by jandex
|
||||
fields.put(KEY_NAME, new JDataFieldInfo(KEY_NAME, DotName.createSimple(JObjectKey.class)));
|
||||
fields.put(VERSION_NAME, new JDataFieldInfo(VERSION_NAME, DotName.createSimple(long.class)));
|
||||
}
|
||||
|
||||
// Find pairs of getters and setters
|
||||
// FIXME:
|
||||
while (!reducableSet.isEmpty()) {
|
||||
var name = reducableSet.first();
|
||||
reducableSet.remove(name);
|
||||
if (name.startsWith("get")) {
|
||||
var setterName = "set" + name.substring(3);
|
||||
if (reducableSet.contains(setterName)) {
|
||||
reducableSet.remove(setterName);
|
||||
} else {
|
||||
throw new RuntimeException("Missing setter for getter: " + name);
|
||||
}
|
||||
|
||||
var getter = methodNameToInfo.get(name);
|
||||
var setter = methodNameToInfo.get(setterName);
|
||||
|
||||
if (!getter.returnType().equals(setter.parameters().getFirst().type())) {
|
||||
throw new RuntimeException("Getter and setter types do not match: " + name);
|
||||
}
|
||||
|
||||
var variableName = name.substring(3, 4).toLowerCase() + name.substring(4);
|
||||
|
||||
fields.put(variableName, new JDataFieldInfo(variableName, getter.returnType().name()));
|
||||
} else {
|
||||
throw new RuntimeException("Unknown method name: " + name);
|
||||
}
|
||||
}
|
||||
producer.produce(new JDataInfoBuildItem(item.jData, Collections.unmodifiableMap(fields)));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns false branch
|
||||
void matchClass(BytecodeCreator bytecodeCreator, ResultHandle toMatch, List<ClassInfo> types, ClassTagFunction fn) {
|
||||
for (var type : types) {
|
||||
var eq = bytecodeCreator.instanceOf(toMatch, type.name().toString());
|
||||
var cmp = bytecodeCreator.ifTrue(eq);
|
||||
fn.apply(type, cmp.trueBranch(), toMatch);
|
||||
}
|
||||
}
|
||||
|
||||
interface ClassTagFunction {
|
||||
void apply(ClassInfo type, BytecodeCreator branch, ResultHandle value);
|
||||
}
|
||||
|
||||
// Returns false branch
|
||||
void matchClassTag(BytecodeCreator bytecodeCreator, ResultHandle toMatch, List<ClassInfo> types, ClassTagFunction fn) {
|
||||
for (var type : types) {
|
||||
var eq = bytecodeCreator.invokeVirtualMethod(
|
||||
MethodDescriptor.ofMethod(Object.class, "equals", boolean.class, Object.class),
|
||||
toMatch,
|
||||
bytecodeCreator.loadClass(type.name().toString())
|
||||
);
|
||||
|
||||
var cmp = bytecodeCreator.ifTrue(eq);
|
||||
fn.apply(type, cmp.trueBranch(), toMatch);
|
||||
}
|
||||
}
|
||||
|
||||
@BuildStep
|
||||
void makeJDataThingy(List<JDataInfoBuildItem> jDataItems,
|
||||
BuildProducer<GeneratedBeanBuildItem> generatedBeans) {
|
||||
var data = jDataItems.stream().collect(Collectors.toUnmodifiableMap(i -> i.klass, x -> x));
|
||||
var classes = data.keySet().stream().map(ClassInfo::asClass).toList();
|
||||
|
||||
var gizmoAdapter = new GeneratedBeanGizmoAdaptor(generatedBeans);
|
||||
|
||||
try (ClassCreator classCreator = ClassCreator.builder()
|
||||
.className("com.usatiuk.objects.alloc.generated.ObjectAllocatorImpl")
|
||||
.interfaces(ObjectAllocator.class)
|
||||
.classOutput(gizmoAdapter)
|
||||
.build()) {
|
||||
|
||||
classCreator.addAnnotation(Singleton.class);
|
||||
|
||||
var versionProvider = classCreator.getFieldCreator("versionProvider", JDataAllocVersionProvider.class);
|
||||
versionProvider.addAnnotation(Inject.class);
|
||||
versionProvider.setModifiers(PUBLIC);
|
||||
|
||||
Function<BytecodeCreator, ResultHandle> loadVersion = (block) -> block.invokeInterfaceMethod(
|
||||
MethodDescriptor.ofMethod(JDataAllocVersionProvider.class, "getVersion", long.class),
|
||||
block.readInstanceField(versionProvider.getFieldDescriptor(), block.getThis())
|
||||
);
|
||||
|
||||
try (MethodCreator methodCreator = classCreator.getMethodCreator("create", JData.class, Class.class, JObjectKey.class)) {
|
||||
matchClassTag(methodCreator, methodCreator.getMethodParam(0), classes, (type, branch, value) -> {
|
||||
branch.returnValue(branch.newInstance(MethodDescriptor.ofConstructor(getDataClassName(type).toString(), JObjectKey.class, long.class), branch.getMethodParam(1), loadVersion.apply(branch)));
|
||||
});
|
||||
methodCreator.throwException(IllegalArgumentException.class, "Unknown type");
|
||||
}
|
||||
|
||||
try (MethodCreator methodCreator = classCreator.getMethodCreator("copy", ChangeTrackingJData.class, JData.class)) {
|
||||
matchClass(methodCreator, methodCreator.getMethodParam(0), classes, (type, branch, value) -> {
|
||||
branch.returnValue(branch.newInstance(MethodDescriptor.ofConstructor(getCTClassName(type).toString(), type.name().toString(), long.class.getName()), value, loadVersion.apply(branch)));
|
||||
});
|
||||
methodCreator.throwException(IllegalArgumentException.class, "Unknown type");
|
||||
}
|
||||
|
||||
try (MethodCreator methodCreator = classCreator.getMethodCreator("unmodifiable", JData.class, JData.class)) {
|
||||
matchClass(methodCreator, methodCreator.getMethodParam(0), classes, (type, branch, value) -> {
|
||||
branch.returnValue(branch.newInstance(MethodDescriptor.ofConstructor(getImmutableClassName(type).toString(), type.name().toString()), value));
|
||||
});
|
||||
methodCreator.throwException(IllegalArgumentException.class, "Unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.test;
|
||||
|
||||
import org.jboss.shrinkwrap.api.ShrinkWrap;
|
||||
import org.jboss.shrinkwrap.api.spec.JavaArchive;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
import io.quarkus.test.QuarkusDevModeTest;
|
||||
|
||||
@Disabled
|
||||
public class ObjectsAllocDevModeTest {
|
||||
|
||||
// Start hot reload (DevMode) test with your extension loaded
|
||||
@RegisterExtension
|
||||
static final QuarkusDevModeTest devModeTest = new QuarkusDevModeTest()
|
||||
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class));
|
||||
|
||||
@Test
|
||||
public void writeYourOwnDevModeTest() {
|
||||
// Write your dev mode tests here - see the testing extension guide https://quarkus.io/guides/writing-extensions#testing-hot-reload for more information
|
||||
Assertions.assertTrue(true, "Add dev mode assertions to " + getClass().getName());
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.test;
|
||||
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import io.quarkus.test.QuarkusUnitTest;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jboss.shrinkwrap.api.ShrinkWrap;
|
||||
import org.jboss.shrinkwrap.api.spec.JavaArchive;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
@Disabled
|
||||
public class ObjectsAllocTest {
|
||||
|
||||
// Start unit test with your extension loaded
|
||||
@RegisterExtension
|
||||
static final QuarkusUnitTest unitTest = new QuarkusUnitTest()
|
||||
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class));
|
||||
|
||||
@Test
|
||||
public void writeYourOwnUnitTest() {
|
||||
// Write your unit tests here - see the testing extension guide https://quarkus.io/guides/writing-extensions#testing-extensions for more information
|
||||
Assertions.assertTrue(true, "Add some assertions to " + getClass().getName());
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-alloc-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>objects-alloc-integration-tests</artifactId>
|
||||
<name>DHFS objects allocation - Integration Tests</name>
|
||||
|
||||
<properties>
|
||||
<skipITs>true</skipITs>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-alloc</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-alloc-deployment</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common-deployment</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build</goal>
|
||||
<goal>generate-code</goal>
|
||||
<goal>generate-code-tests</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<native.image.path>${project.build.directory}/${project.build.finalName}-runner
|
||||
</native.image.path>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
<maven.home>${maven.home}</maven.home>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>native-image</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>native</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skipTests>${native.surefire.skip}</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<properties>
|
||||
<skipITs>false</skipITs>
|
||||
<quarkus.native.enabled>true</quarkus.native.enabled>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.it;
|
||||
|
||||
import com.usatiuk.objects.common.runtime.JDataAllocVersionProvider;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
public class DummyVersionProvider implements JDataAllocVersionProvider {
|
||||
|
||||
long version = 0;
|
||||
|
||||
@Override
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(long version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.it;
|
||||
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
|
||||
public interface TestJDataAssorted extends JData {
|
||||
String getLastName();
|
||||
|
||||
void setLastName(String lastName);
|
||||
|
||||
long getAge();
|
||||
|
||||
void setAge(long age);
|
||||
|
||||
JObjectKey getKidKey();
|
||||
|
||||
void setKidKey(JObjectKey kid);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.it;
|
||||
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
|
||||
public interface TestJDataEmpty extends JData {
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
quarkus.package.jar.decompiler.enabled=true
|
||||
@@ -1,96 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.it;
|
||||
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
import jakarta.inject.Inject;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@QuarkusTest
|
||||
public class ObjectAllocIT {
|
||||
@Inject
|
||||
ObjectAllocator objectAllocator;
|
||||
|
||||
@Inject
|
||||
DummyVersionProvider dummyVersionProvider;
|
||||
|
||||
@Test
|
||||
void testCreateVersion() {
|
||||
dummyVersionProvider.setVersion(1);
|
||||
var newObject = objectAllocator.create(TestJDataEmpty.class, new JObjectKey("TestJDataEmptyKey"));
|
||||
Assertions.assertNotNull(newObject);
|
||||
Assertions.assertEquals("TestJDataEmptyKey", newObject.getKey().name());
|
||||
Assertions.assertEquals(1, newObject.getVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCopyVersion() {
|
||||
dummyVersionProvider.setVersion(1);
|
||||
var newObject = objectAllocator.create(TestJDataAssorted.class, new JObjectKey("TestJDataAssorted"));
|
||||
newObject.setLastName("1");
|
||||
Assertions.assertNotNull(newObject);
|
||||
Assertions.assertEquals("TestJDataAssorted", newObject.getKey().name());
|
||||
Assertions.assertEquals(1, newObject.getVersion());
|
||||
|
||||
dummyVersionProvider.setVersion(2);
|
||||
var copyObject = objectAllocator.copy(newObject);
|
||||
Assertions.assertNotNull(copyObject);
|
||||
Assertions.assertFalse(copyObject.isModified());
|
||||
Assertions.assertEquals("1", copyObject.wrapped().getLastName());
|
||||
Assertions.assertEquals(2, copyObject.wrapped().getVersion());
|
||||
Assertions.assertEquals(1, newObject.getVersion());
|
||||
copyObject.wrapped().setLastName("2");
|
||||
Assertions.assertTrue(copyObject.isModified());
|
||||
Assertions.assertEquals("2", copyObject.wrapped().getLastName());
|
||||
Assertions.assertEquals("1", newObject.getLastName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateObject() {
|
||||
var newObject = objectAllocator.create(TestJDataEmpty.class, new JObjectKey("TestJDataEmptyKey"));
|
||||
Assertions.assertNotNull(newObject);
|
||||
Assertions.assertEquals("TestJDataEmptyKey", newObject.getKey().name());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testCopyObject() {
|
||||
var newObject = objectAllocator.create(TestJDataAssorted.class, new JObjectKey("TestJDataAssorted"));
|
||||
newObject.setLastName("1");
|
||||
Assertions.assertNotNull(newObject);
|
||||
Assertions.assertEquals("TestJDataAssorted", newObject.getKey().name());
|
||||
|
||||
var copyObject = objectAllocator.copy(newObject);
|
||||
Assertions.assertNotNull(copyObject);
|
||||
Assertions.assertFalse(copyObject.isModified());
|
||||
Assertions.assertEquals("1", copyObject.wrapped().getLastName());
|
||||
copyObject.wrapped().setLastName("2");
|
||||
Assertions.assertTrue(copyObject.isModified());
|
||||
Assertions.assertEquals("2", copyObject.wrapped().getLastName());
|
||||
Assertions.assertEquals("1", newObject.getLastName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testImmutable() {
|
||||
var newObject = objectAllocator.create(TestJDataAssorted.class, new JObjectKey("TestJDataAssorted"));
|
||||
newObject.setLastName("1");
|
||||
Assertions.assertNotNull(newObject);
|
||||
Assertions.assertEquals("TestJDataAssorted", newObject.getKey().name());
|
||||
|
||||
var copyObject = objectAllocator.unmodifiable(newObject);
|
||||
Assertions.assertNotNull(copyObject);
|
||||
Assertions.assertEquals("1", copyObject.getLastName());
|
||||
Assertions.assertThrows(UnsupportedOperationException.class, () -> copyObject.setLastName("2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testImmutable2() {
|
||||
var newObject = objectAllocator.create(TestJDataEmpty.class, new JObjectKey("TestJDataEmpty"));
|
||||
Assertions.assertNotNull(newObject);
|
||||
Assertions.assertEquals("TestJDataEmpty", newObject.getKey().name());
|
||||
|
||||
var copyObject = objectAllocator.unmodifiable(newObject);
|
||||
Assertions.assertNotNull(copyObject);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.usatiuk.dhfs</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-alloc-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>DHFS objects allocation - Parent</name>
|
||||
|
||||
<modules>
|
||||
<module>deployment</module>
|
||||
<module>runtime</module>
|
||||
<module>integration-tests</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
@@ -1,64 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-alloc-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>objects-alloc</artifactId>
|
||||
<name>DHFS objects allocation - Runtime</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-arc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-extension-maven-plugin</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>extension-descriptor</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<deployment>${project.groupId}:${project.artifactId}-deployment:${project.version}
|
||||
</deployment>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-compile</id>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-extension-processor</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.runtime;
|
||||
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
|
||||
public interface ChangeTrackingJData<T extends JData> {
|
||||
T wrapped();
|
||||
|
||||
boolean isModified();
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.runtime;
|
||||
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
|
||||
public interface ObjectAllocator {
|
||||
<T extends JData> T create(Class<T> type, JObjectKey key);
|
||||
|
||||
<T extends JData> ChangeTrackingJData<T> copy(T obj);
|
||||
|
||||
<T extends JData> T unmodifiable(T obj);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
name: DHFS objects allocation
|
||||
#description: Do something useful.
|
||||
metadata:
|
||||
# keywords:
|
||||
# - objects-alloc
|
||||
# guide: ... # To create and publish this guide, see https://github.com/quarkiverse/quarkiverse/wiki#documenting-your-extension
|
||||
# categories:
|
||||
# - "miscellaneous"
|
||||
# status: "preview"
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.usatiuk.objects.common.runtime;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
// TODO: This could be maybe moved to a separate module?
|
||||
// The base class for JObject data
|
||||
// Only one instance of this "exists" per key, the instance in the manager is canonical
|
||||
// When committing a transaction, the instance is checked against it, if it isn't the same, a race occurred.
|
||||
// It is immutable, its version is filled in by the allocator from the AllocVersionProvider
|
||||
public interface JData {
|
||||
JObjectKey getKey();
|
||||
|
||||
long getVersion();
|
||||
public interface JData extends Serializable {
|
||||
JObjectKey key();
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.usatiuk.objects.common.runtime;
|
||||
|
||||
public interface JDataAllocVersionProvider {
|
||||
long getVersion();
|
||||
}
|
||||
@@ -3,4 +3,7 @@ package com.usatiuk.objects.common.runtime;
|
||||
import java.io.Serializable;
|
||||
|
||||
public record JObjectKey(String name) implements Serializable {
|
||||
public static JObjectKey of(String name) {
|
||||
return new JObjectKey(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,17 +64,6 @@
|
||||
<artifactId>supportlib</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-alloc</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-alloc-deployment</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common</artifactId>
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.usatiuk.dhfs.objects.persistence.TxManifest;
|
||||
import com.usatiuk.dhfs.objects.transaction.*;
|
||||
import com.usatiuk.dhfs.utils.AutoCloseableNoThrow;
|
||||
import com.usatiuk.dhfs.utils.DataLocker;
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import io.quarkus.logging.Log;
|
||||
@@ -33,8 +32,6 @@ public class JObjectManager {
|
||||
@Inject
|
||||
ObjectSerializer<JDataVersionedWrapper> objectSerializer;
|
||||
@Inject
|
||||
ObjectAllocator objectAllocator;
|
||||
@Inject
|
||||
TransactionFactory transactionFactory;
|
||||
|
||||
private final List<PreCommitTxHook> _preCommitTxHooks;
|
||||
@@ -52,7 +49,7 @@ public class JObjectManager {
|
||||
|
||||
public JDataWrapper(JDataVersionedWrapper<T> referent) {
|
||||
super(referent);
|
||||
var key = referent.data().getKey();
|
||||
var key = referent.data().key();
|
||||
CLEANER.register(referent, () -> {
|
||||
_objects.remove(key, this);
|
||||
});
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.usatiuk.dhfs.objects.transaction;
|
||||
|
||||
import com.usatiuk.dhfs.objects.JDataVersionedWrapper;
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
@@ -16,9 +15,6 @@ import java.util.Optional;
|
||||
|
||||
@ApplicationScoped
|
||||
public class TransactionFactoryImpl implements TransactionFactory {
|
||||
@Inject
|
||||
ObjectAllocator objectAllocator;
|
||||
|
||||
private class TransactionImpl implements TransactionPrivate {
|
||||
@Getter(AccessLevel.PUBLIC)
|
||||
private final long _id;
|
||||
@@ -68,8 +64,8 @@ public class TransactionFactoryImpl implements TransactionFactory {
|
||||
public void put(JData obj) {
|
||||
// get(JData.class, obj.getKey(), LockingStrategy.OPTIMISTIC);
|
||||
|
||||
_writes.put(obj.getKey(), new TxRecord.TxObjectRecordWrite<>(obj));
|
||||
_newWrites.put(obj.getKey(), new TxRecord.TxObjectRecordWrite<>(obj));
|
||||
_writes.put(obj.key(), new TxRecord.TxObjectRecordWrite<>(obj));
|
||||
_newWrites.put(obj.key(), new TxRecord.TxObjectRecordWrite<>(obj));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.usatiuk.dhfs.objects.transaction;
|
||||
|
||||
import com.usatiuk.objects.common.runtime.JDataAllocVersionProvider;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class TransactionObjectAllocVersionProvider implements JDataAllocVersionProvider {
|
||||
@Inject
|
||||
Transaction transaction;
|
||||
|
||||
public long getVersion() {
|
||||
return transaction.getId();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,7 +11,7 @@ public class TxRecord {
|
||||
public record TxObjectRecordWrite<T extends JData>(JData data) implements TxObjectRecord<T> {
|
||||
@Override
|
||||
public JObjectKey key() {
|
||||
return data.getKey();
|
||||
return data.key();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.usatiuk.dhfs.objects;
|
||||
import com.usatiuk.dhfs.objects.data.Parent;
|
||||
import com.usatiuk.dhfs.objects.transaction.LockingStrategy;
|
||||
import com.usatiuk.dhfs.objects.transaction.Transaction;
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import io.quarkus.logging.Log;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
@@ -25,23 +24,19 @@ public class ObjectsTest {
|
||||
@Inject
|
||||
Transaction curTx;
|
||||
|
||||
@Inject
|
||||
ObjectAllocator alloc;
|
||||
|
||||
@Test
|
||||
void createObject() {
|
||||
{
|
||||
txm.begin();
|
||||
var newParent = alloc.create(Parent.class, new JObjectKey("Parent"));
|
||||
newParent.setLastName("John");
|
||||
var newParent = new Parent(JObjectKey.of("Parent"), "John");
|
||||
curTx.put(newParent);
|
||||
txm.commit();
|
||||
}
|
||||
|
||||
{
|
||||
txm.begin();
|
||||
var parent = curTx.get(Parent.class, new JObjectKey("Parent")).orElse(null);
|
||||
Assertions.assertEquals("John", parent.getLastName());
|
||||
var parent = curTx.get(Parent.class, JObjectKey.of("Parent")).orElse(null);
|
||||
Assertions.assertEquals("John", parent.name());
|
||||
txm.commit();
|
||||
}
|
||||
}
|
||||
@@ -50,28 +45,27 @@ public class ObjectsTest {
|
||||
void createDeleteObject() {
|
||||
{
|
||||
txm.begin();
|
||||
var newParent = alloc.create(Parent.class, new JObjectKey("Parent"));
|
||||
newParent.setLastName("John");
|
||||
var newParent = new Parent(JObjectKey.of("Parent2"), "John");
|
||||
curTx.put(newParent);
|
||||
txm.commit();
|
||||
}
|
||||
|
||||
{
|
||||
txm.begin();
|
||||
var parent = curTx.get(Parent.class, new JObjectKey("Parent")).orElse(null);
|
||||
Assertions.assertEquals("John", parent.getLastName());
|
||||
var parent = curTx.get(Parent.class, JObjectKey.of("Parent2")).orElse(null);
|
||||
Assertions.assertEquals("John", parent.name());
|
||||
txm.commit();
|
||||
}
|
||||
|
||||
{
|
||||
txm.begin();
|
||||
curTx.delete(new JObjectKey("Parent"));
|
||||
curTx.delete(new JObjectKey("Parent2"));
|
||||
txm.commit();
|
||||
}
|
||||
|
||||
{
|
||||
txm.begin();
|
||||
var parent = curTx.get(Parent.class, new JObjectKey("Parent")).orElse(null);
|
||||
var parent = curTx.get(Parent.class, new JObjectKey("Parent2")).orElse(null);
|
||||
Assertions.assertNull(parent);
|
||||
txm.commit();
|
||||
}
|
||||
@@ -81,22 +75,20 @@ public class ObjectsTest {
|
||||
void createCreateObject() {
|
||||
{
|
||||
txm.begin();
|
||||
var newParent = alloc.create(Parent.class, new JObjectKey("Parent7"));
|
||||
newParent.setLastName("John");
|
||||
var newParent = new Parent(JObjectKey.of("Parent7"), "John");
|
||||
curTx.put(newParent);
|
||||
txm.commit();
|
||||
}
|
||||
{
|
||||
txm.begin();
|
||||
var newParent = alloc.create(Parent.class, new JObjectKey("Parent7"));
|
||||
newParent.setLastName("John2");
|
||||
var newParent = new Parent(JObjectKey.of("Parent7"), "John2");
|
||||
curTx.put(newParent);
|
||||
txm.commit();
|
||||
}
|
||||
{
|
||||
txm.begin();
|
||||
var parent = curTx.get(Parent.class, new JObjectKey("Parent7")).orElse(null);
|
||||
Assertions.assertEquals("John2", parent.getLastName());
|
||||
Assertions.assertEquals("John2", parent.name());
|
||||
txm.commit();
|
||||
}
|
||||
}
|
||||
@@ -105,8 +97,7 @@ public class ObjectsTest {
|
||||
void editObject() {
|
||||
{
|
||||
txm.begin();
|
||||
var newParent = alloc.create(Parent.class, new JObjectKey("Parent3"));
|
||||
newParent.setLastName("John");
|
||||
var newParent = new Parent(JObjectKey.of("Parent3"), "John");
|
||||
curTx.put(newParent);
|
||||
txm.commit();
|
||||
}
|
||||
@@ -114,23 +105,23 @@ public class ObjectsTest {
|
||||
{
|
||||
txm.begin();
|
||||
var parent = curTx.get(Parent.class, new JObjectKey("Parent3"), LockingStrategy.OPTIMISTIC).orElse(null);
|
||||
Assertions.assertEquals("John", parent.getLastName());
|
||||
parent.setLastName("John2");
|
||||
Assertions.assertEquals("John", parent.name());
|
||||
curTx.put(parent.toBuilder().name("John2").build());
|
||||
txm.commit();
|
||||
}
|
||||
|
||||
{
|
||||
txm.begin();
|
||||
var parent = curTx.get(Parent.class, new JObjectKey("Parent3"), LockingStrategy.WRITE).orElse(null);
|
||||
Assertions.assertEquals("John2", parent.getLastName());
|
||||
parent.setLastName("John3");
|
||||
Assertions.assertEquals("John2", parent.name());
|
||||
curTx.put(parent.toBuilder().name("John3").build());
|
||||
txm.commit();
|
||||
}
|
||||
|
||||
{
|
||||
txm.begin();
|
||||
var parent = curTx.get(Parent.class, new JObjectKey("Parent3")).orElse(null);
|
||||
Assertions.assertEquals("John3", parent.getLastName());
|
||||
Assertions.assertEquals("John3", parent.name());
|
||||
txm.commit();
|
||||
}
|
||||
}
|
||||
@@ -148,8 +139,7 @@ public class ObjectsTest {
|
||||
Log.warn("Thread 1");
|
||||
txm.begin();
|
||||
barrier.await();
|
||||
var newParent = alloc.create(Parent.class, new JObjectKey("Parent2"));
|
||||
newParent.setLastName("John");
|
||||
var newParent = new Parent(JObjectKey.of("Parent2"), "John");
|
||||
curTx.put(newParent);
|
||||
Log.warn("Thread 1 commit");
|
||||
txm.commit();
|
||||
@@ -164,8 +154,7 @@ public class ObjectsTest {
|
||||
Log.warn("Thread 2");
|
||||
txm.begin();
|
||||
barrier.await();
|
||||
var newParent = alloc.create(Parent.class, new JObjectKey("Parent2"));
|
||||
newParent.setLastName("John2");
|
||||
var newParent = new Parent(JObjectKey.of("Parent2"), "John2");
|
||||
curTx.put(newParent);
|
||||
Log.warn("Thread 2 commit");
|
||||
txm.commit();
|
||||
@@ -184,9 +173,9 @@ public class ObjectsTest {
|
||||
|
||||
if (!thread1Failed.get()) {
|
||||
Assertions.assertTrue(thread2Failed.get());
|
||||
Assertions.assertEquals("John", got.getLastName());
|
||||
Assertions.assertEquals("John", got.name());
|
||||
} else if (!thread2Failed.get()) {
|
||||
Assertions.assertEquals("John2", got.getLastName());
|
||||
Assertions.assertEquals("John2", got.name());
|
||||
} else {
|
||||
Assertions.fail("No thread succeeded");
|
||||
}
|
||||
@@ -198,8 +187,7 @@ public class ObjectsTest {
|
||||
String key = "Parent4" + strategy.name();
|
||||
{
|
||||
txm.begin();
|
||||
var newParent = alloc.create(Parent.class, new JObjectKey(key));
|
||||
newParent.setLastName("John3");
|
||||
var newParent = new Parent(JObjectKey.of(key), "John3");
|
||||
curTx.put(newParent);
|
||||
txm.commit();
|
||||
}
|
||||
@@ -216,7 +204,7 @@ public class ObjectsTest {
|
||||
txm.begin();
|
||||
barrier.await();
|
||||
var parent = curTx.get(Parent.class, new JObjectKey(key), strategy).orElse(null);
|
||||
parent.setLastName("John");
|
||||
curTx.put(parent.toBuilder().name("John").build());
|
||||
Log.warn("Thread 1 commit");
|
||||
txm.commit();
|
||||
thread1Failed.set(false);
|
||||
@@ -231,7 +219,7 @@ public class ObjectsTest {
|
||||
txm.begin();
|
||||
barrier.await();
|
||||
var parent = curTx.get(Parent.class, new JObjectKey(key), strategy).orElse(null);
|
||||
parent.setLastName("John2");
|
||||
curTx.put(parent.toBuilder().name("John2").build());
|
||||
Log.warn("Thread 2 commit");
|
||||
txm.commit();
|
||||
thread2Failed.set(false);
|
||||
@@ -249,9 +237,9 @@ public class ObjectsTest {
|
||||
|
||||
if (!thread1Failed.get()) {
|
||||
Assertions.assertTrue(thread2Failed.get());
|
||||
Assertions.assertEquals("John", got.getLastName());
|
||||
Assertions.assertEquals("John", got.name());
|
||||
} else if (!thread2Failed.get()) {
|
||||
Assertions.assertEquals("John2", got.getLastName());
|
||||
Assertions.assertEquals("John2", got.name());
|
||||
} else {
|
||||
Assertions.fail("No thread succeeded");
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.usatiuk.dhfs.objects;
|
||||
|
||||
import com.usatiuk.dhfs.objects.data.Parent;
|
||||
import com.usatiuk.dhfs.objects.transaction.Transaction;
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
@@ -22,9 +21,6 @@ public class PreCommitTxHookTest {
|
||||
@Inject
|
||||
Transaction curTx;
|
||||
|
||||
@Inject
|
||||
ObjectAllocator alloc;
|
||||
|
||||
@ApplicationScoped
|
||||
public static class DummyPreCommitTxHook implements PreCommitTxHook {
|
||||
}
|
||||
@@ -36,8 +32,8 @@ public class PreCommitTxHookTest {
|
||||
void createObject() {
|
||||
{
|
||||
txm.begin();
|
||||
var newParent = alloc.create(Parent.class, new JObjectKey("ParentCreate"));
|
||||
newParent.setLastName("John");
|
||||
var newParent = new Parent(JObjectKey.of("ParentCreate"), "John");
|
||||
curTx.put(newParent);
|
||||
curTx.put(newParent);
|
||||
txm.commit();
|
||||
}
|
||||
@@ -45,14 +41,14 @@ public class PreCommitTxHookTest {
|
||||
{
|
||||
txm.begin();
|
||||
var parent = curTx.get(Parent.class, new JObjectKey("ParentCreate")).orElse(null);
|
||||
Assertions.assertEquals("John", parent.getLastName());
|
||||
Assertions.assertEquals("John", parent.name());
|
||||
txm.commit();
|
||||
}
|
||||
|
||||
ArgumentCaptor<JData> dataCaptor = ArgumentCaptor.forClass(JData.class);
|
||||
ArgumentCaptor<JObjectKey> keyCaptor = ArgumentCaptor.forClass(JObjectKey.class);
|
||||
Mockito.verify(spyHook, Mockito.times(1)).onCreate(keyCaptor.capture(), dataCaptor.capture());
|
||||
Assertions.assertEquals("John", ((Parent) dataCaptor.getValue()).getLastName());
|
||||
Assertions.assertEquals("John", ((Parent) dataCaptor.getValue()).name());
|
||||
Assertions.assertEquals(new JObjectKey("ParentCreate"), keyCaptor.getValue());
|
||||
}
|
||||
|
||||
@@ -60,8 +56,7 @@ public class PreCommitTxHookTest {
|
||||
void deleteObject() {
|
||||
{
|
||||
txm.begin();
|
||||
var newParent = alloc.create(Parent.class, new JObjectKey("ParentDel"));
|
||||
newParent.setLastName("John");
|
||||
var newParent = new Parent(JObjectKey.of("ParentDel"), "John");
|
||||
curTx.put(newParent);
|
||||
txm.commit();
|
||||
}
|
||||
@@ -69,7 +64,7 @@ public class PreCommitTxHookTest {
|
||||
{
|
||||
txm.begin();
|
||||
var parent = curTx.get(Parent.class, new JObjectKey("ParentDel")).orElse(null);
|
||||
Assertions.assertEquals("John", parent.getLastName());
|
||||
Assertions.assertEquals("John", parent.name());
|
||||
txm.commit();
|
||||
}
|
||||
|
||||
@@ -82,7 +77,7 @@ public class PreCommitTxHookTest {
|
||||
ArgumentCaptor<JData> dataCaptor = ArgumentCaptor.forClass(JData.class);
|
||||
ArgumentCaptor<JObjectKey> keyCaptor = ArgumentCaptor.forClass(JObjectKey.class);
|
||||
Mockito.verify(spyHook, Mockito.times(1)).onDelete(keyCaptor.capture(), dataCaptor.capture());
|
||||
Assertions.assertEquals("John", ((Parent) dataCaptor.getValue()).getLastName());
|
||||
Assertions.assertEquals("John", ((Parent) dataCaptor.getValue()).name());
|
||||
Assertions.assertEquals(new JObjectKey("ParentDel"), keyCaptor.getValue());
|
||||
}
|
||||
|
||||
@@ -90,16 +85,14 @@ public class PreCommitTxHookTest {
|
||||
void editObject() {
|
||||
{
|
||||
txm.begin();
|
||||
var newParent = alloc.create(Parent.class, new JObjectKey("ParentEdit"));
|
||||
newParent.setLastName("John");
|
||||
var newParent = new Parent(JObjectKey.of("ParentEdit"), "John");
|
||||
curTx.put(newParent);
|
||||
txm.commit();
|
||||
}
|
||||
|
||||
{
|
||||
txm.begin();
|
||||
var newParent = alloc.create(Parent.class, new JObjectKey("ParentEdit"));
|
||||
newParent.setLastName("John changed");
|
||||
var newParent = new Parent(JObjectKey.of("ParentEdit"), "John changed");
|
||||
curTx.put(newParent);
|
||||
txm.commit();
|
||||
}
|
||||
@@ -108,8 +101,8 @@ public class PreCommitTxHookTest {
|
||||
ArgumentCaptor<JData> dataCaptorNew = ArgumentCaptor.forClass(JData.class);
|
||||
ArgumentCaptor<JObjectKey> keyCaptor = ArgumentCaptor.forClass(JObjectKey.class);
|
||||
Mockito.verify(spyHook, Mockito.times(1)).onChange(keyCaptor.capture(), dataCaptorOld.capture(), dataCaptorNew.capture());
|
||||
Assertions.assertEquals("John", ((Parent) dataCaptorOld.getValue()).getLastName());
|
||||
Assertions.assertEquals("John changed", ((Parent) dataCaptorNew.getValue()).getLastName());
|
||||
Assertions.assertEquals("John", ((Parent) dataCaptorOld.getValue()).name());
|
||||
Assertions.assertEquals("John changed", ((Parent) dataCaptorNew.getValue()).name());
|
||||
Assertions.assertEquals(new JObjectKey("ParentEdit"), keyCaptor.getValue());
|
||||
}
|
||||
|
||||
@@ -117,8 +110,7 @@ public class PreCommitTxHookTest {
|
||||
void editObjectWithGet() {
|
||||
{
|
||||
txm.begin();
|
||||
var newParent = alloc.create(Parent.class, new JObjectKey("ParentEdit2"));
|
||||
newParent.setLastName("John");
|
||||
var newParent = new Parent(JObjectKey.of("ParentEdit2"), "John");
|
||||
curTx.put(newParent);
|
||||
txm.commit();
|
||||
}
|
||||
@@ -126,10 +118,8 @@ public class PreCommitTxHookTest {
|
||||
{
|
||||
txm.begin();
|
||||
var parent = curTx.get(Parent.class, new JObjectKey("ParentEdit2")).orElse(null);
|
||||
Assertions.assertEquals("John", parent.getLastName());
|
||||
var newParent = alloc.create(Parent.class, new JObjectKey("ParentEdit2"));
|
||||
newParent.setLastName("John changed");
|
||||
curTx.put(newParent);
|
||||
Assertions.assertEquals("John", parent.name());
|
||||
curTx.put(parent.toBuilder().name("John changed").build());
|
||||
txm.commit();
|
||||
}
|
||||
|
||||
@@ -137,8 +127,8 @@ public class PreCommitTxHookTest {
|
||||
ArgumentCaptor<JData> dataCaptorNew = ArgumentCaptor.forClass(JData.class);
|
||||
ArgumentCaptor<JObjectKey> keyCaptor = ArgumentCaptor.forClass(JObjectKey.class);
|
||||
Mockito.verify(spyHook, Mockito.times(1)).onChange(keyCaptor.capture(), dataCaptorOld.capture(), dataCaptorNew.capture());
|
||||
Assertions.assertEquals("John", ((Parent) dataCaptorOld.getValue()).getLastName());
|
||||
Assertions.assertEquals("John changed", ((Parent) dataCaptorNew.getValue()).getLastName());
|
||||
Assertions.assertEquals("John", ((Parent) dataCaptorOld.getValue()).name());
|
||||
Assertions.assertEquals("John changed", ((Parent) dataCaptorNew.getValue()).name());
|
||||
Assertions.assertEquals(new JObjectKey("ParentEdit2"), keyCaptor.getValue());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.usatiuk.dhfs.objects.data;
|
||||
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import lombok.Builder;
|
||||
|
||||
public interface Kid extends JData {
|
||||
String getName();
|
||||
|
||||
void setName(String name);
|
||||
}
|
||||
@Builder(toBuilder = true)
|
||||
public record Kid(JObjectKey key, String name) implements JData {
|
||||
}
|
||||
@@ -2,13 +2,8 @@ package com.usatiuk.dhfs.objects.data;
|
||||
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import lombok.Builder;
|
||||
|
||||
public interface Parent extends JData {
|
||||
String getLastName();
|
||||
|
||||
void setLastName(String lastName);
|
||||
|
||||
JObjectKey getKidKey();
|
||||
|
||||
void setKidKey(JObjectKey kid);
|
||||
}
|
||||
@Builder(toBuilder = true)
|
||||
public record Parent(JObjectKey key, String name) implements JData {
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
<module>autoprotomap</module>
|
||||
<module>objects</module>
|
||||
<module>utils</module>
|
||||
<module>objects-alloc</module>
|
||||
<module>objects-common</module>
|
||||
</modules>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user