Compare commits

...

18 Commits

Author SHA1 Message Date
ab7259f726 [RELEASE] create version v0.13.0 2024-06-25 15:47:53 +02:00
cdb4581799 [FEAT] add link of List<UUID> that is decorate with @ManyToOne, or @ManyToMany or @OneToMany 2024-06-20 00:10:22 +02:00
7e81bfef28 [FEAT] add generation of dot files 2024-06-20 00:10:22 +02:00
84525fd7aa [FIX] cover tools 2024-06-13 08:27:33 +02:00
d4eb9c2a5f [FIX] correct the ID in uuid for uuid primary-key 2024-06-12 20:08:26 +02:00
15688f93e5 [FIX] version number 2024-06-12 00:55:51 +02:00
906216f237 [FIX] throw when uploading data 2024-06-12 00:54:42 +02:00
b479414bc2 [FIX] callbacks elements 2024-06-12 00:54:22 +02:00
2bc68321e3 [DEV] develoopment version 2024-06-12 00:53:29 +02:00
d77a5518ff [RELEASE] create version v0.12.1 2024-06-11 23:59:59 +02:00
5f9d13d315 [FEAT] remove in upload cover the filename 2024-06-11 23:48:43 +02:00
Yoann Fleury
0b57d8571c fix: plural for callbacks 2024-06-11 12:41:31 +02:00
483c41914a [RELEASE] create version v0.12.0 2024-06-10 22:26:57 +02:00
a1f56050bf [FEAT] support the min and Max for number and string 2024-06-08 13:48:34 +02:00
a41e837f21 [FIX] import "Write" when no write availlable. 2024-06-08 11:55:51 +02:00
5496855698 [FEAT] add a remove warning 2024-06-08 11:43:29 +02:00
c9cb0d043a [API] remove @SQLWhere 2024-06-08 11:43:00 +02:00
09cfcfc578 [FEAT] generate a full Zod object for write mode.
- Add @NoWriteSpecificMode to permit to remove specific object write model
  - refactor Zod Write model
  - Add .nullable() in write Optional element

Residual bug element use in APi that is mark as no write
2024-06-08 11:42:38 +02:00
24 changed files with 1542 additions and 175 deletions

View File

@@ -25,7 +25,7 @@
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21">
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>

View File

@@ -11,12 +11,12 @@
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<name>edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder</name>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>

View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.11.0</version>
<version>0.13.0</version>
<properties>
<java.version>21</java.version>
<maven.compiler.version>3.1</maven.compiler.version>

View File

@@ -17,7 +17,9 @@ import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
@@ -80,6 +82,14 @@ public class AnnotationTools {
return ((Schema) annotation[0]).example();
}
public static boolean getNoWriteSpecificMode(final Class<?> element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(NoWriteSpecificMode.class);
if (annotation.length == 0) {
return false;
}
return true;
}
public static String getSchemaDescription(final Class<?> element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
@@ -128,18 +138,30 @@ public class AnnotationTools {
return ((DefaultValue) annotation[0]).value();
}
public static ManyToOne getManyToOne(final Field element) throws DataAccessException {
public static ManyToOne getManyToOne(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(ManyToOne.class);
if (annotation.length == 0) {
return null;
}
if (annotation.length > 1) {
throw new DataAccessException(
"Must not have more than 1 element @ManyToOne on " + element.getClass().getCanonicalName());
}
return (ManyToOne) annotation[0];
}
public static ManyToMany getManyToMany(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(ManyToMany.class);
if (annotation.length == 0) {
return null;
}
return (ManyToMany) annotation[0];
}
public static OneToMany getOneToMany(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(OneToMany.class);
if (annotation.length == 0) {
return null;
}
return (OneToMany) annotation[0];
}
public static DataJson getDataJson(final Field element) throws DataAccessException {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DataJson.class);
if (annotation.length == 0) {

View File

@@ -5,8 +5,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** When we wend to have only One type for read and write mode (Wrapping API). */
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLWhere {
String clause();
public @interface NoWriteSpecificMode {
}

View File

@@ -3,12 +3,14 @@ package org.kar.archidata.catcher;
import java.time.Instant;
import java.util.UUID;
import org.kar.archidata.annotation.NoWriteSpecificMode;
import org.kar.archidata.tools.UuidUtils;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.core.Response;
@NoWriteSpecificMode
public class RestErrorResponse {
public UUID uuid = UuidUtils.nextUUID();
@NotNull

View File

@@ -188,9 +188,21 @@ public class AddOnDataJson implements DataAccessAddOn {
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
/**
* Adds a remoteKey to the covers list of a data entry identified by the given class type and ID.
* If the covers list is null, it initializes it. If the remoteKey already exists in the list,
* the method returns without making any changes.
*
* @param clazz The class type to retrieve the table name from.
* @param id The ID of the data object to fetch.
* @param column The name of the column (currently not used, but may be used for specifying a field name).
* @param remoteKey The UUID to add to the covers list.
* @throws Exception If an error occurs during data retrieval or update.
*/
public static void addLink(final Class<?> clazz, final Long id, final String column, final UUID remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
// TODO: Get primary key name
final TableCoversLongUUID data = DataAccess.get(TableCoversLongUUID.class, id,
new OverrideTableName(tableName));
if (data.covers == null) {
@@ -205,10 +217,21 @@ public class AddOnDataJson implements DataAccessAddOn {
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));// TODO: ,new OverrideFieldName("covers", column));
}
public static void addLink(final Class<?> clazz, final UUID id, final String column, final UUID remoteKey)
/**
* Adds a remoteKey to the covers list of a data entry identified by the given class type and ID.
* If the covers list is null, it initializes it. If the remoteKey already exists in the list,
* the method returns without making any changes.
*
* @param clazz The class type to retrieve the table name from.
* @param id The ID of the data object to fetch.
* @param column The name of the column (currently not used, but may be used for specifying a field name).
* @param remoteKey The UUID to add to the covers list.
* @throws Exception If an error occurs during data retrieval or update.
*/
public static void addLink(final Class<?> clazz, final UUID uuid, final String column, final UUID remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDUUID data = DataAccess.get(TableCoversUUIDUUID.class, id,
final TableCoversUUIDUUID data = DataAccess.get(TableCoversUUIDUUID.class, uuid,
new OverrideTableName(tableName));
if (data.covers == null) {
data.covers = new ArrayList<>();
@@ -219,13 +242,13 @@ public class AddOnDataJson implements DataAccessAddOn {
}
}
data.covers.add(remoteKey);
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
DataAccess.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName));
}
public static void addLink(final Class<?> clazz, final UUID id, final String column, final Long remoteKey)
public static void addLink(final Class<?> clazz, final UUID uuid, final String column, final Long remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDLong data = DataAccess.get(TableCoversUUIDLong.class, id,
final TableCoversUUIDLong data = DataAccess.get(TableCoversUUIDLong.class, uuid,
new OverrideTableName(tableName));
if (data.covers == null) {
data.covers = new ArrayList<>();
@@ -236,13 +259,13 @@ public class AddOnDataJson implements DataAccessAddOn {
}
}
data.covers.add(remoteKey);
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
DataAccess.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final UUID id, final String column, final Long remoteKey)
public static void removeLink(final Class<?> clazz, final UUID uuid, final String column, final Long remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDLong data = DataAccess.get(TableCoversUUIDLong.class, id,
final TableCoversUUIDLong data = DataAccess.get(TableCoversUUIDLong.class, uuid,
new OverrideTableName(tableName));
if (data.covers == null) {
return;
@@ -255,13 +278,13 @@ public class AddOnDataJson implements DataAccessAddOn {
newList.add(elem);
}
data.covers = newList;
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
DataAccess.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final UUID id, final String column, final UUID remoteKey)
public static void removeLink(final Class<?> clazz, final UUID uuid, final String column, final UUID remoteKey)
throws Exception {
final String tableName = AnnotationTools.getTableName(clazz);
final TableCoversUUIDUUID data = DataAccess.get(TableCoversUUIDUUID.class, id,
final TableCoversUUIDUUID data = DataAccess.get(TableCoversUUIDUUID.class, uuid,
new OverrideTableName(tableName));
if (data.covers == null) {
return;
@@ -274,7 +297,7 @@ public class AddOnDataJson implements DataAccessAddOn {
newList.add(elem);
}
data.covers = newList;
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
DataAccess.update(data, data.uuid, List.of("covers"), new OverrideTableName(tableName));
}
public static void removeLink(final Class<?> clazz, final Long id, final String column, final Long remoteKey)
@@ -314,9 +337,4 @@ public class AddOnDataJson implements DataAccessAddOn {
data.covers = newList;
DataAccess.update(data, data.id, List.of("covers"), new OverrideTableName(tableName));
}
/* public static <TYPE> void addLink(final Class<TYPE> clazz, final Object localKey, final String column, final Object remoteKey) throws Exception { final String tableName =
* AnnotationTools.getTableName(clazz); final TYPE data = DataAccess.get(clazz, localKey); // TODO: add filter of the "column" // find the field column: // add the remoteKey in the list: // post
* new data in the DB final String linkTableName = generateLinkTableName(this.tableName, this.column); final LinkTable insertElement = new LinkTable(this.localKey, this.remoteKey);
* DataAccess.insert(insertElement, new OverrideTableName(linkTableName)); } */
}

View File

@@ -3,11 +3,10 @@ package org.kar.archidata.dataAccess.addOn.model;
import java.util.List;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.model.GenericDataSoftDelete;
import jakarta.persistence.Column;
import jakarta.persistence.Id;
public class TableCoversLongLong extends GenericDataSoftDelete {
public class TableCoversLongLong {
public TableCoversLongLong() {
// nothing to do...
}
@@ -17,8 +16,10 @@ public class TableCoversLongLong extends GenericDataSoftDelete {
this.covers = covers;
}
@Id
public Long id;
@DataJson()
@Column(nullable = false)
public List<Long> covers;
}

View File

@@ -4,11 +4,10 @@ import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.model.GenericDataSoftDelete;
import jakarta.persistence.Column;
import jakarta.persistence.Id;
public class TableCoversLongUUID extends GenericDataSoftDelete {
public class TableCoversLongUUID {
public TableCoversLongUUID() {
// nothing to do...
}
@@ -18,8 +17,10 @@ public class TableCoversLongUUID extends GenericDataSoftDelete {
this.covers = covers;
}
@Id
public Long id;
@DataJson()
@Column(nullable = false)
public List<UUID> covers;
}

View File

@@ -4,26 +4,22 @@ import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.model.GenericDataSoftDelete;
import jakarta.persistence.Column;
import jakarta.persistence.Id;
public class TableCoversUUIDLong extends GenericDataSoftDelete {
public class TableCoversUUIDLong {
public TableCoversUUIDLong() {
// nothing to do...
}
public TableCoversUUIDLong(final UUID id, final List<Long> covers) {
this.id = id;
public TableCoversUUIDLong(final UUID uuid, final List<Long> covers) {
this.uuid = uuid;
this.covers = covers;
}
@Column(nullable = false)
@Id
public UUID id;
public UUID uuid;
@DataJson()
@Column(nullable = false)
public List<Long> covers;
}

View File

@@ -4,26 +4,22 @@ import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.model.GenericDataSoftDelete;
import jakarta.persistence.Column;
import jakarta.persistence.Id;
public class TableCoversUUIDUUID extends GenericDataSoftDelete {
public class TableCoversUUIDUUID {
public TableCoversUUIDUUID() {
// nothing to do...
}
public TableCoversUUIDUUID(final UUID id, final List<UUID> covers) {
this.id = id;
public TableCoversUUIDUUID(final UUID uuid, final List<UUID> covers) {
this.uuid = uuid;
this.covers = covers;
}
@Column(nullable = false)
@Id
public UUID id;
public UUID uuid;
@DataJson()
@Column(nullable = false)
public List<UUID> covers;
}

View File

@@ -0,0 +1,232 @@
package org.kar.archidata.externalRestApi;
import java.io.FileWriter;
import java.io.InputStream;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.glassfish.jersey.media.multipart.ContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.kar.archidata.catcher.RestErrorResponse;
import org.kar.archidata.externalRestApi.dot.DotApiGeneration;
import org.kar.archidata.externalRestApi.dot.DotClassElement;
import org.kar.archidata.externalRestApi.dot.DotClassElement.DefinedPosition;
import org.kar.archidata.externalRestApi.dot.DotClassElementGroup;
import org.kar.archidata.externalRestApi.model.ApiGroupModel;
import org.kar.archidata.externalRestApi.model.ClassModel;
public class DotGenerateApi {
public static void generateApi(final AnalyzeApi api, final String pathDotFile) throws Exception {
final List<DotClassElement> localModel = generateApiModel(api);
final DotClassElementGroup dotGroup = new DotClassElementGroup(localModel);
try (final FileWriter myWriter = new FileWriter(pathDotFile)) {
myWriter.write("""
# Architecture auto-generated file
digraph UML_Class_diagram {
#rankdir=NS;
graph [
pad="0.5"
nodesep="1"
#ranksep="2"
label="Rest API server Model"
labelloc="t"
fontname="FreeMono,Sans-Mono,Helvetica,Arial,sans-serif"
]
node [
fontname="FreeMono,Sans-Mono,Helvetica,Arial,sans-serif"
shape=record
style=filled
fillcolor=gray95
]
edge [fontname="FreeMono,Sans-Mono,Helvetica,Arial,sans-serif"]
""");
/*
myWriter.write("""
subgraph REST_API {
style=filled;
color=lightgrey;
label="REST API";
rankdir=LR;
""");
*/
for (final ApiGroupModel element : api.apiModels) {
final String tmp = DotApiGeneration.generateApiFile(element, dotGroup);
myWriter.write(tmp);
myWriter.write("\n");
}
// create an invisible link to force all element to be link together:
if (false) {
String previous = null;
for (final ApiGroupModel element : api.apiModels) {
if (previous == null) {
previous = element.name;
continue;
}
myWriter.write("\t{ ");
myWriter.write(previous);
myWriter.write(":s -> ");
previous = element.name;
myWriter.write(previous);
myWriter.write(":n [style=invis]}\n");
}
}
/*
myWriter.write("""
}
""");
myWriter.write("""
subgraph Models {
style=filled;
color=lightgrey;
label="Models";
rankdir=NS;
""");
*/
// Generates all MODEL files
for (final DotClassElement element : localModel) {
final String tmp = element.generateFile(dotGroup);
myWriter.write(tmp);
myWriter.write("\n");
}
/*
myWriter.write("""
}
""");
*/
myWriter.write("""
}
""");
}
}
private static List<DotClassElement> generateApiModel(final AnalyzeApi api) throws Exception {
// First step is to add all specific basic elements the wrap correctly the model
final List<DotClassElement> dotModels = new ArrayList<>();
List<ClassModel> models = api.getCompatibleModels(List.of(Void.class, void.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "void", "void", null, null, DefinedPosition.NATIVE));
}
models = api.getCompatibleModels(List.of(Object.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Object", "object", null, "Object", DefinedPosition.NATIVE));
}
// Map is binded to any ==> can not determine this complex model for now
models = api.getCompatibleModels(List.of(Map.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Object", "any", null, null, DefinedPosition.NATIVE));
}
models = api.getCompatibleModels(List.of(String.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "String", "string", null, "String", DefinedPosition.NATIVE));
}
models = api.getCompatibleModels(
List.of(InputStream.class, FormDataContentDisposition.class, ContentDisposition.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "File", "File", null, "File", DefinedPosition.NATIVE));
}
models = api.getCompatibleModels(List.of(Boolean.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Boolean", "boolean", null, "Boolean", DefinedPosition.NATIVE));
}
models = api.getCompatibleModels(List.of(boolean.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "boolean", "boolean", null, "boolean", DefinedPosition.NATIVE));
}
models = api.getCompatibleModels(List.of(UUID.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "UUID", "UUID", "isUUID", "UUID", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(long.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "long", "Long", "isLong", "long", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Long.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Long", "Long", "isLong", "Long", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(short.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "short", "Short", "isShort", "short", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Short.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Short", "Short", "isShort", "Short", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(int.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "int", "Integer", "isInteger", "int", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Integer.class));
if (models != null) {
dotModels.add(
new DotClassElement(models, "Integer", "Integer", "isInteger", "Integer", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(double.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Double", "Double", "isDouble", "double", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Double.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Double", "Double", "isDouble", "Double", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(float.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "float", "Float", "isFloat", "float", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Float.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Float", "Float", "isFloat", "Float", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Instant.class));
if (models != null) {
dotModels.add(
new DotClassElement(models, "Instant", "Instant", "isInstant", "Instant", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Date.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Date", "IsoDate", "isIsoDate", "Date", DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(Timestamp.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "Timestamp", "Timestamp", "isTimestamp", "Timestamp",
DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(LocalDate.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "LocalDate", "LocalDate", "isLocalDate", "LocalDate",
DefinedPosition.BASIC));
}
models = api.getCompatibleModels(List.of(LocalTime.class));
if (models != null) {
dotModels.add(new DotClassElement(models, "LocalTime", "LocalTime", "isLocalTime", "LocalTime",
DefinedPosition.BASIC));
}
// needed for Rest interface
api.addModel(RestErrorResponse.class);
for (final ClassModel model : api.getAllModel()) {
boolean alreadyExist = false;
for (final DotClassElement elem : dotModels) {
if (elem.isCompatible(model)) {
alreadyExist = true;
break;
}
}
if (alreadyExist) {
continue;
}
dotModels.add(new DotClassElement(model));
}
return dotModels;
}
}

View File

@@ -0,0 +1,414 @@
package org.kar.archidata.externalRestApi.dot;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import org.kar.archidata.externalRestApi.dot.DotClassElement.DefinedPosition;
import org.kar.archidata.externalRestApi.model.ApiGroupModel;
import org.kar.archidata.externalRestApi.model.ApiModel;
import org.kar.archidata.externalRestApi.model.ClassEnumModel;
import org.kar.archidata.externalRestApi.model.ClassListModel;
import org.kar.archidata.externalRestApi.model.ClassMapModel;
import org.kar.archidata.externalRestApi.model.ClassModel;
import org.kar.archidata.externalRestApi.model.ClassObjectModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DotApiGeneration {
static final Logger LOGGER = LoggerFactory.getLogger(DotApiGeneration.class);
public static String generateClassEnumModelTypescript(
final ClassEnumModel model,
final DotClassElementGroup dotGroup,
final Set<ClassModel> imports) throws IOException {
imports.add(model);
final DotClassElement dotModel = dotGroup.find(model);
return dotModel.dotTypeName;
}
public static String generateClassObjectModelTypescript(
final ClassObjectModel model,
final DotClassElementGroup dotGroup,
final Set<ClassModel> imports) throws IOException {
final DotClassElement dotModel = dotGroup.find(model);
if (dotModel.nativeType != DefinedPosition.NATIVE) {
imports.add(model);
}
if (dotModel.nativeType != DefinedPosition.NORMAL) {
return dotModel.dotTypeName;
}
return dotModel.dotTypeName;
}
public static String generateClassMapModelTypescript(
final ClassMapModel model,
final DotClassElementGroup dotGroup,
final Set<ClassModel> imports) throws IOException {
final StringBuilder out = new StringBuilder();
out.append("Map&lt;");
out.append(generateClassModelTypescript(model.keyModel, dotGroup, imports));
out.append(", ");
out.append(generateClassModelTypescript(model.valueModel, dotGroup, imports));
out.append("&gt;");
return out.toString();
}
public static String generateClassListModelTypescript(
final ClassListModel model,
final DotClassElementGroup dotGroup,
final Set<ClassModel> imports) throws IOException {
final StringBuilder out = new StringBuilder();
out.append("List&lt;");
out.append(generateClassModelTypescript(model.valueModel, dotGroup, imports));
out.append("&gt;");
return out.toString();
}
public static String generateClassModelTypescript(
final ClassModel model,
final DotClassElementGroup dotGroup,
final Set<ClassModel> imports) throws IOException {
if (model instanceof final ClassObjectModel objectModel) {
return generateClassObjectModelTypescript(objectModel, dotGroup, imports);
}
if (model instanceof final ClassListModel listModel) {
return generateClassListModelTypescript(listModel, dotGroup, imports);
}
if (model instanceof final ClassMapModel mapModel) {
return generateClassMapModelTypescript(mapModel, dotGroup, imports);
}
if (model instanceof final ClassEnumModel enumModel) {
return generateClassEnumModelTypescript(enumModel, dotGroup, imports);
}
throw new IOException("Impossible model:" + model);
}
public static String generateClassModelsTypescript(
final List<ClassModel> models,
final DotClassElementGroup dotGroup) throws IOException {
if (models.size() == 0) {
return "void";
}
final StringBuilder out = new StringBuilder();
if (models.size() > 1) {
out.append("Union&lt;");
}
boolean isFirst = true;
for (final ClassModel model : models) {
if (isFirst) {
isFirst = false;
} else {
out.append(", ");
}
final String data = DotClassElement.generateClassModelTypescript(model, dotGroup);
out.append(data);
}
if (models.size() > 1) {
out.append("&gt;");
}
return out.toString();
}
public static List<String> generateClassModelsLinks(
final List<ClassModel> models,
final DotClassElementGroup dotGroup) throws IOException {
if (models.size() == 0) {
return null;
}
final List<String> out = new ArrayList<>();
final boolean isFirst = true;
for (final ClassModel model : models) {
final String data = DotClassElement.generateClassModelTypescriptLink(model, dotGroup);
if (data != null) {
out.add(data);
}
}
return out;
}
public static String capitalizeFirstLetter(final String str) {
if (str == null || str.isEmpty()) {
return str;
}
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
public static String generateApiFile(final ApiGroupModel element, final DotClassElementGroup dotGroup)
throws IOException {
final StringBuilder data = new StringBuilder();
final StringBuilder outLinks = new StringBuilder();
data.append("""
%s [
shape=plain
label=<<table color="#FF3333" border="2" cellborder="1" cellspacing="0" cellpadding="4">
<tr>
<td><b>%s</b><br/>(REST)</td>
</tr>
<tr>
<td>
<table border="0" cellborder="0" cellspacing="0" >
""".formatted(element.name, element.name));
final Set<ClassModel> imports = new HashSet<>();
final Set<ClassModel> zodImports = new HashSet<>();
final Set<ClassModel> isImports = new HashSet<>();
final Set<ClassModel> writeImports = new HashSet<>();
final Set<String> toolImports = new HashSet<>();
for (final ApiModel interfaceElement : element.interfaces) {
final List<String> consumes = interfaceElement.consumes;
final List<String> produces = interfaceElement.produces;
final boolean needGenerateProgress = interfaceElement.needGenerateProgress;
/*
if (returnComplexModel != null) {
data.append(returnComplexModel.replaceAll("(?m)^", "\t"));
for (final ClassModel elem : interfaceElement.returnTypes) {
zodImports.addAll(elem.getDependencyGroupModels());
}
}
*/
data.append("\t\t\t\t\t<tr><td align=\"left\" port=\"");
data.append(interfaceElement.name);
data.append("\"><b> + ");
data.append(interfaceElement.name);
data.append("(");
boolean hasParam = false;
/*
if (!interfaceElement.queries.isEmpty()) {
data.append("\n\t\tqueries: {");
for (final Entry<String, List<ClassModel>> queryEntry : interfaceElement.queries.entrySet()) {
data.append("\n\t\t\t");
data.append(queryEntry.getKey());
data.append("?: ");
data.append(generateClassModelsTypescript(queryEntry.getValue(), dotGroup, imports, false));
data.append(",");
}
data.append("\n\t\t},");
}
*/
/* fonctionnel mais trop de donnée
if (!interfaceElement.parameters.isEmpty()) {
//data.append("params: {");
for (final Entry<String, List<ClassModel>> paramEntry : interfaceElement.parameters.entrySet()) {
data.append("");
data.append(paramEntry.getKey());
data.append(": ");
data.append(generateClassModelsTypescript(paramEntry.getValue(), dotGroup, imports, false));
data.append(",");
}
//data.append("},");
}
*/
if (interfaceElement.unnamedElement.size() == 1) {
if (hasParam) {
data.append(", ");
}
hasParam = true;
data.append("data: ");
data.append(
generateClassModelTypescript(interfaceElement.unnamedElement.get(0), dotGroup, writeImports));
} else if (interfaceElement.multiPartParameters.size() != 0) {
if (hasParam) {
data.append(", ");
}
hasParam = true;
boolean hasParam2 = false;
data.append("data: {");
for (final Entry<String, List<ClassModel>> pathEntry : interfaceElement.multiPartParameters
.entrySet()) {
if (hasParam2) {
data.append(", ");
}
hasParam2 = true;
data.append(pathEntry.getKey());
data.append(": ");
data.append(generateClassModelsTypescript(pathEntry.getValue(), dotGroup));
}
data.append("}");
}
data.append("): ");
/*
String tmp = DotClassElement.generateLocalModel(
final String ModelName,
final List<ClassModel> models,
final DotClassElementGroup dotGroup)
public static String generateClassModelsTypescript(
final List<ClassModel> models,
final DotClassElementGroup dotGroup,
final Set<ClassModel> imports) throws IOException {
*/
final String returnType = generateClassModelsTypescript(interfaceElement.returnTypes, dotGroup);
data.append(returnType);
final List<String> returnLinks = generateClassModelsLinks(interfaceElement.returnTypes, dotGroup);
for (final String link : returnLinks) {
outLinks.append("\t");
outLinks.append(element.name);
outLinks.append(":");
outLinks.append(interfaceElement.name);
outLinks.append(":e -> ");
outLinks.append(link);
outLinks.append(":NAME:w\n");
}
data.append("</b>");
//data.append("<br align=\"left\"/>&nbsp;&nbsp;&nbsp;&nbsp;");
data.append("</td></tr>\n\t\t\t\t\t\t\t<tr><td align=\"left\"> ");
/*
data.append("\n\t\t\trestModel: {");
data.append("\n\t\t\t\tendPoint: \"");
*/
data.append(interfaceElement.restEndPoint);
/*
data.append("\",");
data.append("\n\t\t\t\trequestType: HTTPRequestModel.");
toolImports.add("HTTPRequestModel");
data.append(interfaceElement.restTypeRequest);
data.append(",");
if (consumes != null) {
for (final String elem : consumes) {
if (MediaType.APPLICATION_JSON.equals(elem)) {
data.append("\n\t\t\t\tcontentType: HTTPMimeType.JSON,");
toolImports.add("HTTPMimeType");
break;
} else if (MediaType.MULTIPART_FORM_DATA.equals(elem)) {
data.append("\n\t\t\t\tcontentType: HTTPMimeType.MULTIPART,");
toolImports.add("HTTPMimeType");
break;
} else if (MediaType.TEXT_PLAIN.equals(elem)) {
data.append("\n\t\t\t\tcontentType: HTTPMimeType.TEXT_PLAIN,");
toolImports.add("HTTPMimeType");
break;
}
}
} else if (RestTypeRequest.DELETE.equals(interfaceElement.restTypeRequest)) {
data.append("\n\t\t\t\tcontentType: HTTPMimeType.TEXT_PLAIN,");
toolImports.add("HTTPMimeType");
}
if (produces != null) {
if (produces.size() > 1) {
data.append("\n\t\t\t\taccept: produce,");
} else {
final String returnType = generateClassModelsTypescript(interfaceElement.returnTypes, dotGroup,
imports, false);
if (!"void".equals(returnType)) {
for (final String elem : produces) {
if (MediaType.APPLICATION_JSON.equals(elem)) {
data.append("\n\t\t\t\taccept: HTTPMimeType.JSON,");
toolImports.add("HTTPMimeType");
break;
}
}
}
}
}
data.append("\n\t\t\t},");
data.append("\n\t\t\trestConfig,");
if (!interfaceElement.parameters.isEmpty()) {
data.append("\n\t\t\tparams,");
}
if (!interfaceElement.queries.isEmpty()) {
data.append("\n\t\t\tqueries,");
}
if (interfaceElement.unnamedElement.size() == 1) {
data.append("\n\t\t\tdata,");
} else if (interfaceElement.multiPartParameters.size() != 0) {
data.append("\n\t\t\tdata,");
}
if (needGenerateProgress) {
data.append("\n\t\t\tcallback,");
}
data.append("\n\t\t}");
if (returnComplexModel != null) {
data.append(", is");
data.append(returnModelNameIfComplex);
} else {
final DotClassElement retType = dotGroup.find(interfaceElement.returnTypes.get(0));
if (retType.dotCheckType != null) {
data.append(", ");
data.append(retType.dotCheckType);
imports.add(interfaceElement.returnTypes.get(0));
}
}
*/
data.append("</td></tr>\n");
}
/*
data.append("\n}\n");
final StringBuilder out = new StringBuilder();
final List<String> toolImportsList = new ArrayList<>(toolImports);
Collections.sort(toolImportsList);
if (toolImportsList.size() != 0) {
out.append("import {");
for (final String elem : toolImportsList) {
out.append("\n\t");
out.append(elem);
out.append(",");
}
out.append("\n} from \"../rest-tools\";\n\n");
}
if (zodImports.size() != 0) {
out.append("import { z as zod } from \"zod\"\n");
}
final Set<String> finalImportSet = new TreeSet<>();
for (final ClassModel model : imports) {
final DotClassElement dotModel = dotGroup.find(model);
if (dotModel.nativeType == DefinedPosition.NATIVE) {
continue;
}
finalImportSet.add(dotModel.dotTypeName);
}
for (final ClassModel model : isImports) {
final DotClassElement dotModel = dotGroup.find(model);
if (dotModel.nativeType == DefinedPosition.NATIVE) {
continue;
}
if (dotModel.dotCheckType != null) {
finalImportSet.add(dotModel.dotCheckType);
}
}
for (final ClassModel model : zodImports) {
final DotClassElement dotModel = dotGroup.find(model);
if (dotModel.nativeType == DefinedPosition.NATIVE) {
continue;
}
finalImportSet.add("Zod" + dotModel.dotTypeName);
}
for (final ClassModel model : writeImports) {
final DotClassElement dotModel = dotGroup.find(model);
if (dotModel.nativeType == DefinedPosition.NATIVE) {
continue;
}
finalImportSet.add(dotModel.dotTypeName + "Write");
}
if (finalImportSet.size() != 0) {
out.append("import {");
for (final String elem : finalImportSet) {
out.append("\n\t");
out.append(elem);
out.append(",");
}
out.append("\n} from \"../model\";\n\n");
}
out.append(data.toString());
*/
data.append("""
</table>
</td>
</tr>
</table>>
]
""");
data.append(outLinks.toString());
return data.toString();
}
}

View File

@@ -0,0 +1,485 @@
package org.kar.archidata.externalRestApi.dot;
import java.io.IOException;
import java.util.List;
import java.util.Map.Entry;
import org.kar.archidata.externalRestApi.model.ClassEnumModel;
import org.kar.archidata.externalRestApi.model.ClassListModel;
import org.kar.archidata.externalRestApi.model.ClassMapModel;
import org.kar.archidata.externalRestApi.model.ClassModel;
import org.kar.archidata.externalRestApi.model.ClassObjectModel;
import org.kar.archidata.externalRestApi.model.ClassObjectModel.FieldProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DotClassElement {
static final Logger LOGGER = LoggerFactory.getLogger(DotClassElement.class);
public enum DefinedPosition {
NATIVE, // Native element of dot language.
BASIC, // basic wrapping for JAVA type.
NORMAL // Normal Object to interpret.
}
public List<ClassModel> models;
public String zodName;
public String dotTypeName;
public String dotCheckType;
public String declaration;
public String fileName = null;
public String comment = null;
public DefinedPosition nativeType = DefinedPosition.NORMAL;
public static String determineFileName(final String className) {
return className.replaceAll("([a-z])([A-Z])", "$1-$2").replaceAll("([A-Z])([A-Z][a-z])", "$1-$2").toLowerCase();
}
public DotClassElement(final List<ClassModel> model, final String zodName, final String dotTypeName,
final String dotCheckType, final String declaration, final DefinedPosition nativeType) {
this.models = model;
this.zodName = zodName;
this.dotTypeName = dotTypeName;
this.declaration = declaration;
this.nativeType = nativeType;
}
public DotClassElement(final ClassModel model) {
this.models = List.of(model);
this.dotTypeName = model.getOriginClasses().getSimpleName();
this.declaration = null;
}
public boolean isCompatible(final ClassModel model) {
return this.models.contains(model);
}
public String generateEnum(final ClassEnumModel model, final DotClassElementGroup dotGroup) throws IOException {
final StringBuilder out = new StringBuilder();
out.append("""
%s [
shape=plain
label=<<table color="#33FF33" border="2" cellborder="1" cellspacing="0" cellpadding="4">
<tr>
<td port="NAME"><b>%s</b><br/>(ENUM)</td>
</tr>
<tr>
<td>
<table border="0" cellborder="0" cellspacing="0" >
""".formatted(this.dotTypeName, this.dotTypeName));
final boolean first = true;
for (final Entry<String, Object> elem : model.getListOfValues().entrySet()) {
out.append("\t\t\t\t\t\t<tr><td align=\"left\"><b> + ");
out.append(elem.getKey());
out.append("</b> = ");
if (elem.getValue() instanceof final Integer value) {
out.append(value);
} else {
out.append("'");
out.append(elem.getValue());
out.append("'");
}
out.append("</td></tr>\n");
}
out.append("""
</table>
</td>
</tr>
</table>>
]
""");
return out.toString();
}
public String generateImporDot(final List<ClassModel> depModels, final DotClassElementGroup dotGroup)
throws IOException {
final StringBuilder out = new StringBuilder();
for (final ClassModel depModel : depModels) {
final DotClassElement dotModel = dotGroup.find(depModel);
if (dotModel.nativeType != DefinedPosition.NATIVE) {
out.append("import {");
out.append(dotModel.zodName);
out.append("} from \"./");
out.append(dotModel.fileName);
out.append("\";\n");
}
}
return out.toString();
}
private Object generateComment(final ClassObjectModel model) {
final StringBuilder out = new StringBuilder();
if (model.getDescription() != null || model.getExample() != null) {
out.append("/**\n");
if (model.getDescription() != null) {
for (final String elem : model.getDescription().split("\n")) {
out.append(" * ");
out.append(elem);
out.append("\n");
}
}
if (model.getExample() != null) {
out.append(" * Example:\n");
out.append(" * ```\n");
for (final String elem : model.getExample().split("\n")) {
out.append(" * ");
out.append(elem);
out.append("\n");
}
out.append(" * ```\n");
}
out.append(" */\n");
}
return out.toString();
}
public String optionalTypeZod(final FieldProperty field) {
// Common checking element (apply to List, Map, ...)
if (field.nullable()) {
return ".optional()";
}
if (field.notNull()) {
return "";
}
// Other object:
if (field.model().getOriginClasses() == null || field.model().getOriginClasses().isPrimitive()) {
return "";
}
if (field.columnNotNull()) {
return "";
}
return ".optional()";
}
public String maxSizeZod(final FieldProperty field) {
final StringBuilder builder = new StringBuilder();
final Class<?> clazz = field.model().getOriginClasses();
if (clazz == String.class) {
if (field.sizeMin() > 0) {
builder.append(".min(");
builder.append(field.sizeMin());
builder.append(")");
}
if (field.sizeMax() > 0) {
builder.append(".max(");
builder.append(field.sizeMax());
builder.append(")");
}
}
if (clazz == short.class || clazz == Short.class || clazz == int.class || clazz == Integer.class
|| clazz == long.class || clazz == Long.class || clazz == float.class || clazz == Float.class
|| clazz == double.class || clazz == Double.class) {
if (field.min() != null && field.min() > 0) {
builder.append(".min(");
builder.append(field.min());
builder.append(")");
}
if (field.max() != null && field.max() > 0) {
builder.append(".max(");
builder.append(field.max());
builder.append(")");
}
}
return builder.toString();
}
public String readOnlyZod(final FieldProperty field) {
if (field.readOnly()) {
return ".readonly()";
}
return "";
}
public String generateBaseObject() {
final StringBuilder out = new StringBuilder();
return out.toString();
}
public String convertHtml(final String data) {
return data.replace("<", "&lt;").replace(">", "&gt;");
}
public static String generateClassModelTypescript(final ClassModel model, final DotClassElementGroup dotGroup)
throws IOException {
if (model instanceof ClassEnumModel) {
final DotClassElement dotFieldModel = dotGroup.find(model);
return dotFieldModel.dotTypeName;
} else if (model instanceof ClassObjectModel) {
final DotClassElement dotFieldModel = dotGroup.find(model);
return dotFieldModel.dotTypeName;
} else if (model instanceof final ClassListModel fieldListModel) {
return generateDotList(fieldListModel, dotGroup);
} else if (model instanceof final ClassMapModel fieldMapModel) {
return generateDotMap(fieldMapModel, dotGroup);
}
throw new IOException("Impossible model:" + model);
}
public static String generateClassModelTypescriptLink(final ClassModel model, final DotClassElementGroup dotGroup)
throws IOException {
if (model instanceof ClassEnumModel) {
final DotClassElement dotFieldModel = dotGroup.find(model);
return dotFieldModel.dotTypeName;
} else if (model instanceof ClassObjectModel) {
final DotClassElement dotFieldModel = dotGroup.find(model);
if (dotFieldModel.nativeType == DefinedPosition.NORMAL) {
return dotFieldModel.dotTypeName;
}
} else if (model instanceof final ClassListModel fieldListModel) {
final String className = generateDotListClassName(fieldListModel, dotGroup);
if (className != null) {
return className;
}
} else if (model instanceof final ClassMapModel fieldMapModel) {
final String className = generateDotMapClassName(fieldMapModel, dotGroup);
if (className != null) {
return className;
}
}
return null;
}
public String generateObject(final ClassObjectModel model, final DotClassElementGroup dotGroup) throws IOException {
final StringBuilder out = new StringBuilder();
final StringBuilder outLinks = new StringBuilder();
out.append("""
%s [
shape=plain
ranksep="2"
label=<<table color="#000000" border="2" cellborder="1" cellspacing="0" cellpadding="4">
<tr>
<td port="NAME"><b>%s</b></td>
</tr>
<tr>
<td>
<table border="0" cellborder="0" cellspacing="0" >
""".formatted(this.dotTypeName, this.dotTypeName));
String inheritence = null;
if (model.getExtendsClass() != null) {
final ClassModel parentClass = model.getExtendsClass();
final DotClassElement dotParentModel = dotGroup.find(parentClass);
inheritence = dotParentModel.dotTypeName;
}
if (model.getFields().size() == 0) {
out.append("\t\t\t\t\t\t<tr><td> <i>(empty)</i> </td></tr>");
}
for (final FieldProperty field : model.getFields()) {
final ClassModel fieldModel = field.model();
if (field.comment() != null) {
out.append("\t\t\t\t\t\t<tr><td align=\"left\"><i> // ");
out.append(convertHtml(field.comment()));
out.append("</i></td></tr>\n");
}
out.append("\t\t\t\t\t\t<tr><td align=\"left\" port=\"");
out.append(field.name());
out.append("\"><b> + ");
out.append(field.name());
out.append("</b>: ");
out.append(generateClassModelTypescript(fieldModel, dotGroup));
final String remoteType = generateClassModelTypescriptLink(fieldModel, dotGroup);
if (remoteType != null) {
outLinks.append("\t");
outLinks.append(this.dotTypeName);
outLinks.append(":");
outLinks.append(field.name());
outLinks.append(":e -> ");
outLinks.append(remoteType);
outLinks.append(":NAME:w\n");
} else if (field.linkClass() != null) {
final String remoteLinkType = generateClassModelTypescriptLink(field.linkClass(), dotGroup);
if (remoteLinkType != null) {
outLinks.append("\t");
outLinks.append(this.dotTypeName);
outLinks.append(":");
outLinks.append(field.name());
outLinks.append(":e -> ");
outLinks.append(remoteLinkType);
outLinks.append(":NAME:w\n");
}
}
out.append("</td></tr>\n");
}
out.append("""
</table>
</td>
</tr>
</table>>
]
""");
if (inheritence != null) {
out.append("\tedge [dir=back arrowtail=empty arrowsize=2]\n");
out.append("\t");
out.append(inheritence);
// heritage stop link on the "s" South
out.append(":s -> ");
out.append(this.dotTypeName);
// heritage start link on the "n" North
out.append(":n\n");
}
if (!outLinks.isEmpty()) {
out.append("\tedge [dir=back arrowtail=diamond arrowsize=2]\n");
//out.append("\tedge [arrowhead=diamond arrowsize=2]\n");
out.append(outLinks.toString());
}
return out.toString();
}
private static String generateDotMap(final ClassMapModel model, final DotClassElementGroup dotGroup) {
final StringBuilder out = new StringBuilder();
out.append("Map&lt;");
if (model.keyModel instanceof final ClassListModel fieldListModel) {
final String tmp = generateDotList(fieldListModel, dotGroup);
out.append(tmp);
} else if (model.keyModel instanceof final ClassMapModel fieldMapModel) {
final String tmp = generateDotMap(fieldMapModel, dotGroup);
out.append(tmp);
} else if (model.keyModel instanceof final ClassObjectModel fieldObjectModel) {
final String tmp = generateDotObject(fieldObjectModel, dotGroup);
out.append(tmp);
} else if (model.keyModel instanceof final ClassEnumModel fieldEnumModel) {
final String tmp = generateDotEnum(fieldEnumModel, dotGroup);
out.append(tmp);
}
out.append(", ");
if (model.valueModel instanceof final ClassListModel fieldListModel) {
final String tmp = generateDotList(fieldListModel, dotGroup);
out.append(tmp);
} else if (model.valueModel instanceof final ClassMapModel fieldMapModel) {
final String tmp = generateDotMap(fieldMapModel, dotGroup);
out.append(tmp);
} else if (model.valueModel instanceof final ClassObjectModel fieldObjectModel) {
final String tmp = generateDotObject(fieldObjectModel, dotGroup);
out.append(tmp);
} else if (model.valueModel instanceof final ClassEnumModel fieldEnumModel) {
final String tmp = generateDotEnum(fieldEnumModel, dotGroup);
out.append(tmp);
}
out.append("&gt;");
return out.toString();
}
private static String generateDotEnum(final ClassEnumModel model, final DotClassElementGroup dotGroup) {
final DotClassElement dotParentModel = dotGroup.find(model);
return dotParentModel.dotTypeName;
}
private static String generateDotObject(final ClassObjectModel model, final DotClassElementGroup dotGroup) {
final DotClassElement dotParentModel = dotGroup.find(model);
return dotParentModel.dotTypeName;
}
private static String generateDotObjectClassName(
final ClassObjectModel model,
final DotClassElementGroup dotGroup) {
final DotClassElement dotParentModel = dotGroup.find(model);
if (dotParentModel.nativeType == DefinedPosition.NORMAL) {
return dotParentModel.dotTypeName;
}
return null;
}
private static String generateDotListClassName(final ClassListModel model, final DotClassElementGroup dotGroup) {
if (model.valueModel instanceof final ClassListModel fieldListModel) {
return generateDotListClassName(fieldListModel, dotGroup);
} else if (model.valueModel instanceof final ClassMapModel fieldMapModel) {
return generateDotMapClassName(fieldMapModel, dotGroup);
} else if (model.valueModel instanceof final ClassObjectModel fieldObjectModel) {
return generateDotObjectClassName(fieldObjectModel, dotGroup);
}
return null;
}
private static String generateDotMapClassName(final ClassMapModel model, final DotClassElementGroup dotGroup) {
if (model.valueModel instanceof final ClassListModel fieldListModel) {
return generateDotListClassName(fieldListModel, dotGroup);
} else if (model.valueModel instanceof final ClassMapModel fieldMapModel) {
return generateDotMapClassName(fieldMapModel, dotGroup);
} else if (model.valueModel instanceof final ClassObjectModel fieldObjectModel) {
return generateDotObjectClassName(fieldObjectModel, dotGroup);
} else if (model.valueModel instanceof final ClassEnumModel fieldEnumModel) {
return generateDotEnum(fieldEnumModel, dotGroup);
}
return null;
}
private static String generateDotList(final ClassListModel model, final DotClassElementGroup dotGroup) {
final StringBuilder out = new StringBuilder();
out.append("List&lt;");
if (model.valueModel instanceof final ClassListModel fieldListModel) {
final String tmp = generateDotList(fieldListModel, dotGroup);
out.append(tmp);
} else if (model.valueModel instanceof final ClassMapModel fieldMapModel) {
final String tmp = generateDotMap(fieldMapModel, dotGroup);
out.append(tmp);
} else if (model.valueModel instanceof final ClassObjectModel fieldObjectModel) {
final String tmp = generateDotObject(fieldObjectModel, dotGroup);
out.append(tmp);
}
out.append("&gt;");
return out.toString();
}
public String generateFile(final DotClassElementGroup dotGroup) throws IOException {
if (this.nativeType == DefinedPosition.NATIVE) {
return "";
}
final ClassModel model = this.models.get(0);
String data = "";
if (this.nativeType == DefinedPosition.BASIC && model instanceof ClassObjectModel) {
// nothing to do___ data = generateBaseObject();
} else if (model instanceof final ClassEnumModel modelEnum) {
data = generateEnum(modelEnum, dotGroup);
} else if (model instanceof final ClassObjectModel modelObject) {
data = generateObject(modelObject, dotGroup);
}
return data;
}
private static String generateLocalModelBase(final ClassModel model, final DotClassElementGroup dotGroup)
throws IOException {
if (model instanceof final ClassObjectModel objectModel) {
return generateDotObject(objectModel, dotGroup);
}
if (model instanceof final ClassEnumModel enumModel) {
return generateDotEnum(enumModel, dotGroup);
}
if (model instanceof final ClassListModel listModel) {
return generateDotList(listModel, dotGroup);
}
if (model instanceof final ClassMapModel mapModel) {
return generateDotMap(mapModel, dotGroup);
}
return "";
}
public static String generateLocalModel(
final String ModelName,
final List<ClassModel> models,
final DotClassElementGroup dotGroup) throws IOException {
if (models.size() == 1) {
if (models.get(0) instanceof ClassObjectModel) {
return null;
}
if (models.get(0) instanceof ClassEnumModel) {
return null;
}
}
final StringBuilder out = new StringBuilder();
if (models.size() == 1) {
out.append(generateLocalModelBase(models.get(0), dotGroup));
} else {
out.append("Union&lt;");
for (final ClassModel model : models) {
out.append("\t");
out.append(generateLocalModelBase(models.get(0), dotGroup));
out.append(",\n");
}
out.append("&gt;");
}
return out.toString();
}
}

View File

@@ -0,0 +1,27 @@
package org.kar.archidata.externalRestApi.dot;
import java.util.List;
import org.kar.archidata.externalRestApi.model.ClassModel;
public class DotClassElementGroup {
private final List<DotClassElement> dotElements;
public List<DotClassElement> getDotElements() {
return this.dotElements;
}
public DotClassElementGroup(final List<DotClassElement> tsElements) {
this.dotElements = tsElements;
}
public DotClassElement find(final ClassModel model) {
for (final DotClassElement elem : this.dotElements) {
if (elem.isCompatible(model)) {
return elem;
}
}
return null;
}
}

View File

@@ -10,6 +10,7 @@ public class ClassEnumModel extends ClassModel {
protected ClassEnumModel(final Class<?> clazz) {
this.originClasses = clazz;
this.noWriteSpecificMode = true;
}
@Override

View File

@@ -11,12 +11,17 @@ import java.util.Set;
public abstract class ClassModel {
protected boolean analyzeDone = false;
protected Class<?> originClasses = null;
protected boolean noWriteSpecificMode = false;
protected List<ClassModel> dependencyModels = new ArrayList<>();
public Class<?> getOriginClasses() {
return this.originClasses;
}
public boolean isNoWriteSpecificMode() {
return this.noWriteSpecificMode;
}
protected boolean isCompatible(final Class<?> clazz) {
return this.originClasses == clazz;
}

View File

@@ -1,5 +1,6 @@
package org.kar.archidata.externalRestApi.model;
import java.io.IOException;
import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.time.LocalDate;
@@ -10,9 +11,15 @@ import java.util.List;
import java.util.Set;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.validation.constraints.Size;
public class ClassObjectModel extends ClassModel {
static final Logger LOGGER = LoggerFactory.getLogger(ClassObjectModel.class);
@@ -52,19 +59,28 @@ public class ClassObjectModel extends ClassModel {
public record FieldProperty(
String name,
ClassModel model,
ClassModel linkClass, // link class when use remote ID (ex: list<UUID>)
String comment,
int limitSize,
int sizeMin, // String SizeMin
int sizeMax, // String SizeMax
Long min, // number min value
Long max, // number max value
Boolean readOnly,
Boolean notNull,
Boolean columnNotNull,
Boolean nullable) {
public FieldProperty(final String name, final ClassModel model, final String comment, final int limitSize,
public FieldProperty(final String name, final ClassModel model, final ClassModel linkClass,
final String comment, final int sizeMin, final int sizeMax, final Long min, final Long max,
final Boolean readOnly, final Boolean notNull, final Boolean columnNotNull, final Boolean nullable) {
this.name = name;
this.model = model;
this.linkClass = linkClass;
this.comment = comment;
this.limitSize = limitSize;
this.sizeMin = sizeMin;
this.sizeMax = sizeMax;
this.min = min;
this.max = max;
this.readOnly = readOnly;
this.notNull = notNull;
this.columnNotNull = columnNotNull;
@@ -72,11 +88,59 @@ public class ClassObjectModel extends ClassModel {
}
public FieldProperty(final Field field, final ModelGroup previous) throws Exception {
private static int getStringMinSize(final Field field) throws DataAccessException {
final Size size = AnnotationTools.getConstraintsSize(field);
return size != null ? size.min() : 0;
}
private static int getStringMaxSize(final Field field) throws DataAccessException {
final Size size = AnnotationTools.getConstraintsSize(field);
final int colomnLimitSize = AnnotationTools.getLimitSize(field);
return size == null ? colomnLimitSize : colomnLimitSize < size.max() ? colomnLimitSize : size.max();
}
private static Class<?> getSubModelIfExist2(final Field field) {
final ManyToOne manyToOne = AnnotationTools.getManyToOne(field);
if (manyToOne != null) {
if (manyToOne.targetEntity() != null && manyToOne.targetEntity() != void.class) {
return manyToOne.targetEntity();
}
return null;
}
final ManyToMany manyToMany = AnnotationTools.getManyToMany(field);
if (manyToMany != null) {
if (manyToMany.targetEntity() != null && manyToMany.targetEntity() != void.class) {
return manyToMany.targetEntity();
}
return null;
}
final OneToMany oneToMany = AnnotationTools.getOneToMany(field);
if (oneToMany != null) {
if (oneToMany.targetEntity() != null && oneToMany.targetEntity() != void.class) {
return oneToMany.targetEntity();
}
return null;
}
return null;
}
private static ClassModel getSubModelIfExist(final Field field, final ModelGroup previous) throws IOException {
final Class<?> tmp = getSubModelIfExist2(field);
if (tmp == null) {
return null;
}
return ClassModel.getModel(tmp, previous);
}
public FieldProperty(final Field field, final ModelGroup previous) throws DataAccessException, IOException {
this(field.getName(), //
ClassModel.getModel(field.getGenericType(), previous), //
getSubModelIfExist(field, previous), //
AnnotationTools.getComment(field), //
AnnotationTools.getLimitSize(field), //
getStringMinSize(field), //
getStringMaxSize(field), //
AnnotationTools.getConstraintsMin(field), //
AnnotationTools.getConstraintsMax(field), //
AnnotationTools.getSchemaReadOnly(field), //
AnnotationTools.getConstraintsNotNull(field), //
AnnotationTools.getColumnNotNull(field), //
@@ -123,6 +187,7 @@ public class ClassObjectModel extends ClassModel {
}
this.analyzeDone = true;
final Class<?> clazz = this.originClasses;
this.noWriteSpecificMode = AnnotationTools.getNoWriteSpecificMode(clazz);
this.isPrimitive = clazz.isPrimitive();
if (this.isPrimitive) {
return;

View File

@@ -41,7 +41,7 @@ public class TsApiGeneration {
final ClassEnumModel model,
final TsClassElementGroup tsGroup,
final Set<ClassModel> imports,
final boolean writeMode) throws IOException {
final Set<ClassModel> importWrite) throws IOException {
imports.add(model);
final TsClassElement tsModel = tsGroup.find(model);
return tsModel.tsTypeName;
@@ -51,15 +51,19 @@ public class TsApiGeneration {
final ClassObjectModel model,
final TsClassElementGroup tsGroup,
final Set<ClassModel> imports,
final boolean writeMode) throws IOException {
final Set<ClassModel> importWrite) throws IOException {
final TsClassElement tsModel = tsGroup.find(model);
if (tsModel.nativeType != DefinedPosition.NATIVE) {
imports.add(model);
if (importWrite == null || tsModel.models.get(0).isNoWriteSpecificMode()) {
imports.add(model);
} else {
importWrite.add(model);
}
}
if (tsModel.nativeType != DefinedPosition.NORMAL) {
return tsModel.tsTypeName;
}
if (writeMode) {
if (importWrite != null && !tsModel.models.get(0).isNoWriteSpecificMode()) {
return tsModel.tsTypeName + "Write";
}
return tsModel.tsTypeName;
@@ -69,12 +73,12 @@ public class TsApiGeneration {
final ClassMapModel model,
final TsClassElementGroup tsGroup,
final Set<ClassModel> imports,
final boolean writeMode) throws IOException {
final Set<ClassModel> importWrite) throws IOException {
final StringBuilder out = new StringBuilder();
out.append("{[key: ");
out.append(generateClassModelTypescript(model.keyModel, tsGroup, imports, writeMode));
out.append(generateClassModelTypescript(model.keyModel, tsGroup, imports, importWrite));
out.append("]: ");
out.append(generateClassModelTypescript(model.valueModel, tsGroup, imports, writeMode));
out.append(generateClassModelTypescript(model.valueModel, tsGroup, imports, importWrite));
out.append(";}");
return out.toString();
}
@@ -83,9 +87,9 @@ public class TsApiGeneration {
final ClassListModel model,
final TsClassElementGroup tsGroup,
final Set<ClassModel> imports,
final boolean writeMode) throws IOException {
final Set<ClassModel> importWrite) throws IOException {
final StringBuilder out = new StringBuilder();
out.append(generateClassModelTypescript(model.valueModel, tsGroup, imports, writeMode));
out.append(generateClassModelTypescript(model.valueModel, tsGroup, imports, importWrite));
out.append("[]");
return out.toString();
}
@@ -94,18 +98,18 @@ public class TsApiGeneration {
final ClassModel model,
final TsClassElementGroup tsGroup,
final Set<ClassModel> imports,
final boolean writeMode) throws IOException {
final Set<ClassModel> importWrite) throws IOException {
if (model instanceof final ClassObjectModel objectModel) {
return generateClassObjectModelTypescript(objectModel, tsGroup, imports, writeMode);
return generateClassObjectModelTypescript(objectModel, tsGroup, imports, importWrite);
}
if (model instanceof final ClassListModel listModel) {
return generateClassListModelTypescript(listModel, tsGroup, imports, writeMode);
return generateClassListModelTypescript(listModel, tsGroup, imports, importWrite);
}
if (model instanceof final ClassMapModel mapModel) {
return generateClassMapModelTypescript(mapModel, tsGroup, imports, writeMode);
return generateClassMapModelTypescript(mapModel, tsGroup, imports, importWrite);
}
if (model instanceof final ClassEnumModel enumModel) {
return generateClassEnumModelTypescript(enumModel, tsGroup, imports, writeMode);
return generateClassEnumModelTypescript(enumModel, tsGroup, imports, importWrite);
}
throw new IOException("Impossible model:" + model);
}
@@ -114,7 +118,7 @@ public class TsApiGeneration {
final List<ClassModel> models,
final TsClassElementGroup tsGroup,
final Set<ClassModel> imports,
final boolean writeMode) throws IOException {
final Set<ClassModel> importWrite) throws IOException {
if (models.size() == 0) {
return "void";
}
@@ -126,7 +130,7 @@ public class TsApiGeneration {
} else {
out.append(" | ");
}
final String data = generateClassModelTypescript(model, tsGroup, imports, writeMode);
final String data = generateClassModelTypescript(model, tsGroup, imports, importWrite);
out.append(data);
}
return out.toString();
@@ -188,7 +192,7 @@ public class TsApiGeneration {
data.append("\n\t\t\tdata,");
}
if (needGenerateProgress) {
data.append("\n\t\t\tcallback,");
data.append("\n\t\t\tcallbacks,");
}
data.append("\n\t\t}: {");
data.append("\n\t\trestConfig: RESTConfig,");
@@ -199,7 +203,7 @@ public class TsApiGeneration {
data.append("\n\t\t\t");
data.append(queryEntry.getKey());
data.append("?: ");
data.append(generateClassModelsTypescript(queryEntry.getValue(), tsGroup, imports, false));
data.append(generateClassModelsTypescript(queryEntry.getValue(), tsGroup, imports, null));
data.append(",");
}
data.append("\n\t\t},");
@@ -210,15 +214,15 @@ public class TsApiGeneration {
data.append("\n\t\t\t");
data.append(paramEntry.getKey());
data.append(": ");
data.append(generateClassModelsTypescript(paramEntry.getValue(), tsGroup, imports, false));
data.append(generateClassModelsTypescript(paramEntry.getValue(), tsGroup, imports, null));
data.append(",");
}
data.append("\n\t\t},");
}
if (interfaceElement.unnamedElement.size() == 1) {
data.append("\n\t\tdata: ");
data.append(generateClassModelTypescript(interfaceElement.unnamedElement.get(0), tsGroup, writeImports,
true));
data.append(generateClassModelTypescript(interfaceElement.unnamedElement.get(0), tsGroup, imports,
writeImports));
data.append(",");
} else if (interfaceElement.multiPartParameters.size() != 0) {
data.append("\n\t\tdata: {");
@@ -227,7 +231,7 @@ public class TsApiGeneration {
data.append("\n\t\t\t");
data.append(pathEntry.getKey());
data.append(": ");
data.append(generateClassModelsTypescript(pathEntry.getValue(), tsGroup, writeImports, true));
data.append(generateClassModelsTypescript(pathEntry.getValue(), tsGroup, imports, writeImports));
data.append(",");
}
data.append("\n\t\t},");
@@ -264,7 +268,7 @@ public class TsApiGeneration {
data.append(",");
}
if (needGenerateProgress) {
data.append("\n\t\tcallback?: RESTCallbacks,");
data.append("\n\t\tcallbacks?: RESTCallbacks,");
toolImports.add("RESTCallbacks");
}
data.append("\n\t}): Promise<");
@@ -275,7 +279,7 @@ public class TsApiGeneration {
toolImports.add("RESTRequestJson");
} else {
final String returnType = generateClassModelsTypescript(interfaceElement.returnTypes, tsGroup, imports,
false);
null);
data.append(returnType);
data.append("> {");
if ("void".equals(returnType)) {
@@ -320,7 +324,7 @@ public class TsApiGeneration {
data.append("\n\t\t\t\taccept: produce,");
} else {
final String returnType = generateClassModelsTypescript(interfaceElement.returnTypes, tsGroup,
imports, false);
imports, null);
if (!"void".equals(returnType)) {
for (final String elem : produces) {
if (MediaType.APPLICATION_JSON.equals(elem)) {
@@ -346,7 +350,7 @@ public class TsApiGeneration {
data.append("\n\t\t\tdata,");
}
if (needGenerateProgress) {
data.append("\n\t\t\tcallback,");
data.append("\n\t\t\tcallbacks,");
}
data.append("\n\t\t}");
if (returnComplexModel != null) {

View File

@@ -181,12 +181,18 @@ public class TsClassElement {
if (tsModel.nativeType != DefinedPosition.NATIVE) {
out.append("import {");
out.append(tsModel.zodName);
if (tsModel.nativeType == DefinedPosition.NORMAL && !(tsModel.models.get(0).isNoWriteSpecificMode())) {
out.append(", ");
out.append(tsModel.zodName);
out.append("Write ");
}
out.append("} from \"./");
out.append(tsModel.fileName);
out.append("\";\n");
}
}
return out.toString();
}
private Object generateComment(final ClassObjectModel model) {
@@ -215,31 +221,68 @@ public class TsClassElement {
return out.toString();
}
public String optionalTypeZod(final FieldProperty field) {
public boolean isOptionalTypeZod(final FieldProperty field) {
// Common checking element (apply to List, Map, ...)
if (field.nullable()) {
return ".optional()";
return true;
}
if (field.notNull()) {
return "";
return false;
}
// Other object:
if (field.model().getOriginClasses() == null || field.model().getOriginClasses().isPrimitive()) {
return "";
return false;
}
if (field.columnNotNull()) {
return "";
return false;
}
return ".optional()";
return true;
}
public String optionalTypeZod(final FieldProperty field) {
// Common checking element (apply to List, Map, ...)
if (isOptionalTypeZod(field)) {
return ".optional()";
}
return "";
}
public String optionalWriteTypeZod(final FieldProperty field) {
// Common checking element (apply to List, Map, ...)
if (isOptionalTypeZod(field)) {
return ".nullable()";
}
return "";
}
public String maxSizeZod(final FieldProperty field) {
final StringBuilder builder = new StringBuilder();
final Class<?> clazz = field.model().getOriginClasses();
if (field.limitSize() > 0 && clazz == String.class) {
builder.append(".max(");
builder.append(field.limitSize());
builder.append(")");
if (clazz == String.class) {
if (field.sizeMin() > 0) {
builder.append(".min(");
builder.append(field.sizeMin());
builder.append(")");
}
if (field.sizeMax() > 0) {
builder.append(".max(");
builder.append(field.sizeMax());
builder.append(")");
}
}
if (clazz == short.class || clazz == Short.class || clazz == int.class || clazz == Integer.class
|| clazz == long.class || clazz == Long.class || clazz == float.class || clazz == Float.class
|| clazz == double.class || clazz == Double.class) {
if (field.min() != null && field.min() > 0) {
builder.append(".min(");
builder.append(field.min());
builder.append(")");
}
if (field.max() != null && field.max() > 0) {
builder.append(".max(");
builder.append(field.max());
builder.append(")");
}
}
return builder.toString();
}
@@ -270,7 +313,9 @@ public class TsClassElement {
out.append(getBaseHeader());
out.append(generateImports(model.getDependencyModels(), tsGroup));
out.append("\n");
// ------------------------------------------------------------------------
// -- Generate read mode
// ------------------------------------------------------------------------
out.append(generateComment(model));
out.append("export const ");
out.append(this.zodName);
@@ -315,27 +360,85 @@ public class TsClassElement {
out.append("\n});\n");
out.append(generateZodInfer(this.tsTypeName, this.zodName));
out.append(generateExportCheckFunctionWrite(""));
// check if we need to generate write mode :
if (!model.isNoWriteSpecificMode()) {
// ------------------------------------------------------------------------
// -- Generate write mode
// ------------------------------------------------------------------------
//out.append(generateComment(model));
out.append("export const ");
out.append(this.zodName);
out.append("Write = ");
// Generate the Write Type associated.
out.append("\nexport const ");
out.append(this.zodName);
out.append("Write = ");
out.append(this.zodName);
if (omitField.size() != 0) {
out.append(".omit({\n");
for (final String elem : omitField) {
out.append("\t");
out.append(elem);
out.append(": true,\n");
if (model.getExtendsClass() != null) {
final ClassModel parentClass = model.getExtendsClass();
final TsClassElement tsParentModel = tsGroup.find(parentClass);
out.append(tsParentModel.zodName);
out.append("Write");
out.append(".extend({");
} else {
out.append("zod.object({");
}
out.append("\n})");
out.append("\n");
for (final FieldProperty field : model.getFields()) {
// remove all readOnly field
if (field.readOnly()) {
continue;
}
final ClassModel fieldModel = field.model();
if (field.comment() != null) {
out.append("\t/**\n");
out.append("\t * ");
out.append(field.comment());
out.append("\n\t */\n");
}
out.append("\t");
out.append(field.name());
out.append(": ");
if (fieldModel instanceof ClassEnumModel || fieldModel instanceof ClassObjectModel) {
final TsClassElement tsFieldModel = tsGroup.find(fieldModel);
out.append(tsFieldModel.zodName);
} else if (fieldModel instanceof final ClassListModel fieldListModel) {
final String data = generateTsList(fieldListModel, tsGroup);
out.append(data);
} else if (fieldModel instanceof final ClassMapModel fieldMapModel) {
final String data = generateTsMap(fieldMapModel, tsGroup);
out.append(data);
}
out.append(maxSizeZod(field));
out.append(optionalWriteTypeZod(field));
// all write field are optional
if (field.model() instanceof final ClassObjectModel plop) {
if (!plop.isPrimitive()) {
out.append(".optional()");
}
} else {
out.append(".optional()");
}
out.append(",\n");
}
out.append("\n});\n");
out.append(generateZodInfer(this.tsTypeName + "Write", this.zodName + "Write"));
// Check only the input value ==> no need of the output
out.append(generateExportCheckFunctionWrite("Write"));
// Generate the Write Type associated.
/*
out.append("\nexport const ");
out.append(this.zodName);
out.append("Write = ");
out.append(this.zodName);
if (omitField.size() != 0) {
out.append(".omit({\n");
for (final String elem : omitField) {
out.append("\t");
out.append(elem);
out.append(": true,\n");
}
out.append("\n})");
}
out.append(".partial();\n");
*/
}
out.append(".partial();\n");
out.append(generateZodInfer(this.tsTypeName + "Write", this.zodName + "Write"));
// Check only the input value ==> no need of the output
out.append(generateExportCheckFunctionWrite("Write"));
return out.toString();
}

View File

@@ -22,6 +22,8 @@ import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.ReadAllColumn;
import org.kar.archidata.exception.FailException;
import org.kar.archidata.exception.InputException;
import org.kar.archidata.model.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -214,64 +216,54 @@ public class DataTools {
return data;
}
public static <CLASS_TYPE, ID_TYPE> Response uploadCover(
public static <CLASS_TYPE, ID_TYPE> void uploadCover(
final Class<CLASS_TYPE> clazz,
final ID_TYPE id,
String fileName,
final InputStream fileInputStream,
final FormDataContentDisposition fileMetaData) {
try {
// correct input string stream :
fileName = multipartCorrection(fileName);
// public NodeSmall uploadFile(final FormDataMultiPart form) {
LOGGER.info("Upload media file: {}", fileMetaData);
LOGGER.info(" - id: {}", id);
LOGGER.info(" - file_name: ", fileName);
LOGGER.info(" - fileInputStream: {}", fileInputStream);
LOGGER.info(" - fileMetaData: {}", fileMetaData);
final CLASS_TYPE media = DataAccess.get(clazz, id);
if (media == null) {
return Response.notModified("Media Id does not exist or removed...").build();
}
final long tmpUID = getTmpDataId();
final String sha512 = saveTemporaryFile(fileInputStream, tmpUID);
Data data = getWithSha512(sha512);
if (data == null) {
LOGGER.info("Need to add the data in the BDD ... ");
try {
data = createNewData(tmpUID, fileName, sha512);
} catch (final IOException ex) {
removeTemporaryFile(tmpUID);
ex.printStackTrace();
return Response.notModified("can not create input media").build();
} catch (final SQLException ex) {
ex.printStackTrace();
removeTemporaryFile(tmpUID);
return Response.notModified("Error in SQL insertion ...").build();
}
} else if (data.deleted) {
LOGGER.error("Data already exist but deleted");
undelete(data.uuid);
data.deleted = false;
} else {
LOGGER.error("Data already exist ... all good");
}
// Fist step: retrieve all the Id of each parents:...
LOGGER.info("Find typeNode");
if (id instanceof final Long idLong) {
AddOnDataJson.addLink(clazz, idLong, "covers", data.uuid);
} else if (id instanceof final UUID idUUID) {
AddOnDataJson.addLink(clazz, idUUID, "covers", data.uuid);
} else {
throw new IOException("Fail to add Cover can not detect type...");
}
return Response.ok(DataAccess.get(clazz, id)).build();
} catch (final Exception ex) {
System.out.println("Cat ann unexpected error ... ");
ex.printStackTrace();
final FormDataContentDisposition fileMetaData) throws Exception {
// public NodeSmall uploadFile(final FormDataMultiPart form) {
LOGGER.info("Upload media file: {}", fileMetaData);
LOGGER.info(" - id: {}", id);
LOGGER.info(" - file_name: {} ", fileMetaData.getFileName());
LOGGER.info(" - fileInputStream: {}", fileInputStream);
LOGGER.info(" - fileMetaData: {}", fileMetaData);
final CLASS_TYPE media = DataAccess.get(clazz, id);
if (media == null) {
throw new InputException(clazz.getCanonicalName(),
"[" + id.toString() + "] Id does not exist or removed...");
}
final long tmpUID = getTmpDataId();
final String sha512 = saveTemporaryFile(fileInputStream, tmpUID);
Data data = getWithSha512(sha512);
if (data == null) {
LOGGER.info("Need to add the data in the BDD ... ");
try {
data = createNewData(tmpUID, fileMetaData.getFileName(), sha512);
} catch (final IOException ex) {
removeTemporaryFile(tmpUID);
throw new FailException(Response.Status.NOT_MODIFIED,
clazz.getCanonicalName() + "[" + id.toString() + "] can not create input media", ex);
} catch (final SQLException ex) {
removeTemporaryFile(tmpUID);
throw new FailException(Response.Status.NOT_MODIFIED,
clazz.getCanonicalName() + "[" + id.toString() + "] Error in SQL insertion", ex);
}
} else if (data.deleted) {
LOGGER.error("Data already exist but deleted");
undelete(data.uuid);
data.deleted = false;
} else {
LOGGER.error("Data already exist ... all good");
}
// Fist step: retrieve all the Id of each parents:...
LOGGER.info("Find typeNode");
if (id instanceof final Long idLong) {
AddOnDataJson.addLink(clazz, idLong, "covers", data.uuid);
} else if (id instanceof final UUID idUUID) {
AddOnDataJson.addLink(clazz, idUUID, "covers", data.uuid);
} else {
throw new IOException("Fail to add Cover can not detect type...");
}
return Response.serverError().build();
}
}

View File

@@ -120,6 +120,7 @@ public class RESTApi {
}
}
@SuppressWarnings("unchecked")
protected <T, U> T modelSendJson(final String model, final Class<T> clazz, final String urlOffset, String body)
throws RESTErrorResponseExeption, IOException, InterruptedException {
final HttpClient client = HttpClient.newHttpClient();
@@ -164,6 +165,7 @@ public class RESTApi {
return this.mapper.readValue(httpResponse.body(), clazz);
}
@SuppressWarnings("unchecked")
protected <T> T modelSendMap(
final String model,
final Class<T> clazz,

View File

@@ -74,7 +74,7 @@ export interface RESTRequestType {
data?: any;
params?: object;
queries?: object;
callback?: RESTCallbacks;
callbacks?: RESTCallbacks;
}
function replaceAll(input, searchValue, replaceValue) {
@@ -237,7 +237,7 @@ export function RESTRequest({
data,
params,
queries,
callback,
callbacks,
}: RESTRequestType): Promise<ModelResponseHttp> {
// Create the URL PATH:
let generateUrl = RESTUrl({ restModel, restConfig, data, params, queries });
@@ -268,10 +268,10 @@ export function RESTRequest({
return new Promise((resolve, reject) => {
let action: undefined | Promise<Response> = undefined;
if (
isNullOrUndefined(callback) ||
(isNullOrUndefined(callback.progressDownload) &&
isNullOrUndefined(callback.progressUpload) &&
isNullOrUndefined(callback.abortHandle))
isNullOrUndefined(callbacks) ||
(isNullOrUndefined(callbacks.progressDownload) &&
isNullOrUndefined(callbacks.progressUpload) &&
isNullOrUndefined(callbacks.abortHandle))
) {
// No information needed: call the generic fetch interface
action = fetch(generateUrl, {
@@ -288,7 +288,7 @@ export function RESTRequest({
headers,
body,
},
callback
callbacks
);
}
action

View File

@@ -1 +1 @@
0.11.0
0.13.0