seemingly working object allocator generator

This commit is contained in:
2024-12-03 23:28:36 +01:00
parent 3370df6d2c
commit c9c5306e82
51 changed files with 733 additions and 469 deletions

View File

@@ -22,10 +22,6 @@
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency>
<groupId>com.usatiuk</groupId>
<artifactId>autoprotomap</artifactId>
@@ -41,11 +37,6 @@
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-grpc</artifactId>

View File

@@ -1,32 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 com.usatiuk.autoprotomap.it;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@Path("/autoprotomap")
@ApplicationScoped
public class AutoprotomapResource {
// add some rest methods here
@GET
public String hello() {
return "Hello autoprotomap";
}
}

View File

@@ -21,6 +21,11 @@
<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>

View File

@@ -1,6 +1,6 @@
package com.usatiuk.objects.alloc.deployment;
import org.jboss.jandex.Type;
import org.jboss.jandex.DotName;
public record JDataFieldInfo(String name, Type type) {
public record JDataFieldInfo(String name, DotName type) {
}

View File

@@ -1,8 +0,0 @@
package com.usatiuk.objects.alloc.deployment;
import org.jboss.jandex.ClassInfo;
import java.util.Map;
public record JDataInfo(ClassInfo klass, Map<String, JDataFieldInfo> fields) {
}

View File

@@ -0,0 +1,16 @@
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;
}
}

View File

@@ -1,25 +1,28 @@
package com.usatiuk.objects.alloc.deployment;
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.objects.common.runtime.JData;
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.Singleton;
import org.apache.commons.lang3.tuple.Pair;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.Type;
import java.util.Collections;
import java.util.List;
import java.util.TreeMap;
import java.util.TreeSet;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.lang.reflect.Modifier.*;
class ObjectsAllocProcessor {
@BuildStep
@@ -36,81 +39,305 @@ class ObjectsAllocProcessor {
}
}
private static final String KEY_NAME = "key";
JDataInfo collectData(JDataIndexBuildItem item) {
var methodNameToInfo = item.jData.methods().stream()
.collect(Collectors.toUnmodifiableMap(MethodInfo::name, x -> x));
var reducableSet = new TreeSet<>(methodNameToInfo.keySet());
var fields = new TreeMap<String, JDataFieldInfo>();
// 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()));
} else {
throw new RuntimeException("Unknown method name: " + name);
}
}
return new JDataInfo(item.jData, Collections.unmodifiableMap(fields));
String propNameToFieldName(String name) {
return name;
}
interface TypeFunction {
void apply(Type type);
String propNameToGetterName(String name) {
return "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
}
void matchClass(BytecodeCreator bytecodeCreator, ResultHandle value, List<Type> types, TypeFunction fn) {
// bytecodeCreator.insta
String propNameToSetterName(String name) {
return "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
}
interface ClassTagFunction {
void apply(ClassInfo type, BytecodeCreator branch);
DotName getDataClassName(ClassInfo jData) {
return DotName.createComponentized(jData.name().packagePrefixName(), jData.name().local() + "Data");
}
// Returns false branch
<T> BytecodeCreator matchClassTag(BytecodeCreator bytecodeCreator, ResultHandle toMatch, List<ClassInfo> types, ClassTagFunction fn) {
if (types.isEmpty()) {
return bytecodeCreator;
}
DotName getCTClassName(ClassInfo jData) {
return DotName.createComponentized(jData.name().packagePrefixName(), jData.name().local() + "CTData");
}
var eq = bytecodeCreator.invokeVirtualMethod(
MethodDescriptor.ofMethod(Object.class, "equals", boolean.class, Object.class),
toMatch,
bytecodeCreator.loadClass(types.getFirst())
);
var cmp = bytecodeCreator.ifTrue(eq);
fn.apply(types.getFirst(), cmp.trueBranch());
return matchClassTag(cmp.falseBranch(), toMatch, types.subList(1, types.size()), fn);
DotName getImmutableClassName(ClassInfo jData) {
return DotName.createComponentized(jData.name().packagePrefixName(), jData.name().local() + "ImmutableData");
}
@BuildStep
void makeJDataThingy(List<JDataIndexBuildItem> jDataItems,
BuildProducer<GeneratedBeanBuildItem> generatedBeans,
BuildProducer<GeneratedClassBuildItem> generatedClasses) {
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 data = jDataItems.stream().map(this::collectData).collect(Collectors.toUnmodifiableMap(JDataInfo::klass, x -> x));
var fieldsMap = item.fields.values().stream().map(jDataFieldInfo -> {
var fc = classCreator.getFieldCreator(propNameToFieldName(jDataFieldInfo.name()), jDataFieldInfo.type().toString());
if (jDataFieldInfo.name().equals(KEY_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(Pair::getLeft, Pair::getRight));
for (var field : fieldsMap.values()) {
if (field.getName().equals(KEY_NAME)) {
try (var constructor = classCreator.getConstructorCreator(JObjectKey.class)) {
constructor.invokeSpecialMethod(MethodDescriptor.ofConstructor(Object.class), constructor.getThis());
constructor.writeInstanceField(field, constructor.getThis(), constructor.getMethodParam(0));
constructor.returnVoid();
}
} else {
try (var setter = classCreator.getMethodCreator(propNameToSetterName(field.getName()), void.class, field.getType())) {
setter.writeInstanceField(field, setter.getThis(), setter.getMethodParam(0));
setter.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, ObjectAllocator.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 = item.fields.values().stream().map(jDataFieldInfo -> {
var fc = classCreator.getFieldCreator(propNameToFieldName(jDataFieldInfo.name()), jDataFieldInfo.type().toString());
if (jDataFieldInfo.name().equals(KEY_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(Pair::getLeft, Pair::getRight));
for (var field : fieldsMap.values()) {
if (!field.getName().equals(KEY_NAME)) {
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())) {
constructor.invokeSpecialMethod(MethodDescriptor.ofConstructor(Object.class), constructor.getThis());
constructor.writeInstanceField(modified.getFieldDescriptor(), constructor.getThis(), constructor.load(false));
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();
}
}
}
}
@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, ObjectAllocator.ChangeTrackingJData.class)
.interfaces(item.klass.name().toString())
.interfaces(Serializable.class)
.classOutput(gizmoAdapter)
.build()) {
var fieldsMap = item.fields.values().stream().map(jDataFieldInfo -> {
var fc = classCreator.getFieldCreator(propNameToFieldName(jDataFieldInfo.name()), jDataFieldInfo.type().toString());
if (jDataFieldInfo.name().equals(KEY_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(Pair::getLeft, Pair::getRight));
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();
}
}
}
}
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())
.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)));
}
// 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);
@@ -124,18 +351,24 @@ class ObjectsAllocProcessor {
classCreator.addAnnotation(Singleton.class);
try (MethodCreator methodCreator = classCreator.getMethodCreator("create", JData.class, Class.class, JObjectKey.class)) {
matchClassTag(methodCreator, methodCreator.getMethodParam(0), classes, (type, branch) -> {
branch.returnValue(branch.newInstance(MethodDescriptor.ofConstructor(type.toString(), JObjectKey.class), branch.getMethodParam(1)));
matchClassTag(methodCreator, methodCreator.getMethodParam(0), classes, (type, branch, value) -> {
branch.returnValue(branch.newInstance(MethodDescriptor.ofConstructor(getDataClassName(type).toString(), JObjectKey.class), branch.getMethodParam(1)));
});
methodCreator.throwException(IllegalArgumentException.class, "Unknown type");
}
try (MethodCreator methodCreator = classCreator.getMethodCreator("copy", ObjectAllocator.ChangeTrackingJData.class, JData.class)) {
methodCreator.returnValue(methodCreator.loadNull());
matchClass(methodCreator, methodCreator.getMethodParam(0), classes, (type, branch, value) -> {
branch.returnValue(branch.newInstance(MethodDescriptor.ofConstructor(getCTClassName(type).toString(), type.name().toString()), value));
});
methodCreator.throwException(IllegalArgumentException.class, "Unknown type");
}
try (MethodCreator methodCreator = classCreator.getMethodCreator("unmodifiable", JData.class, JData.class)) {
methodCreator.returnValue(methodCreator.loadNull());
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");
}
}

View File

@@ -1,5 +1,6 @@
<?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">
<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>
@@ -15,10 +16,6 @@
</properties>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest</artifactId>
</dependency>
<dependency>
<groupId>com.usatiuk</groupId>
<artifactId>objects-alloc</artifactId>
@@ -30,13 +27,18 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
<groupId>com.usatiuk</groupId>
<artifactId>objects-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<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>
@@ -68,7 +70,8 @@
</executions>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
<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>

View File

@@ -1,32 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 com.usatiuk.objects.alloc.it;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@Path("/objects-alloc")
@ApplicationScoped
public class ObjectsAllocResource {
// add some rest methods here
@GET
public String hello() {
return "Hello objects-alloc";
}
}

View File

@@ -1,9 +1,9 @@
package com.usatiuk.objects.alloc.it;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.objects.common.runtime.JData;
import com.usatiuk.objects.common.runtime.JObjectKey;
interface TestJDataAssorted extends JData {
public interface TestJDataAssorted extends JData {
String getLastName();
void setLastName(String lastName);

View File

@@ -1,6 +1,6 @@
package com.usatiuk.objects.alloc.it;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.runtime.JData;
public interface TestJDataEmpty extends JData {
}

View File

@@ -0,0 +1,62 @@
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;
@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);
}
}

View File

@@ -1,21 +0,0 @@
package com.usatiuk.objects.alloc.it;
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
import com.usatiuk.objects.common.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 ObjectsAllocResourceTest {
@Inject
ObjectAllocator objectAllocator;
@Test
void testCreateObject() {
var newObject = objectAllocator.create(TestJDataEmpty.class, new JObjectKey("TestJDataEmptyKey"));
Assertions.assertNotNull(newObject);
Assertions.assertEquals("TestJDataEmptyKey", newObject.getKey().name());
}
}

View File

@@ -17,7 +17,7 @@
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>com.usatiuk.dhfs</groupId>
<groupId>com.usatiuk</groupId>
<artifactId>objects-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

View File

@@ -1,17 +0,0 @@
package com.usatiuk.objects.alloc.runtime;
import com.usatiuk.objects.common.JData;
import java.io.Serializable;
abstract class ChangeTrackerBase<T extends JData> implements ObjectAllocator.ChangeTrackingJData<T>, Serializable {
private transient boolean _modified = false;
public boolean isModified() {
return _modified;
}
protected void onChange() {
_modified = true;
}
}

View File

@@ -1,7 +1,7 @@
package com.usatiuk.objects.alloc.runtime;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.JObjectKey;
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);

View File

@@ -0,0 +1,51 @@
<?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-common-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>objects-common-deployment</artifactId>
<name>DHFS objects common stuff - Deployment</name>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc-deployment</artifactId>
</dependency>
<dependency>
<groupId>com.usatiuk</groupId>
<artifactId>objects-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
<scope>test</scope>
</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>

View File

@@ -0,0 +1,14 @@
package com.usatiuk.objects.common.deployment;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.FeatureBuildItem;
class ObjectsCommonProcessor {
private static final String FEATURE = "objects-common";
@BuildStep
FeatureBuildItem feature() {
return new FeatureBuildItem(FEATURE);
}
}

View File

@@ -0,0 +1,23 @@
package com.usatiuk.objects.common.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.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import io.quarkus.test.QuarkusDevModeTest;
public class ObjectsCommonDevModeTest {
// 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());
}
}

View File

@@ -0,0 +1,23 @@
package com.usatiuk.objects.common.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.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import io.quarkus.test.QuarkusUnitTest;
public class ObjectsCommonTest {
// 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());
}
}

View File

@@ -0,0 +1,93 @@
<?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-common-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>objects-common-integration-tests</artifactId>
<name>DHFS objects common stuff - Integration Tests</name>
<properties>
<skipITs>true</skipITs>
</properties>
<dependencies>
<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>
</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>

View File

@@ -0,0 +1 @@
quarkus.package.jar.decompiler.enabled=true

View File

@@ -1,20 +1,23 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<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>
<artifactId>objects-common</artifactId>
<groupId>com.usatiuk</groupId>
<artifactId>objects-common-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>DHFS objects common stuff - Parent</name>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<modules>
<module>deployment</module>
<module>runtime</module>
<module>integration-tests</module>
</modules>
</project>
</project>

View File

@@ -0,0 +1,59 @@
<?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-common-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>objects-common</artifactId>
<name>DHFS objects common stuff - Runtime</name>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</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>

View File

@@ -1,4 +1,4 @@
package com.usatiuk.objects.common;
package com.usatiuk.objects.common.runtime;
// TODO: This could be maybe moved to a separate module?
// The base class for JObject data

View File

@@ -1,4 +1,4 @@
package com.usatiuk.objects.common;
package com.usatiuk.objects.common.runtime;
import java.io.Serializable;

View File

@@ -0,0 +1,9 @@
name: DHFS objects common stuff
#description: Do something useful.
metadata:
# keywords:
# - objects-common
# guide: ... # To create and publish this guide, see https://github.com/quarkiverse/quarkiverse/wiki#documenting-your-extension
# categories:
# - "miscellaneous"
# status: "preview"

View File

@@ -76,10 +76,15 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.usatiuk.dhfs</groupId>
<groupId>com.usatiuk</groupId>
<artifactId>objects-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.usatiuk</groupId>
<artifactId>objects-common-deployment</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>

View File

@@ -2,8 +2,8 @@ package com.usatiuk.dhfs.objects;
import com.usatiuk.dhfs.objects.transaction.LockingStrategy;
import com.usatiuk.dhfs.objects.transaction.Transaction;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.objects.common.runtime.JData;
import com.usatiuk.objects.common.runtime.JObjectKey;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

View File

@@ -8,8 +8,8 @@ import com.usatiuk.dhfs.objects.transaction.TransactionPrivate;
import com.usatiuk.dhfs.objects.transaction.TxRecord;
import com.usatiuk.dhfs.utils.DataLocker;
import com.usatiuk.dhfs.utils.VoidFn;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.objects.common.runtime.JData;
import com.usatiuk.objects.common.runtime.JObjectKey;
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
import io.quarkus.logging.Log;
import jakarta.enterprise.context.ApplicationScoped;
@@ -24,7 +24,7 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
// Manages all access to com.usatiuk.objects.common.JData objects.
// Manages all access to com.usatiuk.objects.common.runtime.JData objects.
// In particular, it serves as a source of truth for what is committed to the backing storage.
// All data goes through it, it is responsible for transaction atomicity
@ApplicationScoped

View File

@@ -1,16 +1,15 @@
package com.usatiuk.dhfs.objects.serializer;
package com.usatiuk.dhfs.objects;
import com.google.protobuf.ByteString;
import com.usatiuk.dhfs.objects.ObjectSerializer;
import com.usatiuk.dhfs.utils.SerializationHelper;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.runtime.JData;
import jakarta.enterprise.context.ApplicationScoped;
import java.io.Serializable;
@ApplicationScoped
public class TestJDataSerializer implements ObjectSerializer<JData> {
public class JavaDataSerializer implements ObjectSerializer<JData> {
@Override
public ByteString serialize(JData obj) {
return SerializationHelper.serialize((Serializable) obj);

View File

@@ -1,7 +1,7 @@
package com.usatiuk.dhfs.objects;
import com.google.protobuf.ByteString;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.runtime.JData;
public interface ObjectSerializer<T extends JData> {
ByteString serialize(T obj);

View File

@@ -1,6 +1,6 @@
package com.usatiuk.dhfs.objects;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.runtime.JData;
public interface TxBundle {
long getId();

View File

@@ -2,7 +2,7 @@ package com.usatiuk.dhfs.objects.persistence;
import com.google.protobuf.ByteString;
import com.google.protobuf.UnsafeByteOperations;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.objects.common.runtime.JObjectKey;
import com.usatiuk.dhfs.supportlib.UninitializedByteBuffer;
import com.usatiuk.dhfs.utils.ByteUtils;
import com.usatiuk.dhfs.utils.SerializationHelper;

View File

@@ -1,7 +1,7 @@
package com.usatiuk.dhfs.objects.persistence;
import com.google.protobuf.ByteString;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.objects.common.runtime.JObjectKey;
import io.quarkus.arc.properties.IfBuildProperty;
import jakarta.enterprise.context.ApplicationScoped;

View File

@@ -1,7 +1,7 @@
package com.usatiuk.dhfs.objects.persistence;
import com.google.protobuf.ByteString;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.objects.common.runtime.JObjectKey;
import javax.annotation.Nonnull;
import java.util.Collection;

View File

@@ -1,6 +1,6 @@
package com.usatiuk.dhfs.objects.persistence;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.objects.common.runtime.JObjectKey;
import java.io.Serializable;
import java.util.List;

View File

@@ -1,7 +1,7 @@
package com.usatiuk.dhfs.objects.transaction;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.objects.common.runtime.JData;
import com.usatiuk.objects.common.runtime.JObjectKey;
import java.util.Optional;

View File

@@ -1,7 +1,7 @@
package com.usatiuk.dhfs.objects.transaction;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.objects.common.runtime.JData;
import com.usatiuk.objects.common.runtime.JObjectKey;
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

View File

@@ -1,7 +1,7 @@
package com.usatiuk.dhfs.objects.transaction;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.objects.common.runtime.JData;
import com.usatiuk.objects.common.runtime.JObjectKey;
import java.util.Optional;
import java.util.concurrent.locks.ReadWriteLock;

View File

@@ -1,7 +1,7 @@
package com.usatiuk.dhfs.objects.transaction;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.objects.common.runtime.JData;
import com.usatiuk.objects.common.runtime.JObjectKey;
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
public class TxRecord {

View File

@@ -2,8 +2,9 @@ package com.usatiuk.dhfs.objects;
import com.usatiuk.dhfs.objects.data.Parent;
import com.usatiuk.dhfs.objects.transaction.LockingStrategy;
import com.usatiuk.objects.common.JObjectKey;
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;
import jakarta.inject.Inject;
@@ -20,7 +21,7 @@ public class ObjectsTest {
TransactionManager txm;
@Inject
CurrentTransaction curTx;
Transaction curTx;
@Inject
ObjectAllocator alloc;

View File

@@ -1,16 +0,0 @@
package com.usatiuk.dhfs.objects.allocator;
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
import com.usatiuk.objects.common.JData;
import lombok.Getter;
import java.io.Serializable;
public abstract class ChangeTrackerBase<T extends JData> implements ObjectAllocator.ChangeTrackingJData<T>, Serializable {
@Getter
private transient boolean _modified = false;
protected void onChange() {
_modified = true;
}
}

View File

@@ -1,33 +0,0 @@
package com.usatiuk.dhfs.objects.allocator;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.dhfs.objects.data.Kid;
import lombok.Getter;
public class KidDataCT extends ChangeTrackerBase<Kid> implements Kid {
private final JObjectKey _key;
@Getter
private String _name;
@Override
public void setName(String name) {
_name = name;
onChange();
}
public KidDataCT(Kid normal) {
_key = normal.getKey();
_name = normal.getName();
}
@Override
public JObjectKey getKey() {
return _key;
}
@Override
public Kid wrapped() {
return this;
}
}

View File

@@ -1,23 +0,0 @@
package com.usatiuk.dhfs.objects.allocator;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.dhfs.objects.data.Kid;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
public class KidDataNormal implements Kid, Serializable {
private final JObjectKey _key;
@Getter
@Setter
private String _name;
public KidDataNormal(JObjectKey key) {_key = key;}
@Override
public JObjectKey getKey() {
return _key;
}
}

View File

@@ -1,40 +0,0 @@
package com.usatiuk.dhfs.objects.allocator;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.dhfs.objects.data.Parent;
import lombok.Getter;
public class ParentDataCT extends ChangeTrackerBase<Parent> implements Parent {
@Getter
private JObjectKey _name;
@Getter
private JObjectKey _kidKey;
@Getter
private String _lastName;
public void setKidKey(JObjectKey key) {
_kidKey = key;
onChange();
}
public void setLastName(String lastName) {
_lastName = lastName;
onChange();
}
public ParentDataCT(Parent normal) {
_name = normal.getKey();
_kidKey = normal.getKidKey();
_lastName = normal.getLastName();
}
@Override
public JObjectKey getKey() {
return _name;
}
@Override
public Parent wrapped() {
return this;
}
}

View File

@@ -1,29 +0,0 @@
package com.usatiuk.dhfs.objects.allocator;
import com.usatiuk.dhfs.objects.data.Parent;
import com.usatiuk.objects.common.JObjectKey;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
public class ParentDataNormal implements Parent, Serializable {
@Getter
private JObjectKey _name;
@Getter
@Setter
private JObjectKey _kidKey;
@Getter
@Setter
private String _lastName;
public ParentDataNormal(JObjectKey name) {
_name = name;
}
@Override
public JObjectKey getKey() {
return _name;
}
}

View File

@@ -1,34 +0,0 @@
package com.usatiuk.dhfs.objects.allocator;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.JObjectKey;
public abstract class TestData implements JData {
private boolean _changed = false;
private final long _version;
private final JObjectKey _key;
protected TestData(long version, JObjectKey key) {
_version = version;
_key = key;
}
void onChanged() {
_changed = true;
}
public boolean isChanged() {
return _changed;
}
public long getVersion() {
return _version;
}
@Override
public JObjectKey getKey() {
return _key;
}
public abstract TestData copy();
}

View File

@@ -1,40 +0,0 @@
package com.usatiuk.dhfs.objects.allocator;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
import com.usatiuk.dhfs.objects.data.Kid;
import com.usatiuk.dhfs.objects.data.Parent;
import com.usatiuk.objects.common.JObjectKey;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class TestObjectAllocator implements ObjectAllocator {
@Override
public <T extends JData> T create(Class<T> type, JObjectKey key) {
if (type == Kid.class) {
return type.cast(new KidDataNormal(key));
} else if (type == Parent.class) {
return type.cast(new ParentDataNormal(key));
} else {
throw new IllegalArgumentException("Unknown type: " + type);
}
}
@Override
public <T extends JData> ChangeTrackingJData<T> copy(T obj) {
// if (obj instanceof ChangeTrackerBase<?>) {
// throw new IllegalArgumentException("Cannot copy a ChangeTrackerBase object");
// }
return switch (obj) {
case Kid kid -> (ChangeTrackingJData<T>) new KidDataCT(kid);
case Parent parent -> (ChangeTrackingJData<T>) new ParentDataCT(parent);
default -> throw new IllegalStateException("Unexpected value: " + obj);
};
}
@Override
public <T extends JData> T unmodifiable(T obj) {
return obj; // TODO:
}
}

View File

@@ -1,6 +1,6 @@
package com.usatiuk.dhfs.objects.data;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.runtime.JData;
public interface Kid extends JData {
String getName();

View File

@@ -1,11 +1,9 @@
package com.usatiuk.dhfs.objects.data;
import com.usatiuk.objects.common.JData;
import com.usatiuk.objects.common.JObjectKey;
import com.usatiuk.objects.common.runtime.JData;
import com.usatiuk.objects.common.runtime.JObjectKey;
public interface Parent extends JData {
JObjectKey getName();
String getLastName();
void setLastName(String lastName);