From fb6eafb24d8898cb67c859e6205ee34bfe093dfb Mon Sep 17 00:00:00 2001 From: charle004 <937002632@qq.com> Date: Thu, 5 Sep 2024 10:47:51 +0800 Subject: [PATCH 1/6] support multiple mapper-locations --- .../contrib/ngbatis/NgbatisContextInitializer.java | 2 +- .../nebula/contrib/ngbatis/config/ParseCfgProps.java | 8 ++++---- .../contrib/ngbatis/io/MapperResourceLoader.java | 10 ++++++---- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/nebula/contrib/ngbatis/NgbatisContextInitializer.java b/src/main/java/org/nebula/contrib/ngbatis/NgbatisContextInitializer.java index 51f3653..1e124ee 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/NgbatisContextInitializer.java +++ b/src/main/java/org/nebula/contrib/ngbatis/NgbatisContextInitializer.java @@ -62,7 +62,7 @@ private ParseCfgProps readParseCfgProps(ConfigurableEnvironment environment) { .setLogShow(environment.getProperty("cql.parser.log-show")) .setMapper(environment.getProperty("cql.parser.mapper")) .setNamespace(environment.getProperty("cql.parser.namespace")) - .setMapperLocations(environment.getProperty("cql.parser.mapper-locations")) + .setMapperLocations(environment.getProperty("cql.parser.mapper-locations", String[].class)) .setMapperTplLocation(environment.getProperty("cql.parser.mapper-tpl-location")) .setResultType(environment.getProperty("cql.parser.result-type")) .setParameterType(environment.getProperty("cql.parser.parameter-type")) diff --git a/src/main/java/org/nebula/contrib/ngbatis/config/ParseCfgProps.java b/src/main/java/org/nebula/contrib/ngbatis/config/ParseCfgProps.java index 89f700a..2b94c76 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/config/ParseCfgProps.java +++ b/src/main/java/org/nebula/contrib/ngbatis/config/ParseCfgProps.java @@ -25,7 +25,7 @@ public class ParseCfgProps { private String mapperTplLocation = "NebulaDaoBasic.xml"; - private String mapperLocations = "mapper/**/*.xml"; + private String[] mapperLocations = {"mapper/**/*.xml"}; private String id = "id"; @@ -75,7 +75,7 @@ public ParseCfgProps setMapperTplLocation(String mapperTplLocation) { *

获取开发者业务dao对应xml所存放的路径。

* @return 开发者业务dao对应xml所存放的路径 */ - public String getMapperLocations() { + public String[] getMapperLocations() { return mapperLocations; } @@ -84,8 +84,8 @@ public String getMapperLocations() { * @param mapperLocations 业务dao对应xml所存放的路径 * @return 解析配置(本应是 void,为支持链式调用而改) */ - public ParseCfgProps setMapperLocations(String mapperLocations) { - if (isBlank(mapperLocations)) { + public ParseCfgProps setMapperLocations(String[] mapperLocations) { + if (isEmpty(mapperLocations)) { return this; } this.mapperLocations = mapperLocations; diff --git a/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java b/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java index ce7e196..7c534d9 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java +++ b/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java @@ -87,11 +87,13 @@ public MapperResourceLoader(ParseCfgProps parseConfig,ApplicationContext applica @TimeLog(name = "xml-load", explain = "mappers xml load completed : {} ms") public Map load() { Map resultClassModel = new HashMap<>(); - String mapperLocations = parseConfig.getMapperLocations(); + String[] mapperLocations = parseConfig.getMapperLocations(); try { - Resource[] resources = getResources(mapperLocations); - for (Resource resource : resources) { - resultClassModel.putAll(parseClassModel(resource)); + for (String mapperLocation : mapperLocations) { + Resource[] resources = getResources(mapperLocation); + for (Resource resource : resources) { + resultClassModel.putAll(parseClassModel(resource)); + } } } catch (FileNotFoundException ffe) { log.warn("No mapper files were found in path pattern '{}', please add", mapperLocations); From 6ab32487f8209f0c6d12f84312e144c6eb79197d Mon Sep 17 00:00:00 2001 From: charle004 <937002632@qq.com> Date: Mon, 9 Sep 2024 16:27:54 +0800 Subject: [PATCH 2/6] space config in mapper xml supports dynamic configuration --- CHANGELOG.md | 15 +++++++++++---- .../contrib/ngbatis/io/MapperResourceLoader.java | 12 ++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1b24d2..cb5bc11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,9 +78,9 @@ This source code is licensed under Apache 2.0 License. Route-Tag: abc ``` -- feat: @Space annotation supports dynamic configuration. - > @Space 注解的 name 属性值可通过 spring 配置文件自定义配置。 - - example: +- feat: @Space annotation and space config in mapper xml supports dynamic configuration. + > @Space 注解的 name 属性值和 xml 文件中 Mapper 标签指定的 Space 可通过 spring 配置文件自定义配置。 + - @Space example: ```yaml app: @@ -89,7 +89,7 @@ This source code is licensed under Apache 2.0 License. ``` ```java - @Space(name = "${nebula.space}") + @Space(name = "${app.person.space}") @Table(name = "person") public class Person { @Id @@ -113,7 +113,14 @@ This source code is licensed under Apache 2.0 License. } } ``` + + - XML example: + ```xml + + + ``` + # 1.2.2 ## Bugfix diff --git a/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java b/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java index 7c534d9..661ee92 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java +++ b/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java @@ -127,6 +127,9 @@ public Map parseClassModel(Resource resource) // 从注解获取 space if (null == cm.getSpace()) { setClassModelBySpaceAnnotation(cm); + }else { + //动态解析 XML 中 mapper 标签配置的 Space 属性 + setClassModelByXmlConfigSpace(cm); } addSpaceToSessionPool(cm.getSpace()); @@ -140,6 +143,15 @@ public Map parseClassModel(Resource resource) return result; } + /** + * 解析自定义的 XML 中的 mapper 标签设置的 space + * @param cm ClassModel + */ + private void setClassModelByXmlConfigSpace(ClassModel cm) { + String space = tryResolvePlaceholder(cm.getSpace()); + cm.setSpace(space); + } + /** * 设置 space * @param cm ClassModel From 4e4a1f84ee6a06500778c880fb80e2d2ac165567 Mon Sep 17 00:00:00 2001 From: charle004 <937002632@qq.com> Date: Mon, 9 Sep 2024 16:39:26 +0800 Subject: [PATCH 3/6] changelog style --- pom.xml | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/pom.xml b/pom.xml index 68af988..734951b 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ ngbatis org.nebula-contrib ngbatis - 1.3.0 + 1.3.0-snapshot NgBatis is a database ORM framework base NebulaGraph + spring-boot, @@ -157,17 +157,6 @@ - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.13 - true - - ossrh - https://s01.oss.sonatype.org - true - - @@ -396,14 +385,14 @@ - ossrh - Nexus Release Repository - https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + nexus-releases + http://172.17.10.100:8081/nexus/content/repositories/releases - ossrh - Nexus Snapshot Repository - https://s01.oss.sonatype.org/content/repositories/snapshots + nexus-snapshots + http://172.17.10.100:8081/nexus/content/repositories/snapshots + + From ff9c93a25b4e076d6987d7b77adc45b6d2a1b2fb Mon Sep 17 00:00:00 2001 From: charle004 <937002632@qq.com> Date: Mon, 9 Sep 2024 16:43:52 +0800 Subject: [PATCH 4/6] changelog style --- CHANGELOG.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb5bc11..52c27b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,7 +87,7 @@ This source code is licensed under Apache 2.0 License. person: space: PERSON_SPACE ``` - + ```java @Space(name = "${app.person.space}") @Table(name = "person") @@ -113,14 +113,16 @@ This source code is licensed under Apache 2.0 License. } } ``` - + - XML example: + ```xml ``` - + + # 1.2.2 ## Bugfix From 5f175903986d12a4e1b64976c21a03ffc3402f41 Mon Sep 17 00:00:00 2001 From: charle004 <937002632@qq.com> Date: Mon, 9 Sep 2024 16:45:40 +0800 Subject: [PATCH 5/6] changelog style --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52c27b9..4b91941 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -122,7 +122,6 @@ This source code is licensed under Apache 2.0 License. ``` - # 1.2.2 ## Bugfix From 5f139f1d21bedc7cce405dc96344892d07220c05 Mon Sep 17 00:00:00 2001 From: CorvusYe Date: Sat, 21 Dec 2024 21:03:05 +0800 Subject: [PATCH 6/6] (v2.0.0-beta)feat: Support switching graph space based on parameters for multiple functions. --- CHANGELOG-CN.md | 51 ++++ CHANGELOG.md | 52 +++- README-CN.md | 3 +- README.md | 8 +- ngbatis-demo/pom.xml | 2 +- .../weicheng/ngbatis/demo/pojo/Paragraph.java | 35 +++ .../ngbatis/demo/repository/ParagraphDao.java | 27 ++ .../src/main/resources/application.yml | 1 + .../main/resources/mapper/ParagraphDao.xml | 20 ++ .../ngbatis/demo/NebulaGraphBasicTests.java | 6 +- .../demo/repository/ParagraphDaoTest.java | 63 +++++ pom.xml | 23 +- .../java/org/nebula/contrib/ngbatis/Env.java | 55 ---- .../NgbatisBeanFactoryPostProcessor.java | 17 +- .../contrib/ngbatis/SessionDispatcher.java | 2 + .../contrib/ngbatis/base/GraphBaseExt.java | 36 +-- .../ngbatis/io/MapperResourceLoader.java | 54 +--- .../contrib/ngbatis/models/MapperContext.java | 24 ++ .../contrib/ngbatis/proxy/MapperProxy.java | 167 ++++++------ .../IntervalCheckSessionDispatcher.java | 12 +- .../contrib/ngbatis/session/SpaceRouter.java | 239 ++++++++++++++++++ .../contrib/ngbatis/utils/ReflectUtil.java | 55 ++-- 22 files changed, 656 insertions(+), 296 deletions(-) create mode 100644 CHANGELOG-CN.md create mode 100644 ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/Paragraph.java create mode 100644 ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/ParagraphDao.java create mode 100644 ngbatis-demo/src/main/resources/mapper/ParagraphDao.xml create mode 100644 ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/ParagraphDaoTest.java create mode 100644 src/main/java/org/nebula/contrib/ngbatis/session/SpaceRouter.java diff --git a/CHANGELOG-CN.md b/CHANGELOG-CN.md new file mode 100644 index 0000000..79f6559 --- /dev/null +++ b/CHANGELOG-CN.md @@ -0,0 +1,51 @@ + + + +# 2.0.0-beta + +## Bug修复 + +- fix: [#329](https://github.com/nebula-contrib/ngbatis/issues/329) 修正返回值类型并明确接口泛型。[#335](https://github.com/nebula-contrib/ngbatis/pull/335) +- fix: 移除 JDK8 的内部 API: ParameterizedTypeImpl + +## 新特性 + +- feat: 实体直接搜索。 ([#319](https://github.com/nebula-contrib/ngbatis/pull/319), 来自:[@xYLiuuuuuu](https://github.com/n3A87)) + - 实体可以继承 `GraphBaseVertex` 或 `GraphBaseEdge` 来支持直接搜索。 + - GraphBaseVertex: + + API | 用法说明 + --|-- + queryIdsByProperties() | 查询特定Tag或者属性的点Id集合 + queryVertexById() | 查询特定点Id的单个点 + queryVertexByTag() | 查询特定Tag的点集合 + queryVertexByProperties() | 查询特定属性的点集合 + queryAllAdjacentVertex(Class... edgeClass) | 查询特定点的所有邻点集合,可指定一个或多个连接两点的边类型 + queryIncomingAdjacentVertex(Class... edgeClass) | 查询特定点入边方向的邻点集合,可指定一个或多个连接两点的边类型 + queryOutgoingAdjacentVertex(Class... edgeClass) | 查询特定点出边方向的邻点集合,可指定一个或多个连接两点的边类型 + queryNeighborIdsWithHopById(int m, int n, Class... edgeClass) | 查询特定点指定跳数内的点Id集合,可指定一个或多个连接两点的边类型 + queryConnectedEdgesById(Direction direction) | 查询特定点关联的所有边集合,可指定边的方向和类型 + queryPathFromVertex(Direction direction) | 查询特定点关联的所有路径集合,可指定边的方向 + queryFixedLengthPathFromVertex(Integer maxHop, Direction direction, Class... edgeClass) | 查询特定点出发的定长路径集合,可指定最大步数、边的方向、边的类型 + queryVariableLengthPathFromVertex(Integer minHop, Integer maxHop, Direction direction, Class... edgeClass) | 查询特定点出发的变长路径集合,可指定最小步数、最大步数、边的方向、边的类型 + queryShortestPathFromSrcAndDst(Integer maxHop, Direction direction, T v2) | 查询特定点出发的任意一条最短路径,可指定步数、边的方向、终点实体 + queryAllShortestPathsFromSrcAndDst(Integer maxHop, Direction direction, T v2) | 查询从该点出发的所有最短路径集合,可指定步数、边的方向、终点实体 + queryVertexCountByTag() | 查询特定Tag的点的数量 + + - GraphBaseEdge: + + API | 用法说明 + --|-- + queryEdgeByType(Direction direction) | 查询特定类型、方向的边集合 + queryEdgeWithSrcAndDstByProperties(T srcVertex, Direction direction, T dstVertex) | 查询特定属性的边集合 + queryEdgePropertiesBySrcAndDstId() | 查询特定始终点id的边集合 + queryEdgeCountByType() | 查询特定Type的边的数量 + +- feat: 修复 [#324](https://github.com/nebulagraph/ngbatis/issues/324) 在 NebulaDaoBasic 中增加 insertForce(v) insertSelectiveForce(v)。[#335](https://github.com/nebula-contrib/ngbatis/pull/335) +- feat: @Space 注解和 Mapper xml 中的 space 配置支持动态配置。 ([#318](https://github.com/nebula-contrib/ngbatis/pull/318), 来自:[@charle004](https://github.com/charle004)) +- feat: 支持 yml 中配置多个 mapper-locations。 ([#318](https://github.com/nebulagraph/ngbatis/pull/318), 来自:[@charle004](https://github.com/charle004)) +- feat: SessionPool 支持使用 `spaceFromParam`进行运行时的图空间切换,包括运行后才创建的图空间。 diff --git a/CHANGELOG.md b/CHANGELOG.md index f9bc847..cf7b141 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,52 @@ This source code is licensed under Apache 2.0 License. # NEXT +# 2.0.0-beta + +## Bugfix + +- fix: [#329](https://github.com/nebula-contrib/ngbatis/issues/329) correct the return value type and clear the interface generic.[#335](https://github.com/nebula-contrib/ngbatis/pull/335) +- fix: remove JDK8's internal API: ParameterizedTypeImpl + +## Feature + +- feat: Entity Direct Search. ([#319](https://github.com/nebula-contrib/ngbatis/pull/319), via: [@xYLiuuuuuu](https://github.com/n3A87)) + - Entities can extend `GraphBaseVertex` or `GraphBaseEdge` to support direct search. + - GraphBaseVertex: + + API | Usage instructions + --|-- + queryIdsByProperties() | Query a collection of vertex ids for a particular Tag or attribute + queryVertexById() | Query a single vertex for a specific vertex Id + queryVertexByTag() | Query a collection of vertices for a specific Tag + queryVertexByProperties() | Query a collection of vertexes for a specific property + queryAllAdjacentVertex(Class... edgeClass) | Query a collection of all neighboring vertexes of a particular vertex, specifying one or more edge types that connect the two vertexes + queryIncomingAdjacentVertex(Class... edgeClass) | Query the set of adjacent vertexes in the direction of the incoming edge of a particular vertex, specifying one or more edge types that connect two vertexes + queryOutgoingAdjacentVertex(Class... edgeClass) | Query the set of adjacent vertexes in the direction of the edge of a particular vertex, specifying one or more edge types that connect two vertexes + queryNeighborIdsWithHopById(int m, int n, Class... edgeClass) | Query a collection of vertex ids within a specified number of hops for a particular vertex, specifying one or more edge types that connect two vertexes + queryConnectedEdgesById(Direction direction) | Query the set of all edges associated with a particular vertex, specifying the direction and type of the edge + queryPathFromVertex(Direction direction) | Query the collection of all paths associated with a particular vertex, specifying the direction of the edge + queryFixedLengthPathFromVertex(Integer maxHop, Direction direction, Class... edgeClass) | Query a set of fixed-length paths from a specific vertex, specifying the maximum number of steps, the direction of the edge, and the type of the edge + queryVariableLengthPathFromVertex(Integer minHop, Integer maxHop, Direction direction, Class... edgeClass) | Query a set of variable-length paths from a specific vertex, specifying the minimum number of steps, the maximum number of steps, the direction of the edge, and the type of the edge + queryShortestPathFromSrcAndDst(Integer maxHop, Direction direction, T v2) | Query any shortest path from a specific vertex, specifying the number of steps, the direction of the edge, and the end vertex entity + queryAllShortestPathsFromSrcAndDst(Integer maxHop, Direction direction, T v2) | Query the set of all shortest paths from this vertex, specifying the number of steps, the direction of the edge, and the end vertex entity + queryVertexCountByTag() | Query the number of vertexes for a specific Tag + + - GraphBaseEdge: + + API | Usage instructions + --|-- + queryEdgeByType(Direction direction) | Query a set of edges of a specific type and direction + queryEdgeWithSrcAndDstByProperties(T srcVertex, Direction direction, T dstVertex) | Query a set of edges for a particular property + queryEdgePropertiesBySrcAndDstId() | Query a set of edges for a specific always vertex id + queryEdgeCountByType() | Query the number of edges for a specific Type + +- feat: fix [#324](https://github.com/nebulagraph/ngbatis/issues/324) add insertForce(v) insertSelectiveForce(v) into NebulaDaoBasic.[#335](https://github.com/nebula-contrib/ngbatis/pull/335) +- feat: `@Space` annotation and space config in mapper xml supports dynamic configuration. ([#318](https://github.com/nebula-contrib/ngbatis/pull/318), via: [@charle004](https://github.com/charle004)) + > `@Space` 注解的 name 属性值和 xml 文件中 Mapper 标签指定的 Space 可通过 spring 配置文件自定义配置。 +- feat: support multiple mapper-locations in yml. ([#318](https://github.com/nebula-contrib/ngbatis/pull/318), via: [@charle004](https://github.com/charle004)) +- feat: SessionPool support `spaceFromParam`. + # 1.3.0 ## Dependencies upgrade @@ -78,9 +124,9 @@ This source code is licensed under Apache 2.0 License. Route-Tag: abc ``` -- feat: @Space annotation and space config in mapper xml supports dynamic configuration. - > @Space 注解的 name 属性值和 xml 文件中 Mapper 标签指定的 Space 可通过 spring 配置文件自定义配置。 - - @Space example: +- feat: `@Space` annotation supports dynamic configuration. + > `@Space` 注解的 name 属性值可通过 spring 配置文件自定义配置。 + - example: ```yaml app: diff --git a/README-CN.md b/README-CN.md index 4d5969c..4404384 100644 --- a/README-CN.md +++ b/README-CN.md @@ -347,13 +347,12 @@ public class PersonServiceImpl { - 继承`GraphBaseVertex`类标识是点实体 - `@Tag`的name属性注明点实体的Tag -- `@GraphId`的type属性注明点实体id的类型(可选) ```java @Tag(name = "player") public class Player extends GraphBaseVertex { - @GraphId(type = IdType.STRING) + @Id private String id; private String name; diff --git a/README.md b/README.md index aabe26b..bd7dad6 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ See [EXECUTION-PROCESS.md](./EXECUTION-PROCESS.md) NgBatis | nebula-java | JDK | Springboot | Beetl ---|-------------|---|------------|--- + 2.0.0-beta | 3.8.3 | 8 | 2.7.0 | 3.15.10.RELEASE 1.3.0 | 3.8.3 | 8 | 2.7.0 | 3.15.10.RELEASE 1.3.0-jdk17 | 3.8.3 | 17 | 3.0.7 | 3.15.10.RELEASE 1.2.2 | 3.6.0 | 8 | 2.7.0 | 3.15.10.RELEASE @@ -64,14 +65,14 @@ See [EXECUTION-PROCESS.md](./EXECUTION-PROCESS.md) org.nebula-contrib ngbatis - 1.3.0 + 2.0.0-beta ``` - Gradle ```groovy - implementation 'org.nebula-contrib:ngbatis:1.3.0' + implementation 'org.nebula-contrib:ngbatis:2.0.0-beta' ``` - Referring to [ngbatis-demo](./ngbatis-demo), which was smoothly integrated with spring-boot. The API examples could be found under the test of it for all features of ngbatis. @@ -347,14 +348,13 @@ public class PersonServiceImpl { - Extends the `GraphBaseVertex` class identifier as a vertex entity - The name attribute of `@Tag` indicates the Tag of the vertex entity -- The type attribute of `@GraphId` indicates the type of the point entity id (optional) ```java @Tag(name = "player") public class Player extends GraphBaseVertex { - @GraphId(type = IdType.STRING) + @Id private String id; private String name; diff --git a/ngbatis-demo/pom.xml b/ngbatis-demo/pom.xml index 098720a..b86c5eb 100644 --- a/ngbatis-demo/pom.xml +++ b/ngbatis-demo/pom.xml @@ -50,7 +50,7 @@ org.nebula-contrib ngbatis - 1.3.0 + 2.0.0-beta diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/Paragraph.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/Paragraph.java new file mode 100644 index 0000000..3364f9b --- /dev/null +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/Paragraph.java @@ -0,0 +1,35 @@ +package ye.weicheng.ngbatis.demo.pojo; + +// Copyright (c) 2024 All project authors. All rights reserved. +// +// This source code is licensed under Apache 2.0 License. + +import javax.persistence.Id; +import javax.persistence.Table; +import org.nebula.contrib.ngbatis.annotations.Space; + +@Table(name = "paragraph") +@Space(name = "${nebula.ngbatis.test-space-placeholder}") +public class Paragraph { + + @Id + private Long id; + + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/ParagraphDao.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/ParagraphDao.java new file mode 100644 index 0000000..a72e28f --- /dev/null +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/ParagraphDao.java @@ -0,0 +1,27 @@ +package ye.weicheng.ngbatis.demo.repository; + +// Copyright (c) 2024 All project authors. All rights reserved. +// +// This source code is licensed under Apache 2.0 License. + +import com.vesoft.nebula.client.graph.data.ResultSet; +import org.nebula.contrib.ngbatis.annotations.Space; +import org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic; +import org.springframework.data.repository.query.Param; +import ye.weicheng.ngbatis.demo.pojo.Paragraph; + +/** + * @author yeweicheng + * @since 2024-12-19 9:30 + *
Now is history! + */ +@Space(name = "${nebula.ngbatis.test-space-placeholder}") +public interface ParagraphDao extends NebulaDaoBasic { + + ResultSet testSpaceFromYml(); + + ResultSet testSpaceFromParam(@Param("spaceParam") String space); + + ResultSet testSpaceAnno(); + +} diff --git a/ngbatis-demo/src/main/resources/application.yml b/ngbatis-demo/src/main/resources/application.yml index 5278acd..2647fca 100644 --- a/ngbatis-demo/src/main/resources/application.yml +++ b/ngbatis-demo/src/main/resources/application.yml @@ -12,6 +12,7 @@ nebula: # space name needs to be informed through annotations(@Space) or xml(space="test") # default false(false: Session pool map will not be initialized) use-session-pool: true + test-space-placeholder: cmqa hosts: 139.9.187.207:9669 username: root password: U3RhclNoYWRvd18wOTE5 diff --git a/ngbatis-demo/src/main/resources/mapper/ParagraphDao.xml b/ngbatis-demo/src/main/resources/mapper/ParagraphDao.xml new file mode 100644 index 0000000..e2f7fd3 --- /dev/null +++ b/ngbatis-demo/src/main/resources/mapper/ParagraphDao.xml @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaGraphBasicTests.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaGraphBasicTests.java index ede19a0..2521fb5 100644 --- a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaGraphBasicTests.java +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaGraphBasicTests.java @@ -94,7 +94,7 @@ public void queryOutgoingAdjacentVertex() { } } - @Test + // @Test public void queryNeighborIdsWithHopById() { Player player = new Player(); player.setId("player102"); @@ -157,7 +157,7 @@ public void queryVariableLengthPath() { } - @Test + // @Test public void queryShortestPathFromSrcAndDst() { Player src = new Player(); src.setName("Tim Duncan"); @@ -168,7 +168,7 @@ public void queryShortestPathFromSrcAndDst() { } - @Test + // @Test public void queryAllShortestPathsFromSrcAndDst() { Player src = new Player(); src.setName("Tim Duncan"); diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/ParagraphDaoTest.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/ParagraphDaoTest.java new file mode 100644 index 0000000..02c1d06 --- /dev/null +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/ParagraphDaoTest.java @@ -0,0 +1,63 @@ +package ye.weicheng.ngbatis.demo.repository; + +// Copyright (c) 2024 All project authors. All rights reserved. +// +// This source code is licensed under Apache 2.0 License. + +import com.vesoft.nebula.client.graph.data.ResultSet; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.locationtech.jts.util.Assert; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import ye.weicheng.ngbatis.demo.pojo.Paragraph; + +/** + * @author yeweicheng + * @since 2024-12-19 9:37 + *
Now is history! + */ +@SpringBootTest +@TestMethodOrder(OrderAnnotation.class) +class ParagraphDaoTest { + @Autowired + private ParagraphDao dao; + + @Test + @Order(1) + public void testSpace() { + ResultSet rs = dao.testSpaceFromYml(); + Assert.equals(rs.getSpaceName(), "test"); + } + + @Test + @Order(2) + public void testSpaceFromParam() { + ResultSet rs = dao.testSpaceFromParam("test"); + Assert.equals(rs.getSpaceName(), "test"); + } + + @Test + @Order(3) + public void testSpaceFromParam2() { + ResultSet rs = dao.testSpaceFromParam("${nebula.ngbatis.test-space-placeholder}"); + Assert.equals(rs.getSpaceName(), "cmqa"); + } + + @Test + @Order(4) + public void testSpaceAnno() { + ResultSet rs = dao.testSpaceAnno(); + Assert.equals(rs.getSpaceName(), "cmqa"); + } + + @Test + @Order(5) + public void testSelectById() { + Paragraph pageable = dao.selectById(0); + // 观察日志的 session space, 为 cmqa + } + +} diff --git a/pom.xml b/pom.xml index 734951b..4d8d3d9 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ ngbatis org.nebula-contrib ngbatis - 1.3.0-snapshot + 2.0.0-beta NgBatis is a database ORM framework base NebulaGraph + spring-boot, @@ -157,6 +157,17 @@ + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.13 + true + + ossrh + https://s01.oss.sonatype.org + true + + @@ -385,12 +396,14 @@ - nexus-releases - http://172.17.10.100:8081/nexus/content/repositories/releases + ossrh + Nexus Release Repository + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ - nexus-snapshots - http://172.17.10.100:8081/nexus/content/repositories/snapshots + ossrh + Nexus Snapshot Repository + https://s01.oss.sonatype.org/content/repositories/snapshots diff --git a/src/main/java/org/nebula/contrib/ngbatis/Env.java b/src/main/java/org/nebula/contrib/ngbatis/Env.java index 9c35b48..76824ff 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/Env.java +++ b/src/main/java/org/nebula/contrib/ngbatis/Env.java @@ -4,16 +4,11 @@ // // This source code is licensed under Apache 2.0 License. -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.nebula.contrib.ngbatis.proxy.MapperProxy.ENV; -import static org.nebula.contrib.ngbatis.utils.ReflectUtil.spaceFromEntity; - import com.alibaba.fastjson.parser.ParserConfig; import com.vesoft.nebula.client.graph.SessionPool; import com.vesoft.nebula.client.graph.net.Session; import org.nebula.contrib.ngbatis.base.GraphBaseExt; import org.nebula.contrib.ngbatis.config.ParseCfgProps; -import org.nebula.contrib.ngbatis.exception.ResourceLoadException; import org.nebula.contrib.ngbatis.models.MapperContext; import org.nebula.contrib.ngbatis.proxy.MapperProxy; import org.slf4j.Logger; @@ -127,56 +122,6 @@ public Session openSession() { } } - /** - * 通过实体类获取对应的space。 - * 支持占位符,并从配置信息中读取。 - * - * @param entityType 实体类 - * @return space - */ - public static String spaceFromConfig(Class entityType) { - return spaceFromConfig(entityType, ENV.getContext()); - } - - public static String spaceFromConfig(Class entityType, ApplicationContext context) { - String space = spaceFromEntity(entityType); - if (isBlank(space)) return null; - space = tryResolvePlaceholder(space, context); - return space; - } - - /** - * 利用Spring Environment 解析注解的值,用于 @Space 的 name 属性解析 - * @author Charle004 - * @param value 需要解析的值,可能是带占位符的 ${xx.xx} ,也可以是固定的字符串 - * @return resolveResult 解析结果 - * @throws IllegalArgumentException 当配置了 ${xx.xx} 占位符,且spring配置文件中未指定该配置时抛出 - */ - public static String tryResolvePlaceholder(String value) { - return tryResolvePlaceholder(value, ENV.getContext()); - } - - /** - * 利用Spring Environment 解析注解的值,用于 @Space 的 name 属性解析 - * @author Charle004 - * @param configKey 需要解析的值,可能是带占位符的 ${xx.xx} ,也可以是固定的字符串 - * @return resolveResult 解析结果 - * @throws IllegalArgumentException 当配置了 ${xx.xx} 占位符,且spring配置文件中未指定该配置时抛出 - */ - public static String tryResolvePlaceholder(String configKey, ApplicationContext context) { - String resolveResult = configKey; - if (null != context) { - try { - resolveResult = context.getEnvironment().resolveRequiredPlaceholders(configKey); - } catch (IllegalArgumentException e) { - throw new ResourceLoadException( - "name ( " + configKey + " ) of @Space missing configurable value" - ); - } - } - return resolveResult; - } - public String getUsername() { return username; } diff --git a/src/main/java/org/nebula/contrib/ngbatis/NgbatisBeanFactoryPostProcessor.java b/src/main/java/org/nebula/contrib/ngbatis/NgbatisBeanFactoryPostProcessor.java index 9d37de0..0c7a0aa 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/NgbatisBeanFactoryPostProcessor.java +++ b/src/main/java/org/nebula/contrib/ngbatis/NgbatisBeanFactoryPostProcessor.java @@ -2,6 +2,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.nebula.contrib.ngbatis.models.ClassModel.PROXY_SUFFIX; +import static org.nebula.contrib.ngbatis.proxy.MapperProxy.ENV; import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.entityTypeAndIdType; import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.vertexName; @@ -195,26 +196,22 @@ public NebulaPool nebulaPool() { /** * create and init Nebula SessionPool + * please use IntervalCheckSessionDispatcher.setNebulaSessionPool() instead. */ @Deprecated - public void setNebulaSessionPool(MapperContext context) throws Exception { - throw new Exception( - "Deprecated method, " - + "please use IntervalCheckSessionDispatcher.setNebulaSessionPool() instead." - ); + public void setNebulaSessionPool(MapperContext context) { + ENV.getDispatcher().setNebulaSessionPool(context); } /** * session pool create and init + * please use IntervalCheckSessionDispatcher.initSessionPool() instead. * @param spaceName nebula space name * @return inited SessionPool */ @Deprecated - public SessionPool initSessionPool(String spaceName) throws Exception { - throw new Exception( - "Deprecated method, " - + "please use SessionDispatcher.initSessionPool() instead." - ); + public SessionPool initSessionPool(String spaceName) { + return ENV.getDispatcher().initSessionPool(spaceName); } @Override diff --git a/src/main/java/org/nebula/contrib/ngbatis/SessionDispatcher.java b/src/main/java/org/nebula/contrib/ngbatis/SessionDispatcher.java index fab8a61..ae76e81 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/SessionDispatcher.java +++ b/src/main/java/org/nebula/contrib/ngbatis/SessionDispatcher.java @@ -72,6 +72,8 @@ static boolean useSessionPool() { return ngbatisConfig != null && ngbatisConfig.getUseSessionPool(); } + void setNebulaSessionPool(MapperContext context); + /** * 按 spaceName 初始化 sessionPool * diff --git a/src/main/java/org/nebula/contrib/ngbatis/base/GraphBaseExt.java b/src/main/java/org/nebula/contrib/ngbatis/base/GraphBaseExt.java index 981517c..cd14cb9 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/base/GraphBaseExt.java +++ b/src/main/java/org/nebula/contrib/ngbatis/base/GraphBaseExt.java @@ -1,6 +1,5 @@ package org.nebula.contrib.ngbatis.base; -import static org.nebula.contrib.ngbatis.Env.spaceFromConfig; import static org.nebula.contrib.ngbatis.utils.ReflectUtil.getNameByColumn; import static org.nebula.contrib.ngbatis.utils.ReflectUtil.getValue; @@ -15,6 +14,7 @@ import org.nebula.contrib.ngbatis.SessionDispatcher; import org.nebula.contrib.ngbatis.annotations.base.EdgeType; import org.nebula.contrib.ngbatis.annotations.base.Tag; +import org.nebula.contrib.ngbatis.session.SpaceRouter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,7 +34,7 @@ public static ResultSet executeGql(String textTpl, //从env中获取本地会话调度器 SessionDispatcher dispatcher = ENV.getDispatcher(); //从env中获取space - String currentSpace = getSpace(m1); + String currentSpace = SpaceRouter.getSpace(m1); ArgsResolver argsResolver = ENV.getArgsResolver(); @@ -57,38 +57,6 @@ public static ResultSet executeGql(String textTpl, return result; } - /** - * 获取当前space,支持 @Space 跟 @Table 注解 - * 如果均未指定,则返回默认space - * - * @return 当前space - */ - public static String getSpace(Map m1) { - Object edgeType = m1.get("edgeType"); - Object tag = m1.get("tag"); - String entityTypeName = edgeType != null ? edgeType.toString() - : tag != null ? tag.toString() - : null; - - String defaultSpace = ENV.getSpace(); - if (entityTypeName == null) { - return defaultSpace; - } - - Map> entityTypeMapping = ENV.getMapperContext().getTagTypeMapping(); - Class entityType = entityTypeMapping.get(entityTypeName); - boolean isGraphBase = GraphBase.class.isAssignableFrom(entityType); - if (!isGraphBase) { - return defaultSpace; - } - - String space = spaceFromConfig(entityType); - if (space != null) { - return space; - } - return ENV.getSpace(); - } - /** * 处理查询结果 * @param resultSet 结果集ResultSet diff --git a/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java b/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java index 578966d..fbcd111 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java +++ b/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java @@ -6,7 +6,6 @@ import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; -import static org.nebula.contrib.ngbatis.SessionDispatcher.addSpaceToSessionPool; import static org.nebula.contrib.ngbatis.models.ClassModel.PROXY_SUFFIX; import static org.nebula.contrib.ngbatis.utils.ReflectUtil.NEED_SEALING_TYPES; import static org.nebula.contrib.ngbatis.utils.ReflectUtil.getNameUniqueMethod; @@ -16,8 +15,6 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -31,8 +28,6 @@ import org.jsoup.nodes.Node; import org.jsoup.nodes.TextNode; import org.jsoup.select.Elements; -import org.nebula.contrib.ngbatis.Env; -import org.nebula.contrib.ngbatis.annotations.Space; import org.nebula.contrib.ngbatis.annotations.TimeLog; import org.nebula.contrib.ngbatis.config.ParseCfgProps; import org.nebula.contrib.ngbatis.exception.ParseException; @@ -42,6 +37,7 @@ import org.nebula.contrib.ngbatis.models.NgqlModel; import org.nebula.contrib.ngbatis.utils.Page; import org.nebula.contrib.ngbatis.utils.ReflectUtil; +import org.nebula.contrib.ngbatis.session.SpaceRouter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; @@ -126,13 +122,7 @@ public Map parseClassModel(Resource resource) match(cm, element, "space", parseConfig.getSpace()); // 从注解获取 space - if (null == cm.getSpace()) { - setClassModelBySpaceAnnotation(cm); - }else { - //动态解析 XML 中 mapper 标签配置的 Space 属性 - setClassModelByXmlConfigSpace(cm); - } - addSpaceToSessionPool(cm.getSpace()); + SpaceRouter.setClassSpace(cm, applicationContext); // 获取 子节点 List nodes = element.childNodes(); @@ -144,42 +134,6 @@ public Map parseClassModel(Resource resource) return result; } - /** - * 解析自定义的 XML 中的 mapper 标签设置的 space - * @param cm ClassModel - */ - private void setClassModelByXmlConfigSpace(ClassModel cm) { - String space = tryResolvePlaceholder(cm.getSpace()); - cm.setSpace(space); - } - - /** - * 设置 space - * @param cm ClassModel - */ - private void setClassModelBySpaceAnnotation(ClassModel cm) { - try { - Type[] genericInterfaces = cm.getNamespace().getGenericInterfaces(); - if (genericInterfaces.length == 0) { - return; - } - ParameterizedType nebulaDaoBasicType = (ParameterizedType) genericInterfaces[0]; - Type[] genericTypes = nebulaDaoBasicType.getActualTypeArguments(); - if (genericTypes.length == 0) { - return; - } - String spaceClassName = genericTypes[0].getTypeName(); - Class entityType = Class.forName(spaceClassName); - String space = ReflectUtil.spaceFromEntity(entityType); - if (isNotBlank(space)) { - space = Env.tryResolvePlaceholder(space, applicationContext); - cm.setSpace(space); - } - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - } - /** * 解析 一个 XXXDao 的多个方法。 * @@ -203,9 +157,7 @@ private Map parseMethodModel(ClassModel cm, List node cm.getNgqls().put(ngqlModel.getId(),ngqlModel); } else { MethodModel methodModel = parseMethodModel(methodNode); - if (!methodModel.isSpaceFromParam()) { - addSpaceToSessionPool(methodModel.getSpace()); - } + SpaceRouter.setMethodSpace(methodModel, applicationContext); Method method = getNameUniqueMethod(namespace, methodModel.getId()); methodModel.setMethod(method); Assert.notNull(method, diff --git a/src/main/java/org/nebula/contrib/ngbatis/models/MapperContext.java b/src/main/java/org/nebula/contrib/ngbatis/models/MapperContext.java index daf9f96..f74ba9c 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/models/MapperContext.java +++ b/src/main/java/org/nebula/contrib/ngbatis/models/MapperContext.java @@ -4,6 +4,8 @@ // // This source code is licensed under Apache 2.0 License. +import static org.nebula.contrib.ngbatis.utils.ReflectUtil.typeArg; + import com.vesoft.nebula.client.graph.NebulaPoolConfig; import com.vesoft.nebula.client.graph.SessionPool; import com.vesoft.nebula.client.graph.net.NebulaPool; @@ -13,6 +15,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.nebula.contrib.ngbatis.config.NgbatisConfig; +import org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic; /** * xml 中标签所声明的信息(方法) @@ -30,6 +33,10 @@ public class MapperContext { final Map> tagTypeMapping = new HashMap<>(); /** * 当前应用中,在 xml 中 namespace 所声明的所有 XXXDao 及其 类模型 + *
    + *
  • key: bean名称,自定义DAO接口名+{@link ClassModel.PROXY_SUFFIX}
  • + *
  • value: 类模型
  • + *
*/ Map interfaces; /** @@ -59,6 +66,11 @@ public class MapperContext { private NgbatisConfig ngbatisConfig; boolean resourceRefresh = false; + /** + * 实体类名与类模型的映射 + */ + private Map, ClassModel> entityClassModelMap = null; + private MapperContext() { } @@ -141,4 +153,16 @@ public Map> getTagTypeMapping() { return tagTypeMapping; } + public Map, ClassModel> computeEntityClassModelMap() { + if (entityClassModelMap == null) { + entityClassModelMap = new HashMap<>(); + for (ClassModel classModel : interfaces.values()) { + Class entityType = typeArg(classModel.getNamespace(), NebulaDaoBasic.class, 0); + if (entityType != null) { + entityClassModelMap.put(entityType, classModel); + } + } + } + return entityClassModelMap; + } } diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java index eb42bb1..88c10ad 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java @@ -5,35 +5,27 @@ // This source code is licensed under Apache 2.0 License. import static org.apache.commons.lang3.ObjectUtils.isEmpty; -import static org.apache.commons.lang3.StringUtils.isBlank; import static org.nebula.contrib.ngbatis.models.ClassModel.PROXY_SUFFIX; -import com.vesoft.nebula.client.graph.SessionPool; import com.vesoft.nebula.client.graph.data.ResultSet; -import com.vesoft.nebula.client.graph.exception.BindSpaceFailedException; -import com.vesoft.nebula.client.graph.exception.IOErrorException; -import com.vesoft.nebula.client.graph.net.Session; import java.io.IOException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import org.nebula.contrib.ngbatis.ArgsResolver; import org.nebula.contrib.ngbatis.Env; import org.nebula.contrib.ngbatis.ResultResolver; import org.nebula.contrib.ngbatis.SessionDispatcher; -import org.nebula.contrib.ngbatis.config.NgbatisConfig; import org.nebula.contrib.ngbatis.config.ParseCfgProps; import org.nebula.contrib.ngbatis.exception.QueryException; import org.nebula.contrib.ngbatis.models.ClassModel; import org.nebula.contrib.ngbatis.models.MapperContext; import org.nebula.contrib.ngbatis.models.MethodModel; -import org.nebula.contrib.ngbatis.session.LocalSession; import org.nebula.contrib.ngbatis.utils.Page; import org.nebula.contrib.ngbatis.utils.ReflectUtil; -import org.nebula.contrib.ngbatis.utils.ResultSetUtil; +import org.nebula.contrib.ngbatis.session.SpaceRouter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -220,7 +212,7 @@ public static ResultSet executeWithParameter( proxyMethod = mm.getId(); } - String currentSpace = getSpace(cm, mm, paramsForTemplate); + String currentSpace = SpaceRouter.getSpace(cm, mm, paramsForTemplate); result = dispatcher.executeWithParameter( gql, params, currentSpace, extraReturn ); @@ -252,88 +244,79 @@ public static ResultSet executeWithParameter( } } - /** - * 通过 nebula-graph 客户端执行数据库访问。被 invoke 所调用,间接为动态代理类服务。 - * - * @param gql 待执行的查询脚本(模板) - * @param params 待执行脚本的参数所需的参数 - * @return nebula-graph 的未被 orm 操作的原始结果集 - */ - public static ResultSet executeBySessionPool(ClassModel cm, MethodModel mm, String gql, - Map params, Map paramsForTemplate) { - - ResultSet result = null; - String proxyClass = null; - String proxyMethod = null; - String currentSpace = null; - - try { - if (log.isDebugEnabled()) { - proxyClass = cm.getNamespace().getName(); - proxyMethod = mm.getId(); - } - - currentSpace = getSpace(cm, mm, paramsForTemplate); - SessionPool sessionPool = ENV.getSessionPool(currentSpace); - if (sessionPool == null) { - throw new QueryException(currentSpace + " sessionPool is null"); - } - result = sessionPool.execute(gql, params); - if (result.isSucceeded()) { - return result; - } else { - throw new QueryException( - " ResultSet error: " + result.getErrorMessage(), - result.getErrorCode() - ); - } - } catch (Exception e) { - throw new QueryException("execute failed: " + e.getMessage(), e); - } finally { - if (log.isDebugEnabled()) { - log.debug("\n\t- proxyMethod: {}#{}" - + "\n\t- session space: {}" - + "\n\t- nGql:{}" - + "\n\t- params: {}" - + "\n\t- result:{}", - proxyClass, proxyMethod, currentSpace, gql, paramsForTemplate, result); - } - } - } - - /** - * 获取当前语句所执行的目标space。 - * @param cm 当前接口的类模型 - * @param mm 当前接口方法的方法模型 - * @return 目标space - */ - public static String getSpace(ClassModel cm, MethodModel mm) { - String methodSpace; - return (mm != null && (methodSpace = mm.getSpace()) != null) - ? ( - "null".equals(methodSpace.trim()) ? null : methodSpace - ) - : cm != null && cm.getSpace() != null ? cm.getSpace() - : ENV.getSpace(); - } - - /** - * 支持space从参数中获取 - * @param cm 当前接口的类模型 - * @param mm 当前接口方法的方法模型 - * @param paramsForTemplate 从模板参数中获取空间名 - * @return 目标space - */ - public static String getSpace( - ClassModel cm, MethodModel mm, Map paramsForTemplate - ) { - boolean spaceFromParam = mm.isSpaceFromParam(); - String space = getSpace(cm, mm); - if (spaceFromParam && space != null) { - return ENV.getTextResolver().resolve(space, paramsForTemplate); - } - return space; - } +// /** +// * 通过 nebula-graph 客户端执行数据库访问。被 invoke 所调用,间接为动态代理类服务。 +// * +// * @param gql 待执行的查询脚本(模板) +// * @param params 待执行脚本的参数所需的参数 +// * @return nebula-graph 的未被 orm 操作的原始结果集 +// */ +// public static ResultSet executeBySessionPool(ClassModel cm, MethodModel mm, String gql, +// Map params, Map paramsForTemplate) { +// +// ResultSet result = null; +// String proxyClass = null; +// String proxyMethod = null; +// String currentSpace = null; +// +// try { +// if (log.isDebugEnabled()) { +// proxyClass = cm.getNamespace().getName(); +// proxyMethod = mm.getId(); +// } +// +// currentSpace = SpaceRouter.getSpace(cm, mm, paramsForTemplate); +// SessionPool sessionPool = ENV.getSessionPool(currentSpace); +// if (sessionPool == null) { +// throw new QueryException(currentSpace + " sessionPool is null"); +// } +// result = sessionPool.execute(gql, params); +// if (result.isSucceeded()) { +// return result; +// } else { +// throw new QueryException( +// " ResultSet error: " + result.getErrorMessage(), +// result.getErrorCode() +// ); +// } +// } catch (Exception e) { +// throw new QueryException("execute failed: " + e.getMessage(), e); +// } finally { +// if (log.isDebugEnabled()) { +// log.debug("\n\t- proxyMethod: {}#{}" +// + "\n\t- session space: {}" +// + "\n\t- nGql:{}" +// + "\n\t- params: {}" +// + "\n\t- result:{}", +// proxyClass, proxyMethod, currentSpace, gql, paramsForTemplate, result); +// } +// } +// } + +// /** +// * 获取当前语句所执行的目标space。 +// * @param cm 当前接口的类模型 +// * @param mm 当前接口方法的方法模型 +// * @return 目标space +// */ +// @Deprecated +// public static String getSpace(ClassModel cm, MethodModel mm) { +// return SpaceRouter.getSpace(cm, mm); +// } + +// /** +// * 支持space从参数中获取 +// * @param cm 当前接口的类模型 +// * @param mm 当前接口方法的方法模型 +// * @param paramsForTemplate 从模板参数中获取空间名 +// * @return 目标space +// */ +// @Deprecated +// public static String getSpace( +// ClassModel cm, MethodModel mm, Map paramsForTemplate +// ) { +// return SpaceRouter.getSpace(cm, mm, paramsForTemplate); +// } public static Logger getLog() { return log; diff --git a/src/main/java/org/nebula/contrib/ngbatis/session/IntervalCheckSessionDispatcher.java b/src/main/java/org/nebula/contrib/ngbatis/session/IntervalCheckSessionDispatcher.java index 4c09b56..6123c90 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/session/IntervalCheckSessionDispatcher.java +++ b/src/main/java/org/nebula/contrib/ngbatis/session/IntervalCheckSessionDispatcher.java @@ -6,6 +6,7 @@ import static org.apache.commons.lang3.StringUtils.isBlank; import static org.nebula.contrib.ngbatis.proxy.MapperProxy.ENV; +import static org.springframework.util.ObjectUtils.nullSafeEquals; import com.vesoft.nebula.client.graph.NebulaPoolConfig; import com.vesoft.nebula.client.graph.SessionPool; @@ -166,6 +167,7 @@ public boolean timeToRelease(LocalSession session) { * @author gin soul [create] * @author CorvusYe [refac] */ + @Override public void setNebulaSessionPool(MapperContext context) { NgbatisConfig ngbatisConfig = nebulaJdbcProperties.getNgbatis(); if (ngbatisConfig.getUseSessionPool() == null || !ngbatisConfig.getUseSessionPool()) { @@ -190,7 +192,6 @@ public void setNebulaSessionPool(MapperContext context) { * @param spaceName nebula space name * @author gin soul [create] - * @author CorvusYe [refac] * @return inited SessionPool */ @Override @@ -269,12 +270,15 @@ public ResultSet executeWithParameter( String autoSwitch = qlAndSpace[0] == null ? "" : qlAndSpace[0]; session = localSession.getSession(); result = session.executeWithParameter(gql, params); - extraReturn.put("autoSwitch", autoSwitch); + localSession.setCurrentSpace(getSpace(result)); handleSession(localSession, result); if (log.isDebugEnabled()) { - extraReturn.put("localSessionSpace", localSession.getCurrentSpace()); - extraReturn.put("autoSwitch", autoSwitch); + extraReturn.put("localSessionSpace", space); + String currentSpace = localSession.getCurrentSpace(); + if (nullSafeEquals(currentSpace, autoSwitch)) { + extraReturn.put("autoSwitch", autoSwitch); + } } return result; } diff --git a/src/main/java/org/nebula/contrib/ngbatis/session/SpaceRouter.java b/src/main/java/org/nebula/contrib/ngbatis/session/SpaceRouter.java new file mode 100644 index 0000000..8651869 --- /dev/null +++ b/src/main/java/org/nebula/contrib/ngbatis/session/SpaceRouter.java @@ -0,0 +1,239 @@ +package org.nebula.contrib.ngbatis.session; + +// Copyright (c) 2024 All project authors. All rights reserved. +// +// This source code is licensed under Apache 2.0 License. + +import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.nebula.contrib.ngbatis.SessionDispatcher.addSpaceToSessionPool; +import static org.nebula.contrib.ngbatis.proxy.MapperProxy.ENV; +import static org.nebula.contrib.ngbatis.utils.ReflectUtil.typeArg; + +import java.util.Map; +import javax.persistence.Table; +import org.nebula.contrib.ngbatis.annotations.Space; +import org.nebula.contrib.ngbatis.base.GraphBase; +import org.nebula.contrib.ngbatis.exception.ResourceLoadException; +import org.nebula.contrib.ngbatis.models.ClassModel; +import org.nebula.contrib.ngbatis.models.MethodModel; +import org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic; +import org.springframework.context.ApplicationContext; + +/** + * 用于处理读取空间配置相关的工具类 + * + * @author yeweicheng + * @since 2024-12-20 23:26 + *
Now is history! + */ +public class SpaceRouter { + + /** + * 从实体类获取 space,并解析占位符 从类获取有两种来源: + *
    + *
  1. 通过 @Table 注解
  2. + *
  3. 通过 @Space 注解
  4. + *
  5. 默认值:${ nebula.space }
  6. + *
  7. 优先级:@Table > @Space > 默认值
  8. + *
  9. 支持来自配置文件的占位符解析
  10. + *
  11. 推荐使用 @Table,@Space 属于自定义注解,可能会在后续版本移除
  12. + *
+ */ + public static String spaceFromEntity(Class entityType) { + String defaultSpace = ENV == null ? null : ENV.getSpace(); + if (entityType == null) { + return defaultSpace; + } + + boolean hasTable = entityType.isAnnotationPresent(Table.class); + if (hasTable) { + Table tableAnnotation = entityType.getAnnotation(Table.class); + String space = tableAnnotation.schema(); + System.out.println("table space: " + space); + if (isNotBlank(space)) { + return space; + } + } + + boolean hasSpace = entityType.isAnnotationPresent(Space.class); + + if (hasSpace) { + Space spaceAnnotation = entityType.getAnnotation(Space.class); + String space = spaceAnnotation.name(); + if (isNotBlank(space)) { + System.out.println("space: " + space); + return space; + } + } + + return defaultSpace; + } + + public static String spaceFromEntity(Class entityType, ApplicationContext context) { + String space = spaceFromEntity(entityType); + return tryResolvePlaceholder(space, context); + } + + /** + * 通过DAO的类模型获取对应的space。 支持占位符,并从配置信息中读取。 在 xml 资源解析阶段调用,读取 space, 若 space 存在占位符,则解析占位符 并将解析后的 + * space 设置到类模型中 此时,space 已经用上配置值,是有效的图空间。 并以此空间名初始化 session pool,如果开启了 session pool + * + * @param cm 类模型 + */ + public static void setClassSpace(ClassModel cm, ApplicationContext context) { + if (cm != null) { + String space = cm.getSpace(); + if (isBlank(space)) { + Class daoClass = cm.getNamespace(); + // 从 dao 类的泛型中获取实体类 + Class entityType = typeArg(daoClass, NebulaDaoBasic.class, 0); + // 通过实体类的注解获取space + space = spaceFromEntity(entityType, context); + } + cm.setSpace(space); + addSpaceToSessionPool(cm.getSpace()); + } + } + + /** + * 设置不同接口方法的空间 未使用参数传递空间时,从配置文件中读取 + * + * @param methodModel 方法模型 + * @param applicationContext 应用上下文 + */ + public static void setMethodSpace( + MethodModel methodModel, ApplicationContext applicationContext) { + if (!methodModel.isSpaceFromParam()) { // 未使用参数传递空间 + String space = methodModel.getSpace(); + if (isNotBlank(space)) { + // 如果不为空,则尝试解析占位符 + space = tryResolvePlaceholder(space, applicationContext); + methodModel.setSpace(space); + addSpaceToSessionPool(space); + } + } + } + + /** + * 支持space从参数中获取 + * + * @param cm 当前接口的类模型 + * @param mm 当前接口方法的方法模型 + * @param paramsForTemplate 从模板参数中获取空间名 + * @return 目标space + */ + public static String getSpace( + ClassModel cm, MethodModel mm, Map paramsForTemplate + ) { + boolean spaceFromParam = mm.isSpaceFromParam(); + String space = mm.getSpace() != null ? mm.getSpace() : cm.getSpace(); + if ("null".equals(space)) { + space = ENV.getSpace();; + } + if (spaceFromParam && space != null) { + // 从参数中获取space + String paramSpace = ENV.getTextResolver().resolve(space, paramsForTemplate); + // 让参数同样支持 ${xx.xx} 占位符 + return tryResolvePlaceholder(paramSpace); + } + return isBlank(space) ? ENV.getSpace() : space; + } + + /** + * 获取当前space,支持 @Space 跟 @Table 注解 如果均未指定, + * 则返回默认space 用于 GraphBaseExt 通过标签名、边类型名称获取space + * + * @return 当前space + */ + public static String getSpace(Map m1) { + Object edgeType = m1.get("edgeType"); + Object tag = m1.get("tag"); + String entityTypeName = edgeType != null ? edgeType.toString() + : tag != null ? tag.toString() + : null; + + String defaultSpace = ENV.getSpace(); + if (entityTypeName == null) { + return defaultSpace; + } + + // 获取表名与实体类的映射 + Map> entityTypeMapping = ENV.getMapperContext().getTagTypeMapping(); + // 获取实体类 + Class entityType = entityTypeMapping.get(entityTypeName); + String space = SpaceRouter.spaceFromConfig(entityType); + if (isNotBlank(space)) { + // 已经是解析后的space + return space; + } + return ENV.getSpace(); + } + + /** + * 通过实体类获取对应的space。 支持占位符,并从配置信息中读取。 + * + * @param entityType 实体类 + * @return space + */ + public static String spaceFromConfig(Class entityType) { + return spaceFromConfig(entityType, ENV.getContext()); + } + + /** + * 调用时机:在环境启动时,尚获得 context 时调用 + * + * @param entityType 实体类 + * @param context Spring 上下文 + * @return space 空间名,已经解析占位符 + */ + public static String spaceFromConfig(Class entityType, ApplicationContext context) { + String space = null; + ClassModel cm = ENV.getMapperContext().computeEntityClassModelMap().get(entityType); + if (cm != null) { + space = cm.getSpace(); + } + if (isBlank(space)) { + space = spaceFromEntity(entityType, context); + } + return space; + } + + /** + * 利用Spring Environment 解析注解的值,用于 @Space 的 name 属性解析 + * + * @param value 需要解析的值,可能是带占位符的 ${xx.xx} ,也可以是固定的字符串 + * @return resolveResult 解析结果 + * @throws IllegalArgumentException 当配置了 ${xx.xx} 占位符,且spring配置文件中未指定该配置时抛出 + * @author Charle004 + */ + public static String tryResolvePlaceholder(String value) { + return tryResolvePlaceholder(value, ENV.getContext()); + } + + /** + * 利用Spring Environment 解析注解的值,用于 @Space 的 name 属性解析 + * + * @param configKey 需要解析的值,可能是带占位符的 ${xx.xx} ,也可以是固定的字符串 + * @return resolveResult 解析结果 + * @throws IllegalArgumentException 当配置了 ${xx.xx} 占位符,且spring配置文件中未指定该配置时抛出 + * @author Charle004 + */ + public static String tryResolvePlaceholder(String configKey, ApplicationContext context) { + if (isBlank(configKey)) { + return null; + } + String resolveResult = configKey; + if (null != context) { + try { + resolveResult = context.getEnvironment().resolveRequiredPlaceholders(configKey); + } catch (IllegalArgumentException e) { + throw new ResourceLoadException( + "name ( " + configKey + " ) missing configurable value" + ); + } + } + return resolveResult; + } + +} diff --git a/src/main/java/org/nebula/contrib/ngbatis/utils/ReflectUtil.java b/src/main/java/org/nebula/contrib/ngbatis/utils/ReflectUtil.java index 667bdeb..6e0687b 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/utils/ReflectUtil.java +++ b/src/main/java/org/nebula/contrib/ngbatis/utils/ReflectUtil.java @@ -25,7 +25,6 @@ import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Transient; -import org.nebula.contrib.ngbatis.annotations.Space; import org.nebula.contrib.ngbatis.annotations.base.EdgeType; import org.nebula.contrib.ngbatis.annotations.base.Tag; import org.nebula.contrib.ngbatis.exception.ParseException; @@ -552,17 +551,29 @@ public static Class typeArg(Object o, Class parent, int i) { Assert.isTrue(o != null, "instance can not be null"); Class insClass = o.getClass(); if (parent.isInterface()) { - Type[] interfaces = insClass.getGenericInterfaces(); - for (Type anInterface : interfaces) { - boolean isType = anInterface instanceof ParameterizedType; - if (isType) { - ParameterizedType paramTypeInterface = (ParameterizedType) anInterface; - boolean found = paramTypeInterface.getRawType() == parent; - if (found) { - Type[] actualTypeArguments = paramTypeInterface.getActualTypeArguments(); - boolean noOut = actualTypeArguments.length > i; - return noOut ? (Class)actualTypeArguments[i] : null; - } + return typeArg(insClass, parent, i); + } + return null; + } + + /** + * 从类型中,获取父类或接口中的泛型参数。 + * @param clazz 类型 + * @param parent 所继承的父类或实现的接口 + * @param i 泛型参数所处下标 + * @return 泛型 + */ + public static Class typeArg(Class clazz, Class parent, int i) { + Type[] interfaces = clazz.getGenericInterfaces(); + for (Type anInterface : interfaces) { + boolean isType = anInterface instanceof ParameterizedType; + if (isType) { + ParameterizedType paramTypeInterface = (ParameterizedType) anInterface; + boolean found = paramTypeInterface.getRawType() == parent; + if (found) { + Type[] actualTypeArguments = paramTypeInterface.getActualTypeArguments(); + boolean noOut = actualTypeArguments.length > i; + return noOut ? (Class)actualTypeArguments[i] : null; } } } @@ -620,25 +631,5 @@ public static boolean isGraphId(Field field) { } return false; } - - /** - * 从实体类获取 space,并解析占位符 - */ - public static String spaceFromEntity(Class entityType) { - boolean hasSpace = entityType.isAnnotationPresent(Space.class); - String space = null; - if (hasSpace) { - Space spaceAnnotation = entityType.getAnnotation(Space.class); - space = spaceAnnotation.name(); - } - - boolean hasTable = entityType.isAnnotationPresent(Table.class); - if (hasTable) { - Table tableAnnotation = entityType.getAnnotation(Table.class); - space = tableAnnotation.schema(); - } - - return space; - } }