Skip to content

Commit 1a43df8

Browse files
Basic builder
Signed-off-by: Anders Swanson <anders.swanson@oracle.com>
1 parent 2ae791e commit 1a43df8

File tree

14 files changed

+664
-0
lines changed

14 files changed

+664
-0
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!-- Copyright (c) 2023, 2024, Oracle and/or its affiliates. -->
3+
<!-- Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. -->
4+
<project xmlns="http://maven.apache.org/POM/4.0.0"
5+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
7+
<modelVersion>4.0.0</modelVersion>
8+
<parent>
9+
<artifactId>oracle-spring-boot-starters</artifactId>
10+
<groupId>com.oracle.database.spring</groupId>
11+
<version>25.2.0</version>
12+
<relativePath>../pom.xml</relativePath>
13+
</parent>
14+
15+
<artifactId>oracle-spring-boot-json-relational-duality-views</artifactId>
16+
<version>25.2.0</version>
17+
18+
<name>Oracle Spring Boot - JSON Relational Duality Views</name>
19+
<description>Spring Boot for Oracle Database JSON Relational duality Views</description>
20+
<url>https://github.com/oracle/spring-cloud-oracle/tree/main/database/starters/oracle-spring-boot-json-relational-duality-views</url>
21+
22+
<organization>
23+
<name>Oracle America, Inc.</name>
24+
<url>https://www.oracle.com</url>
25+
</organization>
26+
27+
<developers>
28+
<developer>
29+
<name>Oracle</name>
30+
<email>obaas_ww at oracle.com</email>
31+
<organization>Oracle America, Inc.</organization>
32+
<organizationUrl>https://www.oracle.com</organizationUrl>
33+
</developer>
34+
</developers>
35+
36+
<licenses>
37+
<license>
38+
<name>The Universal Permissive License (UPL), Version 1.0</name>
39+
<url>https://oss.oracle.com/licenses/upl/</url>
40+
<distribution>repo</distribution>
41+
</license>
42+
</licenses>
43+
44+
<scm>
45+
<url>https://github.com/oracle/spring-cloud-oracle</url>
46+
<connection>scm:git:https://github.com/oracle/spring-cloud-oracle.git</connection>
47+
<developerConnection>scm:git:git@github.com:oracle/spring-cloud-oracle.git</developerConnection>
48+
</scm>
49+
50+
<dependencies>
51+
<dependency>
52+
<groupId>com.oracle.database.spring</groupId>
53+
<artifactId>oracle-spring-boot-starter-ucp</artifactId>
54+
<version>${project.version}</version>
55+
</dependency>
56+
57+
<dependency>
58+
<groupId>org.springframework.boot</groupId>
59+
<artifactId>spring-boot-starter-jdbc</artifactId>
60+
</dependency>
61+
62+
<dependency>
63+
<groupId>org.springframework.boot</groupId>
64+
<artifactId>spring-boot-starter-data-jpa</artifactId>
65+
</dependency>
66+
67+
68+
<dependency>
69+
<groupId>jakarta.json</groupId>
70+
<artifactId>jakarta.json-api</artifactId>
71+
</dependency>
72+
73+
<dependency>
74+
<groupId>org.eclipse.parsson</groupId>
75+
<artifactId>parsson</artifactId>
76+
</dependency>
77+
78+
<dependency>
79+
<groupId>jakarta.json.bind</groupId>
80+
<artifactId>jakarta.json.bind-api</artifactId>
81+
</dependency>
82+
83+
<dependency>
84+
<groupId>org.eclipse</groupId>
85+
<artifactId>yasson</artifactId>
86+
</dependency>
87+
88+
<dependency>
89+
<groupId>org.testcontainers</groupId>
90+
<artifactId>junit-jupiter</artifactId>
91+
<scope>test</scope>
92+
</dependency>
93+
94+
<dependency>
95+
<groupId>org.testcontainers</groupId>
96+
<artifactId>testcontainers</artifactId>
97+
<scope>test</scope>
98+
</dependency>
99+
100+
<dependency>
101+
<groupId>org.testcontainers</groupId>
102+
<artifactId>oracle-free</artifactId>
103+
<scope>test</scope>
104+
</dependency>
105+
106+
<dependency>
107+
<groupId>org.springframework.boot</groupId>
108+
<artifactId>spring-boot-starter-test</artifactId>
109+
<scope>test</scope>
110+
</dependency>
111+
112+
<dependency>
113+
<groupId>org.springframework.boot</groupId>
114+
<artifactId>spring-boot-testcontainers</artifactId>
115+
<scope>test</scope>
116+
</dependency>
117+
</dependencies>
118+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.oracle.spring.json.duality.builder;
2+
3+
import java.sql.Connection;
4+
import java.sql.SQLException;
5+
import java.sql.Statement;
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
9+
import javax.sql.DataSource;
10+
import org.springframework.beans.factory.DisposableBean;
11+
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
12+
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
13+
import org.springframework.stereotype.Component;
14+
15+
@Component
16+
public final class DualityViewBuilder implements DisposableBean {
17+
private final DataSource dataSource;
18+
private final boolean isShowSql;
19+
private final RootSnippet rootSnippet;
20+
private final List<String> dualityViews = new ArrayList<>();
21+
22+
public DualityViewBuilder(DataSource dataSource,
23+
JpaProperties jpaProperties,
24+
HibernateProperties hibernateProperties) {
25+
this.dataSource = dataSource;
26+
this.isShowSql = jpaProperties.isShowSql();
27+
this.rootSnippet = RootSnippet.fromDdlAuto(
28+
hibernateProperties.getDdlAuto()
29+
);
30+
}
31+
32+
void build(Class<?> javaType, JsonRelationalDualityView dvAnnotation) {
33+
if (rootSnippet.equals(RootSnippet.NONE)) {
34+
return;
35+
}
36+
ViewEntity ve = new ViewEntity(javaType, new StringBuilder(), rootSnippet, 0);
37+
String ddl = ve.build().toString();
38+
if (isShowSql) {
39+
// TODO: log sql statement
40+
}
41+
if (rootSnippet.equals(RootSnippet.VALIDATE)) {
42+
// TODO: handle duality view validation
43+
return;
44+
}
45+
runDDL(ddl);
46+
}
47+
48+
private void runDDL(String ddl) {
49+
try (Connection conn = dataSource.getConnection();
50+
Statement stmt = conn.createStatement()) {
51+
stmt.executeUpdate(ddl);
52+
} catch (SQLException e) {
53+
throw new RuntimeException(e);
54+
}
55+
}
56+
57+
58+
@Override
59+
public void destroy() throws Exception {
60+
if (rootSnippet.equals(RootSnippet.CREATE_DROP) && !dualityViews.isEmpty()) {
61+
final String dropView = """
62+
drop view %s
63+
""";
64+
try (Connection conn = dataSource.getConnection();
65+
Statement stmt = conn.createStatement()) {
66+
for (String view : dualityViews) {
67+
stmt.execute(dropView.formatted(view));
68+
}
69+
}
70+
}
71+
}
72+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.oracle.spring.json.duality.builder;
2+
3+
import java.util.Set;
4+
5+
import jakarta.annotation.PostConstruct;
6+
import jakarta.persistence.EntityManager;
7+
import jakarta.persistence.metamodel.EntityType;
8+
import org.springframework.stereotype.Component;
9+
10+
@Component
11+
final public class DualityViewScanner {
12+
private final DualityViewBuilder dualityViewBuilder;
13+
private final EntityManager entityManager;
14+
15+
public DualityViewScanner(DualityViewBuilder dualityViewBuilder, EntityManager entityManager) {
16+
this.dualityViewBuilder = dualityViewBuilder;
17+
this.entityManager = entityManager;
18+
}
19+
20+
@PostConstruct
21+
public void scan() {
22+
Set<EntityType<?>> entities = entityManager.getMetamodel().getEntities();
23+
for (EntityType<?> entityType : entities) {
24+
Class<?> javaType = entityType.getJavaType();
25+
JsonRelationalDualityView dvAnnotation = javaType.getAnnotation(JsonRelationalDualityView.class);
26+
if (dvAnnotation != null) {
27+
dualityViewBuilder.build(javaType, dvAnnotation);
28+
}
29+
}
30+
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.oracle.spring.json.duality.builder;
2+
3+
import java.lang.annotation.Documented;
4+
import java.lang.annotation.ElementType;
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.RetentionPolicy;
7+
import java.lang.annotation.Target;
8+
9+
@Documented
10+
@Target({ElementType.TYPE})
11+
@Retention(RetentionPolicy.RUNTIME)
12+
public @interface JsonRelationalDualityView {
13+
String name() default "";
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.oracle.spring.json.duality.builder;
2+
3+
public enum RootSnippet {
4+
NONE(null),
5+
VALIDATE(null),
6+
CREATE("create force editionable json relational duality view"),
7+
CREATE_DROP(CREATE.snippet),
8+
UPDATE("create or replace force editionable json relational duality view");
9+
private final String snippet;
10+
11+
RootSnippet(String snippet) {
12+
this.snippet = snippet;
13+
}
14+
15+
public String getSnippet() {
16+
return snippet;
17+
}
18+
19+
public static RootSnippet fromDdlAuto(String ddlAuto) {
20+
if (ddlAuto == null) {
21+
return NONE;
22+
}
23+
// none, validate, update, create, and create-drop
24+
return switch (ddlAuto) {
25+
case "none" -> NONE;
26+
case "validate" -> VALIDATE;
27+
case "create" -> CREATE;
28+
case "create_drop" -> CREATE_DROP;
29+
case "update" -> UPDATE;
30+
default -> throw new IllegalStateException("Unexpected value: " + ddlAuto);
31+
};
32+
}
33+
}

0 commit comments

Comments
 (0)