diff --git a/cosid-core/src/test/java/me/ahoo/cosid/accessor/NotFoundCosIdAccessorTest.java b/cosid-core/src/test/java/me/ahoo/cosid/accessor/NotFoundCosIdAccessorTest.java new file mode 100644 index 0000000000..729dc22084 --- /dev/null +++ b/cosid-core/src/test/java/me/ahoo/cosid/accessor/NotFoundCosIdAccessorTest.java @@ -0,0 +1,51 @@ +/* + * Copyright [2021-present] [ahoo wang (https://github.com/Ahoo-Wang)]. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.ahoo.cosid.accessor; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +import org.junit.jupiter.api.Test; + +class NotFoundCosIdAccessorTest { + @Test + public void getIdDefinition() { + assertThat(CosIdAccessor.NOT_FOUND.getIdDefinition(), nullValue()); + } + + @Test + public void getIdGenerator() { + assertThat(CosIdAccessor.NOT_FOUND.getIdGenerator(), nullValue()); + } + + @Test + public void getIdField() { + assertThat(CosIdAccessor.NOT_FOUND.getIdField(), nullValue()); + } + + @Test + public void getId() { + assertThat(CosIdAccessor.NOT_FOUND.getId(new Object()), nullValue()); + } + + @Test + public void setId() { + CosIdAccessor.NOT_FOUND.setId(new Object(), new Object()); + } + + @Test + public void ensureId() { + assertThat(CosIdAccessor.NOT_FOUND.ensureId(new Object()), equalTo(false)); + } +} \ No newline at end of file diff --git a/cosid-core/src/test/java/me/ahoo/cosid/accessor/registry/DefaultAccessorRegistryTest.java b/cosid-core/src/test/java/me/ahoo/cosid/accessor/registry/DefaultAccessorRegistryTest.java index 5cd8fae2d0..6d82b798fc 100644 --- a/cosid-core/src/test/java/me/ahoo/cosid/accessor/registry/DefaultAccessorRegistryTest.java +++ b/cosid-core/src/test/java/me/ahoo/cosid/accessor/registry/DefaultAccessorRegistryTest.java @@ -13,8 +13,12 @@ package me.ahoo.cosid.accessor.registry; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + import me.ahoo.cosid.accessor.parser.DefaultAccessorParser; import me.ahoo.cosid.annotation.AnnotationDefinitionParser; +import me.ahoo.cosid.annotation.entity.IntIdEntity; import me.ahoo.cosid.annotation.entity.LongIdEntity; import me.ahoo.cosid.annotation.entity.MissingIdGenEntity; import me.ahoo.cosid.annotation.entity.StringIdEntity; @@ -30,9 +34,9 @@ * @author ahoo wang */ class DefaultAccessorRegistryTest { - + CosIdAccessorRegistry accessorRegistry = new DefaultAccessorRegistry(new DefaultAccessorParser(AnnotationDefinitionParser.INSTANCE)); - + @Test void ensureIdExistsByAnnotation() { DefaultIdGeneratorProvider.INSTANCE.setShare(AtomicLongGenerator.INSTANCE); @@ -41,7 +45,7 @@ void ensureIdExistsByAnnotation() { accessorRegistry.ensureId(entity); Assertions.assertEquals(888, entity.getId()); } - + @Test void ensureIdNotFindByAnnotation() { MissingIdGenEntity entity = new MissingIdGenEntity(); @@ -49,7 +53,7 @@ void ensureIdNotFindByAnnotation() { accessorRegistry.ensureId(entity); }); } - + @Test void ensureStringId() { DefaultIdGeneratorProvider.INSTANCE.setShare(AtomicLongGenerator.INSTANCE); @@ -57,5 +61,12 @@ void ensureStringId() { accessorRegistry.ensureId(entity); Assertions.assertFalse(Strings.isNullOrEmpty(entity.getId())); } - + + @Test + void ensureIntId() { + DefaultIdGeneratorProvider.INSTANCE.setShare(AtomicLongGenerator.INSTANCE); + IntIdEntity entity = new IntIdEntity(); + accessorRegistry.ensureId(entity); + assertThat(entity.getId(), not(0)); + } } diff --git a/cosid-core/src/test/java/me/ahoo/cosid/accessor/scanner/DefaultCosIdScannerTest.java b/cosid-core/src/test/java/me/ahoo/cosid/accessor/scanner/DefaultCosIdScannerTest.java index 23dcadd929..0b5ea4e36e 100644 --- a/cosid-core/src/test/java/me/ahoo/cosid/accessor/scanner/DefaultCosIdScannerTest.java +++ b/cosid-core/src/test/java/me/ahoo/cosid/accessor/scanner/DefaultCosIdScannerTest.java @@ -14,7 +14,6 @@ package me.ahoo.cosid.accessor.scanner; import me.ahoo.cosid.accessor.CosIdAccessor; -import me.ahoo.cosid.accessor.parser.CosIdAccessorParser; import me.ahoo.cosid.accessor.parser.DefaultAccessorParser; import me.ahoo.cosid.accessor.parser.NamedDefinitionParser; import me.ahoo.cosid.accessor.registry.CosIdAccessorRegistry; @@ -23,6 +22,7 @@ import me.ahoo.cosid.accessor.scanner.entity.OrderItemEntity; import me.ahoo.cosid.annotation.AnnotationDefinitionParser; import me.ahoo.cosid.annotation.entity.ChildEntity; +import me.ahoo.cosid.annotation.entity.IntIdEntity; import me.ahoo.cosid.annotation.entity.LongIdEntity; import me.ahoo.cosid.annotation.entity.MissingIdGenEntity; import me.ahoo.cosid.annotation.entity.PrimitiveLongIdEntity; @@ -35,56 +35,62 @@ * @author ahoo wang */ class DefaultCosIdScannerTest { - + @Test void scanAnnotationDefinitionParser() { CosIdAccessorRegistry registry = new DefaultAccessorRegistry(new DefaultAccessorParser(AnnotationDefinitionParser.INSTANCE)); DefaultCosIdScanner scanner = new DefaultCosIdScanner(new String[] {"me.ahoo.cosid.accessor.annotation.entity"}, AnnotationDefinitionParser.INSTANCE, registry); scanner.scan(); - + CosIdAccessor cosIdAccessor = registry.get(LongIdEntity.class); Assertions.assertNotNull(cosIdAccessor); Assertions.assertNotEquals(CosIdAccessor.NOT_FOUND, cosIdAccessor); Assertions.assertEquals(LongIdEntity.class, cosIdAccessor.getIdDeclaringClass()); - + cosIdAccessor = registry.get(MissingIdGenEntity.class); Assertions.assertNotNull(cosIdAccessor); Assertions.assertNotEquals(CosIdAccessor.NOT_FOUND, cosIdAccessor); Assertions.assertEquals(MissingIdGenEntity.class, cosIdAccessor.getIdDeclaringClass()); - + cosIdAccessor = registry.get(PrimitiveLongIdEntity.class); Assertions.assertNotNull(cosIdAccessor); Assertions.assertNotEquals(CosIdAccessor.NOT_FOUND, cosIdAccessor); Assertions.assertEquals(PrimitiveLongIdEntity.class, cosIdAccessor.getIdDeclaringClass()); - + + cosIdAccessor = registry.get(IntIdEntity.class); + Assertions.assertNotNull(cosIdAccessor); + Assertions.assertNotEquals(CosIdAccessor.NOT_FOUND, cosIdAccessor); + Assertions.assertEquals(IntIdEntity.class, cosIdAccessor.getIdDeclaringClass()); + cosIdAccessor = registry.get(StringIdEntity.class); Assertions.assertNotNull(cosIdAccessor); Assertions.assertNotEquals(CosIdAccessor.NOT_FOUND, cosIdAccessor); Assertions.assertEquals(StringIdEntity.class, cosIdAccessor.getIdDeclaringClass()); - + cosIdAccessor = registry.get(ChildEntity.class); Assertions.assertNotNull(cosIdAccessor); Assertions.assertNotEquals(CosIdAccessor.NOT_FOUND, cosIdAccessor); Assertions.assertEquals(LongIdEntity.class, cosIdAccessor.getIdDeclaringClass()); } - + @Test void scanNamedDefinitionParser() { CosIdAccessorRegistry registry = new DefaultAccessorRegistry(new DefaultAccessorParser(AnnotationDefinitionParser.INSTANCE)); DefaultCosIdScanner scanner = new DefaultCosIdScanner(new String[] {"me.ahoo.cosid.accessor.scanner.entity"}, new NamedDefinitionParser("id"), registry); scanner.scan(); - + CosIdAccessor cosIdAccessor = registry.get(OrderEntity.class); Assertions.assertNotNull(cosIdAccessor); Assertions.assertNotEquals(CosIdAccessor.NOT_FOUND, cosIdAccessor); Assertions.assertEquals(OrderEntity.class, cosIdAccessor.getIdDeclaringClass()); - + cosIdAccessor = registry.get(OrderItemEntity.class); Assertions.assertNotNull(cosIdAccessor); Assertions.assertNotEquals(CosIdAccessor.NOT_FOUND, cosIdAccessor); Assertions.assertEquals(OrderItemEntity.class, cosIdAccessor.getIdDeclaringClass()); + } - + } diff --git a/cosid-core/src/test/java/me/ahoo/cosid/annotation/entity/IntIdEntity.java b/cosid-core/src/test/java/me/ahoo/cosid/annotation/entity/IntIdEntity.java new file mode 100644 index 0000000000..ccb276182a --- /dev/null +++ b/cosid-core/src/test/java/me/ahoo/cosid/annotation/entity/IntIdEntity.java @@ -0,0 +1,32 @@ +/* + * Copyright [2021-present] [ahoo wang (https://github.com/Ahoo-Wang)]. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.ahoo.cosid.annotation.entity; + +import me.ahoo.cosid.annotation.CosId; + +/** + * @author ahoo wang + */ +public class IntIdEntity { + @CosId + private int id; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } +} diff --git a/cosid-dependencies/build.gradle.kts b/cosid-dependencies/build.gradle.kts index 5a0cfe3bd3..4c40e188b4 100644 --- a/cosid-dependencies/build.gradle.kts +++ b/cosid-dependencies/build.gradle.kts @@ -20,6 +20,7 @@ dependencies { api(libs.guava) api(libs.mybatis) api(libs.mybatisSpringBoot) + api(libs.springDocStarterWebfluxUi) api(libs.junitPioneer) api(libs.hamcrest) api(libs.jmhCore) diff --git a/cosid-proxy-server/build.gradle.kts b/cosid-proxy-server/build.gradle.kts index 11bd449075..a45e3dc681 100644 --- a/cosid-proxy-server/build.gradle.kts +++ b/cosid-proxy-server/build.gradle.kts @@ -35,13 +35,13 @@ application { mainClass.set("me.ahoo.cosid.proxy.server.ProxyServer") applicationDefaultJvmArgs = listOf( - "-Xms512M", - "-Xmx512M", - "-XX:MaxMetaspaceSize=128M", - "-XX:MaxDirectMemorySize=256M", + "-Xms1280M", + "-Xmx1280M", + "-XX:MaxMetaspaceSize=256M", + "-XX:MaxDirectMemorySize=512M", "-Xss1m", "-server", - "-XX:+UseG1GC", + "-XX:+UseZGC", "-Xlog:gc*:file=logs/${applicationName}-gc.log:time,tags:filecount=10,filesize=32M", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=data", @@ -79,6 +79,7 @@ dependencies { implementation("com.google.guava:guava") implementation("io.netty:netty-all") implementation("org.springframework.boot:spring-boot-starter-webflux") + implementation("org.springdoc:springdoc-openapi-starter-webflux-ui") compileOnly("org.projectlombok:lombok") annotationProcessor("org.projectlombok:lombok") annotationProcessor("org.springframework.boot:spring-boot-configuration-processor") diff --git a/cosid-proxy-server/src/dist/config/application.yaml b/cosid-proxy-server/src/dist/config/application.yaml index a08fa7eda6..717a29a864 100644 --- a/cosid-proxy-server/src/dist/config/application.yaml +++ b/cosid-proxy-server/src/dist/config/application.yaml @@ -1,14 +1,24 @@ +management: + endpoints: + web: + exposure: + include: + - cosid + - cosidGenerator + - cosidStringGenerator +springdoc: + show-actuator: true server: port: 8688 spring: application: name: ${service.name:cosid-proxy} - # redis: - # url: redis://localhost:6379 +# redis: +# url: redis://localhost:6379 autoconfigure: exclude: - # - org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration - - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration +# - org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration + - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration # datasource: # url: jdbc:mysql://localhost:3306/cosid_db # username: root @@ -19,15 +29,13 @@ cosid: enabled: true distributor: type: redis - guarder: - enabled: true snowflake: enabled: true segment: enabled: true - mode: chain distributor: type: redis logging: level: me.ahoo.cosid: debug + diff --git a/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/configuration/SwaggerConfiguration.java b/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/configuration/SwaggerConfiguration.java new file mode 100644 index 0000000000..f82a7ef6c3 --- /dev/null +++ b/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/configuration/SwaggerConfiguration.java @@ -0,0 +1,40 @@ +/* + * Copyright [2021-present] [ahoo wang (https://github.com/Ahoo-Wang)]. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.ahoo.cosid.proxy.server.configuration; + +import com.google.common.base.MoreObjects; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springdoc.core.customizers.OpenApiCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SwaggerConfiguration { + + @Bean + public OpenApiCustomizer openApiCustomizer() { + var version = MoreObjects.firstNonNull(getClass().getPackage().getImplementationVersion(), "2.3.0"); + return openApi -> { + var info = new Info() + .title("CosId Proxy Server") + .description("Universal, flexible, high-performance distributed ID generator.") + .contact(new Contact().name("Ahoo Wang").url("https://github.com/Ahoo-Wang/CosId")) + .license(new License().url("https://github.com/Ahoo-Wang/CosId/blob/main/LICENSE").name("Apache 2.0")) + .version(version); + openApi.info(info); + }; + } +} diff --git a/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/controller/IdController.java b/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/controller/IdController.java index 7ba42ebcde..0a85521d1f 100644 --- a/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/controller/IdController.java +++ b/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/controller/IdController.java @@ -15,6 +15,7 @@ import me.ahoo.cosid.provider.IdGeneratorProvider; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -38,6 +39,7 @@ public IdController(IdGeneratorProvider provider) { this.provider = provider; } + @Operation(summary = "Generate a ID by share.") @GetMapping public long generate() { return provider @@ -45,6 +47,7 @@ public long generate() { .generate(); } + @Operation(summary = "Generate a ID by id name.") @GetMapping("{name}") public long generate(@PathVariable String name) { return provider @@ -52,6 +55,7 @@ public long generate(@PathVariable String name) { .generate(); } + @Operation(summary = "Generate a ID as String by share.") @GetMapping("/as-string") public String generateAsString() { return provider @@ -59,6 +63,7 @@ public String generateAsString() { .generateAsString(); } + @Operation(summary = "Generate a ID as String by id name.") @GetMapping("/as-string/{name}") public String generateAsString(@PathVariable String name) { return provider diff --git a/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/controller/MachineController.java b/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/controller/MachineController.java index 092cc758ee..a3b3c67d26 100644 --- a/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/controller/MachineController.java +++ b/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/controller/MachineController.java @@ -19,6 +19,7 @@ import me.ahoo.cosid.machine.MachineIdOverflowException; import me.ahoo.cosid.machine.MachineState; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -46,6 +47,7 @@ public MachineController(MachineIdDistributor distributor) { /** * Distribute a machine ID, the operation is idempotent. */ + @Operation(summary = "Distribute a machine ID, the operation is idempotent.") @PostMapping("/{namespace}") public MachineState distribute(@PathVariable String namespace, int machineBit, InstanceId instanceId, String safeGuardDuration) throws MachineIdOverflowException { return distributor.distribute(namespace, machineBit, instanceId, Duration.parse(safeGuardDuration)); @@ -54,6 +56,7 @@ public MachineState distribute(@PathVariable String namespace, int machineBit, I /** * Revert a machine ID, the operation is idempotent. */ + @Operation(summary = "Revert a machine ID, the operation is idempotent.") @DeleteMapping("/{namespace}") public void revert(@PathVariable String namespace, InstanceId instanceId) { distributor.revert(namespace, instanceId); @@ -63,6 +66,7 @@ public void revert(@PathVariable String namespace, InstanceId instanceId) { * Guard a machine ID. */ @PatchMapping("/{namespace}") + @Operation(summary = "Guard a machine ID.") public void guard(@PathVariable String namespace, InstanceId instanceId, String safeGuardDuration) throws MachineIdLostException { distributor.guard(namespace, instanceId, Duration.parse(safeGuardDuration)); } diff --git a/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/controller/SegmentController.java b/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/controller/SegmentController.java index 4817eaa362..bb84969cfc 100644 --- a/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/controller/SegmentController.java +++ b/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/controller/SegmentController.java @@ -18,6 +18,7 @@ import me.ahoo.cosid.segment.IdSegmentDistributorFactory; import com.google.common.base.Preconditions; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -45,6 +46,7 @@ public SegmentController(IdSegmentDistributorFactory distributorFactory) { /** * Create an ID segment dispatcher, the operation is idempotent. */ + @Operation(summary = "Create an ID segment dispatcher, the operation is idempotent.") @PostMapping("/distributor/{namespace}/{name}") public void createDistributor(@PathVariable String namespace, @PathVariable String name, long offset, long step) { String namespacedName = IdSegmentDistributor.getNamespacedName(namespace, name); @@ -52,6 +54,7 @@ public void createDistributor(@PathVariable String namespace, @PathVariable Stri key -> distributorFactory.create(new IdSegmentDistributorDefinition(namespace, name, offset, step))); } + @Operation(summary = "Get next max id.") @PatchMapping("/{namespace}/{name}") public long nextMaxId(@PathVariable String namespace, @PathVariable String name, long step) { String namespacedName = IdSegmentDistributor.getNamespacedName(namespace, name); diff --git a/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/error/ErrorResponse.java b/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/error/ErrorResponse.java index 8217f91b90..150bea5900 100644 --- a/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/error/ErrorResponse.java +++ b/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/error/ErrorResponse.java @@ -25,10 +25,13 @@ public class ErrorResponse { public static final String BAD_REQUEST = "400"; + public static final String MACHINE_ID_OVERFLOW = "M-01"; + public static final String NOT_FOUND_MACHINE_STATE = "M-02"; + public static final String MACHINE_ID_LOST = "M-03"; private final String code; private final String msg; - @Nullable + private final List errors; public ErrorResponse(String code, String msg, List errors) { @@ -45,6 +48,7 @@ public String getMsg() { return msg; } + @Nullable public List getErrors() { return errors; } diff --git a/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/error/GlobalRestExceptionHandler.java b/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/error/GlobalRestExceptionHandler.java index 7566466a37..cd8a328c8a 100644 --- a/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/error/GlobalRestExceptionHandler.java +++ b/cosid-proxy-server/src/main/java/me/ahoo/cosid/proxy/server/error/GlobalRestExceptionHandler.java @@ -13,6 +13,10 @@ package me.ahoo.cosid.proxy.server.error; +import static me.ahoo.cosid.proxy.server.error.ErrorResponse.MACHINE_ID_LOST; +import static me.ahoo.cosid.proxy.server.error.ErrorResponse.MACHINE_ID_OVERFLOW; +import static me.ahoo.cosid.proxy.server.error.ErrorResponse.NOT_FOUND_MACHINE_STATE; + import me.ahoo.cosid.machine.MachineIdLostException; import me.ahoo.cosid.machine.MachineIdOverflowException; import me.ahoo.cosid.machine.NotFoundMachineStateException; @@ -56,21 +60,21 @@ public ResponseEntity handleClientException(IllegalArgumentExcept public ResponseEntity handleCosIdException(MachineIdOverflowException ex) { return ResponseEntity .badRequest() - .body(ErrorResponse.of("M-01", ex.getMessage())); + .body(ErrorResponse.of(MACHINE_ID_OVERFLOW, ex.getMessage())); } @ExceptionHandler(NotFoundMachineStateException.class) public ResponseEntity handleCosIdException(NotFoundMachineStateException ex) { return ResponseEntity .badRequest() - .body(ErrorResponse.of("M-02", ex.getMessage())); + .body(ErrorResponse.of(NOT_FOUND_MACHINE_STATE, ex.getMessage())); } @ExceptionHandler(MachineIdLostException.class) public ResponseEntity handleCosIdException(MachineIdLostException ex) { return ResponseEntity .badRequest() - .body(ErrorResponse.of("M-03", ex.getMessage())); + .body(ErrorResponse.of(MACHINE_ID_LOST, ex.getMessage())); } @ResponseStatus(HttpStatus.BAD_REQUEST) diff --git a/cosid-proxy-server/src/main/resources/application.yaml b/cosid-proxy-server/src/main/resources/application.yaml index abe91e1457..717a29a864 100644 --- a/cosid-proxy-server/src/main/resources/application.yaml +++ b/cosid-proxy-server/src/main/resources/application.yaml @@ -1,3 +1,13 @@ +management: + endpoints: + web: + exposure: + include: + - cosid + - cosidGenerator + - cosidStringGenerator +springdoc: + show-actuator: true server: port: 8688 spring: @@ -19,15 +29,13 @@ cosid: enabled: true distributor: type: redis - guarder: - enabled: true snowflake: enabled: true segment: enabled: true - mode: chain distributor: type: redis logging: level: me.ahoo.cosid: debug + diff --git a/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ErrorResponse.java b/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ErrorResponse.java index f67a2d7dcc..496a990b66 100644 --- a/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ErrorResponse.java +++ b/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ErrorResponse.java @@ -29,6 +29,9 @@ public class ErrorResponse { public static final String BAD_REQUEST = "400"; + public static final String MACHINE_ID_OVERFLOW = "M-01"; + public static final String NOT_FOUND_MACHINE_STATE = "M-02"; + public static final String MACHINE_ID_LOST = "M-03"; private final String code; private final String msg; @@ -54,23 +57,6 @@ public List getErrors() { return errors; } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof ErrorResponse)) { - return false; - } - ErrorResponse that = (ErrorResponse) o; - return Objects.equals(getCode(), that.getCode()) && Objects.equals(getMsg(), that.getMsg()) && Objects.equals(getErrors(), that.getErrors()); - } - - @Override - public int hashCode() { - return Objects.hash(getCode(), getMsg(), getErrors()); - } - public static ErrorResponse of(String code, String msg) { return new ErrorResponse(code, msg, Collections.emptyList()); } diff --git a/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ProxyIdSegmentDistributor.java b/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ProxyIdSegmentDistributor.java index 799ce853ec..6abdfadda5 100644 --- a/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ProxyIdSegmentDistributor.java +++ b/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ProxyIdSegmentDistributor.java @@ -13,8 +13,6 @@ package me.ahoo.cosid.proxy; -import static me.ahoo.cosid.proxy.ProxyMachineIdDistributor.JSON; - import me.ahoo.cosid.segment.IdSegmentDistributor; import com.google.common.base.Preconditions; @@ -23,9 +21,9 @@ import lombok.extern.slf4j.Slf4j; import okhttp3.OkHttpClient; import okhttp3.Request; -import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; +import okhttp3.internal.Util; import javax.annotation.Nonnull; @@ -77,7 +75,7 @@ public long nextMaxId(long step) { Request request = new Request.Builder() .url(apiUrl) - .patch(RequestBody.create(JSON, "")) + .patch(Util.EMPTY_REQUEST) .build(); try (Response response = client.newCall(request).execute()) { ResponseBody responseBody = response.body(); diff --git a/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ProxyIdSegmentDistributorFactory.java b/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ProxyIdSegmentDistributorFactory.java index 2c322760d9..d187050e2d 100644 --- a/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ProxyIdSegmentDistributorFactory.java +++ b/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ProxyIdSegmentDistributorFactory.java @@ -13,8 +13,6 @@ package me.ahoo.cosid.proxy; -import static me.ahoo.cosid.proxy.ProxyMachineIdDistributor.JSON; - import me.ahoo.cosid.segment.IdSegmentDistributor; import me.ahoo.cosid.segment.IdSegmentDistributorDefinition; import me.ahoo.cosid.segment.IdSegmentDistributorFactory; @@ -24,9 +22,9 @@ import lombok.extern.slf4j.Slf4j; import okhttp3.OkHttpClient; import okhttp3.Request; -import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; +import okhttp3.internal.Util; import javax.annotation.Nonnull; @@ -60,7 +58,7 @@ public IdSegmentDistributor create(IdSegmentDistributorDefinition definition) { Request request = new Request.Builder() .url(apiUrl) - .post(RequestBody.Companion.create("", JSON)) + .post(Util.EMPTY_REQUEST) .build(); try (Response response = client.newCall(request).execute()) { ResponseBody responseBody = response.body(); diff --git a/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ProxyMachineIdDistributor.java b/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ProxyMachineIdDistributor.java index 35b61b24e3..c945dafcbe 100644 --- a/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ProxyMachineIdDistributor.java +++ b/cosid-proxy/src/main/java/me/ahoo/cosid/proxy/ProxyMachineIdDistributor.java @@ -13,8 +13,12 @@ package me.ahoo.cosid.proxy; -import me.ahoo.cosid.machine.ClockBackwardsSynchronizer; +import static me.ahoo.cosid.proxy.ErrorResponse.MACHINE_ID_LOST; +import static me.ahoo.cosid.proxy.ErrorResponse.MACHINE_ID_OVERFLOW; +import static me.ahoo.cosid.proxy.ErrorResponse.NOT_FOUND_MACHINE_STATE; + import me.ahoo.cosid.machine.AbstractMachineIdDistributor; +import me.ahoo.cosid.machine.ClockBackwardsSynchronizer; import me.ahoo.cosid.machine.InstanceId; import me.ahoo.cosid.machine.MachineIdLostException; import me.ahoo.cosid.machine.MachineIdOverflowException; @@ -25,12 +29,11 @@ import com.google.common.base.Strings; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; -import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; +import okhttp3.internal.Util; import java.time.Duration; @@ -43,8 +46,6 @@ @Slf4j public class ProxyMachineIdDistributor extends AbstractMachineIdDistributor { - public static final MediaType JSON - = MediaType.get("application/json; charset=utf-8"); private final OkHttpClient client; private final String proxyHost; @@ -67,7 +68,7 @@ protected MachineState distributeRemote(String namespace, int machineBit, Instan Request request = new Request.Builder() .url(apiUrl) - .post(RequestBody.create(JSON, "")) + .post(Util.EMPTY_REQUEST) .build(); try (Response response = client.newCall(request).execute()) { ResponseBody responseBody = response.body(); @@ -81,12 +82,10 @@ protected MachineState distributeRemote(String namespace, int machineBit, Instan return Jsons.OBJECT_MAPPER.readValue(bodyStr, MachineStateDto.class); } ErrorResponse errorResponse = Jsons.OBJECT_MAPPER.readValue(bodyStr, ErrorResponse.class); - switch (errorResponse.getCode()) { - case "M-01": - throw new MachineIdOverflowException(machineBit, instanceId); - default: - throw new IllegalStateException(Strings.lenientFormat("Unexpected code:[%s] - message:[%s].", errorResponse.getCode(), errorResponse.getMsg())); + if (errorResponse.getCode().equals(MACHINE_ID_OVERFLOW)) { + throw new MachineIdOverflowException(machineBit, instanceId); } + throw new IllegalStateException(Strings.lenientFormat("Unexpected code:[%s] - message:[%s].", errorResponse.getCode(), errorResponse.getMsg())); } } @@ -124,7 +123,7 @@ protected void guardRemote(String namespace, InstanceId instanceId, MachineState Request request = new Request.Builder() .url(apiUrl) - .patch(RequestBody.create(JSON, "")) + .patch(Util.EMPTY_REQUEST) .build(); try (Response response = client.newCall(request).execute()) { ResponseBody responseBody = response.body(); @@ -139,12 +138,9 @@ protected void guardRemote(String namespace, InstanceId instanceId, MachineState ErrorResponse errorResponse = Jsons.OBJECT_MAPPER.readValue(bodyStr, ErrorResponse.class); switch (errorResponse.getCode()) { - case "M-02": - throw new NotFoundMachineStateException(namespace, instanceId); - case "M-03": - throw new MachineIdLostException(namespace, instanceId, machineState); - default: - throw new IllegalStateException("Unexpected value: " + errorResponse.getCode()); + case NOT_FOUND_MACHINE_STATE -> throw new NotFoundMachineStateException(namespace, instanceId); + case MACHINE_ID_LOST -> throw new MachineIdLostException(namespace, instanceId, machineState); + default -> throw new IllegalStateException("Unexpected value: " + errorResponse.getCode()); } } } diff --git a/cosid-proxy/src/test/java/me/ahoo/cosid/proxy/JsonsTest.java b/cosid-proxy/src/test/java/me/ahoo/cosid/proxy/JsonsTest.java index e8f169daab..0e1046b712 100644 --- a/cosid-proxy/src/test/java/me/ahoo/cosid/proxy/JsonsTest.java +++ b/cosid-proxy/src/test/java/me/ahoo/cosid/proxy/JsonsTest.java @@ -25,7 +25,9 @@ void serialize() { ErrorResponse errorResponse = ErrorResponse.badRequest("badRequest"); String jsonStr = Jsons.serialize(errorResponse); ErrorResponse actual = Jsons.deserialize(jsonStr, ErrorResponse.class); - assertThat(actual, equalTo(errorResponse)); + assertThat(actual.getCode(), equalTo(errorResponse.getCode())); + assertThat(actual.getMsg(), equalTo(errorResponse.getMsg())); + assertThat(actual.getErrors(), equalTo(errorResponse.getErrors())); } } diff --git a/cosid-proxy/src/test/java/me/ahoo/cosid/proxy/ProxyMachineIdDistributorTest.java b/cosid-proxy/src/test/java/me/ahoo/cosid/proxy/ProxyMachineIdDistributorTest.java index 86691f3592..16895c6829 100644 --- a/cosid-proxy/src/test/java/me/ahoo/cosid/proxy/ProxyMachineIdDistributorTest.java +++ b/cosid-proxy/src/test/java/me/ahoo/cosid/proxy/ProxyMachineIdDistributorTest.java @@ -14,11 +14,16 @@ package me.ahoo.cosid.proxy; import me.ahoo.cosid.machine.ClockBackwardsSynchronizer; +import me.ahoo.cosid.machine.InstanceId; import me.ahoo.cosid.machine.MachineIdDistributor; import me.ahoo.cosid.machine.MachineStateStorage; +import me.ahoo.cosid.machine.NotFoundMachineStateException; +import me.ahoo.cosid.test.Assert; +import me.ahoo.cosid.test.MockIdGenerator; import me.ahoo.cosid.test.machine.distributor.MachineIdDistributorSpec; import okhttp3.OkHttpClient; +import org.junit.jupiter.api.Test; class ProxyMachineIdDistributorTest extends MachineIdDistributorSpec { @@ -29,7 +34,19 @@ protected MachineIdDistributor getDistributor() { @Override public void guardLost() { - //TODO - //super.guardLost(); + //ignore + } + + @Test + public void guardIfNotFoundMachineState() { + MachineIdDistributor distributor = getDistributor(); + String namespace = MockIdGenerator.usePrefix("guardIfNotFoundMachineState").generateAsString(); + InstanceId instanceId = mockInstance(0, false); + MachineStateStorage.IN_MEMORY.set(namespace, 10, instanceId); + + Assert.assertThrows(NotFoundMachineStateException.class, () -> { + distributor.guard(namespace, instanceId, MachineIdDistributor.FOREVER_SAFE_GUARD_DURATION); + }); + } } diff --git a/cosid-proxy/src/test/java/me/ahoo/cosid/proxy/ProxyServerLauncher.java b/cosid-proxy/src/test/java/me/ahoo/cosid/proxy/ProxyServerLauncher.java index bff6d0752e..44549cbe5f 100644 --- a/cosid-proxy/src/test/java/me/ahoo/cosid/proxy/ProxyServerLauncher.java +++ b/cosid-proxy/src/test/java/me/ahoo/cosid/proxy/ProxyServerLauncher.java @@ -34,7 +34,7 @@ public class ProxyServerLauncher { REDIS_CONTAINER.start(); int cosidProxyExposedPort = 8688; - COSID_PROXY_CONTAINER = new GenericContainer(DockerImageName.parse("ahoowang/cosid-proxy:2.2.1")) + COSID_PROXY_CONTAINER = new GenericContainer(DockerImageName.parse("ahoowang/cosid-proxy:2.3.0")) .withNetwork(NETWORK_CONTAINER) .withExposedPorts(cosidProxyExposedPort) .withReuse(true) diff --git a/cosid-test/src/main/java/me/ahoo/cosid/test/machine/distributor/MachineIdDistributorSpec.java b/cosid-test/src/main/java/me/ahoo/cosid/test/machine/distributor/MachineIdDistributorSpec.java index f13d64c096..10ad224ee2 100644 --- a/cosid-test/src/main/java/me/ahoo/cosid/test/machine/distributor/MachineIdDistributorSpec.java +++ b/cosid-test/src/main/java/me/ahoo/cosid/test/machine/distributor/MachineIdDistributorSpec.java @@ -32,7 +32,7 @@ public abstract class MachineIdDistributorSpec { private static final int TEST_MACHINE_BIT = 5; private static final Duration TEST_SAFE_GUARD_DURATION = Duration.ofSeconds(5); - static InstanceId mockInstance(int port, boolean stable) { + protected static InstanceId mockInstance(int port, boolean stable) { return InstanceId.of(TEST_HOST, port, stable); } diff --git a/gradle.properties b/gradle.properties index 3af26ac2eb..a893eabe2c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ # limitations under the License. # group=me.ahoo.cosid -version=2.3.0 +version=2.3.1 description=Universal, flexible, high-performance distributed ID generator. website=https://github.com/Ahoo-Wang/CosId issues=https://github.com/Ahoo-Wang/CosId/issues diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b787cdf5dc..494137ad17 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,7 @@ mybatis = "3.5.13" mybatisSpringBoot = "3.0.2" junitPioneer = "2.0.1" axon = "4.8.1" +springDoc = "2.1.0" hamcrest = "2.2" mockk = "1.13.5" detektFormatting = "1.23.1" @@ -27,6 +28,7 @@ testcontainersBom = { module = "org.testcontainers:testcontainers-bom", version. guava = { module = "com.google.guava:guava", version.ref = "guava" } mybatis = { module = "org.mybatis:mybatis", version.ref = "mybatis" } mybatisSpringBoot = { module = "org.mybatis.spring.boot:mybatis-spring-boot-starter", version.ref = "mybatisSpringBoot" } +springDocStarterWebfluxUi = { module = "org.springdoc:springdoc-openapi-starter-webflux-ui", version.ref = "springDoc" } junitPioneer = { module = "org.junit-pioneer:junit-pioneer", version.ref = "junitPioneer" } hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" } mockk = { module = "io.mockk:mockk", version.ref = "mockk" }