Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ package-lock.json
**/ttyd.sh
**/spring-shell.log
**/version.txt
/.claude/scheduled_tasks.lock
.claude/
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,13 @@
updateCsvRecords(connection, targetSchema, tableMetadata, recordsToUpdate, csvParser.getHeaderNames(), pkName, csvFile);
}
updateSequence(csvFile, connection, countAll);
if (countAll > 0) {
// CSV inserts always carry an explicit PK value; the DB's IDENTITY counter is therefore
// not advanced by the load. Bump it to MAX(col)+1 so a subsequent INSERT … DEFAULT
// (e.g. from a Hibernate @GeneratedValue(IDENTITY) entity) doesn't collide on the seeded
// rows.
restartIdentityColumns(dataSource, connection, targetSchema, tableName);
}
}
}

Expand Down Expand Up @@ -281,6 +288,96 @@
}
}

/**
* Walks JDBC metadata for the freshly-loaded table, finds every {@code IS_AUTOINCREMENT == YES}
* column, and advances its internal counter to {@code MAX(col) + 1}. Most engines (H2, PostgreSQL,
* MSSQL, MySQL) do not auto-advance an identity counter when the INSERT supplies an explicit value,
* which leaves the next "generate-me-one" INSERT colliding with the seeded rows on PK = 1.
*
* <p>
* Failures here are logged and swallowed — the CSV data is already persisted, and not every dialect
* supports identity restart in a portable way. Production traffic will surface the same collision
* the user already saw if the restart fails, but at least the seeded rows survive.
*/
private void restartIdentityColumns(DirigibleDataSource dataSource, Connection connection, String schema, String tableName) {
try (ResultSet cols = connection.getMetaData()
.getColumns(connection.getCatalog(), schema, tableName, "%")) {

Check failure

Code scanning / CodeQL

Query built from user-controlled sources High

This query depends on a
user-provided value
.
while (cols.next()) {
if (!"YES".equalsIgnoreCase(cols.getString("IS_AUTOINCREMENT"))) {
continue;
}
String column = cols.getString("COLUMN_NAME");
try {
long next = computeNextValue(connection, schema, tableName, column);
executeIdentityRestart(dataSource, connection, schema, tableName, column, next);
logger.info("Advanced IDENTITY counter on [{}.{}.{}] to [{}]", schema, tableName, column, next);

Check warning

Code scanning / CodeQL

Log Injection Medium

This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
} catch (SQLException restartError) {
logger.warn("Failed to advance IDENTITY counter on [{}.{}.{}]: {}", schema, tableName, column,
restartError.getMessage());

Check warning

Code scanning / CodeQL

Log Injection Medium

This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
Comment on lines +315 to +316
}
}
} catch (SQLException metadataError) {
logger.warn("Failed to look up IDENTITY columns on [{}.{}]: {}", schema, tableName, metadataError.getMessage());

Check warning

Code scanning / CodeQL

Log Injection Medium

This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
}
}

/**
* Computes the next value to seed an identity counter with: {@code MAX(col) + 1}. The caller only
* invokes this after at least one row has been inserted, so {@code MAX} is guaranteed non-null.
*/
private long computeNextValue(Connection connection, String schema, String tableName, String column) throws SQLException {
String sql = "SELECT MAX(" + quote(connection, column) + ") FROM " + qualifiedTable(connection, schema, tableName);
try (PreparedStatement ps = connection.prepareStatement(sql); ResultSet rs = ps.executeQuery()) {

Check failure

Code scanning / CodeQL

Query built from user-controlled sources High

This query depends on a
user-provided value
.
This query depends on a
user-provided value
.
if (rs.next()) {
long current = rs.getLong(1);
return rs.wasNull() ? 1L : current + 1L;
}
}
return 1L;
}

/**
* Emits dialect-specific DDL to advance an identity counter past {@code next}. Unknown dialects are
* skipped with an info-level log — better than throwing and aborting the whole CSVIM cycle.
*/
private void executeIdentityRestart(DirigibleDataSource dataSource, Connection connection, String schema, String tableName,
String column, long next) throws SQLException {
String sql;
if (dataSource.isOfType(DatabaseSystem.H2)) {
sql = "ALTER TABLE " + qualifiedTable(connection, schema, tableName) + " ALTER COLUMN " + quote(connection, column)
+ " RESTART WITH " + next;
} else if (dataSource.isOfType(DatabaseSystem.POSTGRESQL)) {
// setval(seq, n, false) -> next nextval() returns exactly n.
sql = "SELECT setval(pg_get_serial_sequence('" + schema + "." + tableName + "', '" + column + "'), " + next + ", false)";
} else if (dataSource.isOfType(DatabaseSystem.MSSQL)) {
// RESEED stores the *current* identity, so the next assigned id is current + increment.
sql = "DBCC CHECKIDENT('" + schema + "." + tableName + "', RESEED, " + (next - 1) + ")";
} else if (dataSource.isOfType(DatabaseSystem.MYSQL) || dataSource.isOfType(DatabaseSystem.MARIADB)) {
sql = "ALTER TABLE `" + schema + "`.`" + tableName + "` AUTO_INCREMENT = " + next;
} else {
logger.info("IDENTITY restart not implemented for dialect [{}] — skipping [{}.{}.{}]", dataSource.getDatabaseSystem(), schema,
tableName, column);

Check warning

Code scanning / CodeQL

Log Injection Medium

This log entry depends on a
user-provided value
.
This log entry depends on a
user-provided value
.
Comment on lines +358 to +359
return;
}
try (PreparedStatement ps = connection.prepareStatement(sql)) {

Check failure

Code scanning / CodeQL

Query built from user-controlled sources High

This query depends on a
user-provided value
.
This query depends on a
user-provided value
.
ps.execute();
}
}

/** Returns the schema-qualified, dialect-quoted table identifier. */
private static String qualifiedTable(Connection connection, String schema, String tableName) throws SQLException {
String q = connection.getMetaData()
.getIdentifierQuoteString();
return q + schema + q + "." + q + tableName + q;
}

/** Returns a dialect-quoted identifier. */
private static String quote(Connection connection, String identifier) throws SQLException {
String q = connection.getMetaData()
.getIdentifierQuoteString();
return q + identifier + q;
}

private boolean isDefaultDataSource(String dataSourceName) {
return null == dataSourceName || dataSourceName.equalsIgnoreCase(defaultDataSourceName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import jakarta.persistence.*;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
Expand Down Expand Up @@ -75,6 +76,7 @@ public class TableColumn {
private boolean unique;
@Column(name = "COLUMN_AUTOINCREMENT", columnDefinition = "BOOLEAN", nullable = true)
@Expose
@SerializedName(value = "autoincrement", alternate = {"identity"})
private boolean autoincrement;
/** The table. */
@ManyToOne(fetch = FetchType.EAGER, optional = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,15 @@ private static void setColumnAttributes(JsonObject column, TableColumn columnMod
&& column.get("nullable")
.getAsBoolean());

// The .table parser deserialises this field via Gson's @SerializedName(value="autoincrement",
// alternate={"identity"}); the .schema parser is hand-rolled and needs to honour both
// spellings explicitly. "identity" is the canonical name in every existing .schema fixture.
JsonElement identityElement = column.get("identity");
if (identityElement == null || identityElement.isJsonNull()) {
identityElement = column.get("autoincrement");
}
columnModel.setAutoincrement(identityElement != null && !identityElement.isJsonNull() && identityElement.getAsBoolean());

String defaultValue = getJsonElementValue(column, "defaultValue", null);
columnModel.setDefaultValue(defaultValue);

Expand Down
16 changes: 16 additions & 0 deletions components/group/group-templates/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-angular</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-angular-java</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-angular-v2</artifactId>
Expand All @@ -27,6 +31,10 @@
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-dao</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-dao-java</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-dao-v2</artifactId>
Expand Down Expand Up @@ -55,6 +63,10 @@
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-rest</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-rest-java</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-rest-v2</artifactId>
Expand All @@ -67,6 +79,10 @@
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-ui-angular</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-ui-angular-java</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-ui-angular-v2</artifactId>
Expand Down
24 changes: 24 additions & 0 deletions components/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -237,18 +237,22 @@

<!-- Templates -->
<module>template/template-application-angular</module>
<module>template/template-application-angular-java</module>
<module>template/template-application-angular-v2</module>
<module>template/template-application-dao</module>
<module>template/template-application-dao-java</module>
<module>template/template-application-dao-v2</module>
<module>template/template-application-data</module>
<module>template/template-application-data-v2</module>
<module>template/template-application-feed</module>
<module>template/template-application-feed-v2</module>
<module>template/template-application-odata</module>
<module>template/template-application-rest</module>
<module>template/template-application-rest-java</module>
<module>template/template-application-rest-v2</module>
<module>template/template-application-schema</module>
<module>template/template-application-ui-angular</module>
<module>template/template-application-ui-angular-java</module>
<module>template/template-application-ui-angular-v2</module>
<module>template/template-bpm</module>
<module>template/template-camel</module>
Expand Down Expand Up @@ -1360,6 +1364,11 @@
<artifactId>dirigible-components-template-application-angular</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-angular-java</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-angular-v2</artifactId>
Expand All @@ -1370,6 +1379,11 @@
<artifactId>dirigible-components-template-application-dao</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-dao-java</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-dao-v2</artifactId>
Expand Down Expand Up @@ -1405,6 +1419,11 @@
<artifactId>dirigible-components-template-application-rest</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-rest-java</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-rest-v2</artifactId>
Expand All @@ -1420,6 +1439,11 @@
<artifactId>dirigible-components-template-application-ui-angular</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-ui-angular-java</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-template-application-ui-angular-v2</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
/**
* Copyright (c) 2010-2026 Eclipse Dirigible contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-FileCopyrightText: Eclipse Dirigible contributors
* SPDX-License-Identifier: EPL-2.0
*/
/* open-sans-latin-300-normal */
@font-face {
font-family: "Open Sans";
Expand Down
20 changes: 20 additions & 0 deletions components/template/template-application-angular-java/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<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">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-parent</artifactId>
<version>13.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<name>Components - Template - Application (Angular) - Java</name>
<artifactId>dirigible-components-template-application-angular-java</artifactId>
<packaging>jar</packaging>

<properties>
<license.header.location>../generation-header.txt</license.header.location>
</properties>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"guid": "template-application-angular-java",
"dependencies": [
{
"guid": "template-application-schema"
},
{
"guid": "template-application-dao-java"
},
{
"guid": "template-application-rest-java"
},
{
"guid": "template-application-ui-angular-java"
}
],
"actions": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"extensionPoint": "platform-templates",
"module": "template-application-angular-java/template/template.js",
"description": "Application Template (with Angular UI) - Java"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Generated by Eclipse Dirigible based on model and template.
*
* Do not modify the content as it may be re-generated again.
*/
import * as schemaTemplateManager from "template-application-schema/template/template";
import * as uiAngularjsTemplateManager from "template-application-ui-angular-java/template/template";
import * as generateUtils from "service-generate/template/generateUtils";
import * as parameterUtils from "service-generate/template/parameterUtils";

export function generate(model, parameters) {
model = JSON.parse(model).model;
let templateSources = getTemplate(parameters).sources;
parameters.javaRuntime = true;
parameterUtils.process(model, parameters);
return generateUtils.generateFiles(model, parameters, templateSources);
};

export function getTemplate(parameters) {
let schemaTemplate = schemaTemplateManager.getTemplate(parameters);
let uiAngularjsTemplate = uiAngularjsTemplateManager.getTemplate(parameters);

let templateSources = [];
templateSources = templateSources.concat(schemaTemplate.sources);
templateSources = templateSources.concat(uiAngularjsTemplate.sources);

return {
name: "Application - Full Stack - Java",
description: "Full stack application with a Database Schema, Java REST Services and an AngularJS UI",
extension: "model",
sources: templateSources,
parameters: parameterUtils.getUniqueParameters(schemaTemplate.parameters, uiAngularjsTemplate.parameters)
};
};
24 changes: 24 additions & 0 deletions components/template/template-application-dao-java/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<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">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.eclipse.dirigible</groupId>
<artifactId>dirigible-components-parent</artifactId>
<version>13.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<name>Components - Template - Application - DAO - Java</name>
<artifactId>dirigible-components-template-application-dao-java</artifactId>
<packaging>jar</packaging>

<properties>
<profile.content.phase>generate-sources</profile.content.phase>
<content.repository.name>template-application-dao-java</content.repository.name>
<content.project.name>template-application-dao-java</content.project.name>

<license.header.location>../generation-header.txt</license.header.location>
</properties>

</project>
Loading
Loading