diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml deleted file mode 100644 index f97516343..000000000 --- a/.github/workflows/codecov.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Codecov - -on: - push: - branches: - - 2023.0 - - 2022.0 - - 2021.0 - - 2020.0 - - hoxton - - greenwich - pull_request: - branches: - - 2023.0 - - 2022.0 - - 2021.0 - - 2020.0 - - hoxton - - greenwich - -jobs: - codecov: - runs-on: ubuntu-latest - - steps: - - name: Checkout codes - uses: actions/checkout@v4 - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: 17 - - name: Test with Maven - run: mvn clean test -B -U -Psonatype - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - with: - files: ${{ github.workspace }}/target/site/jacoco/jacoco.xml diff --git a/.github/workflows/junit.yml b/.github/workflows/junit.yml new file mode 100644 index 000000000..34bb4153f --- /dev/null +++ b/.github/workflows/junit.yml @@ -0,0 +1,86 @@ +name: Junit Test + +on: + push: + branches: + - 2024 + - 2023 + - 2022 + - 2021 + - 2020 + - hoxton + - greenwich + pull_request: + branches: + - 2024 + - 2023 + - 2022 + - 2021 + - 2020 + - hoxton + - greenwich + +jobs: + set-jdks: + runs-on: ubuntu-latest + outputs: + jdks: ${{ steps.set-jdks.outputs.jdks }} + steps: + - name: Set JDK matrix based on branch + id: set-jdks + run: | + shopt -s nocasematch + branch_name=${{ github.ref_name }} + if [ -n "${{ github.base_ref }}" ]; then + branch_name=${{ github.base_ref }} + fi + echo $branch_name + if [[ "$branch_name" == "2024" ]]; then + echo "jdks=[17,21]" >> $GITHUB_OUTPUT + elif [[ "$branch_name" == "2023" ]]; then + echo "jdks=[17,21]" >> $GITHUB_OUTPUT + elif [[ "$branch_name" == "2022" ]]; then + echo "jdks=[17,21]" >> $GITHUB_OUTPUT + elif [[ "$branch_name" == "2021" ]]; then + echo "jdks=[8,11,17,21]" >> $GITHUB_OUTPUT + elif [[ "$branch_name" == "2020" ]]; then + echo "jdks=[8,11,17,21]" >> $GITHUB_OUTPUT + elif [[ "$branch_name" == "hoxton" ]]; then + echo "jdks=[8,11,17]" >> $GITHUB_OUTPUT + elif [[ "$branch_name" == "greenwich" ]]; then + echo "jdks=[8,11]" >> $GITHUB_OUTPUT + else + echo "jdks=[17]" >> $GITHUB_OUTPUT + fi + shopt -u nocasematch + junit: + strategy: + matrix: + java: ${{ fromJson(needs.set-jdks.outputs.jdks) }} + os: [ 'windows-latest', 'ubuntu-latest' ] + runs-on: ${{ matrix.os }} + needs: set-jdks + steps: + - name: Checkout codes + uses: actions/checkout@v4 + - name: Set up JDK ${{ matrix.java }} + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: ${{ matrix.java }} + - name: Cache local Maven repository + uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Test with Maven + run: mvn clean test -B -U -Psonatype + - name: Upload coverage to Codecov + if: matrix.os == 'ubuntu-latest' && matrix.java == 17 + uses: codecov/codecov-action@v4 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + with: + files: ${{ github.workspace }}/target/site/jacoco/jacoco.xml diff --git a/.github/workflows/junit_test.yml b/.github/workflows/junit_test.yml deleted file mode 100644 index 0ecdb273b..000000000 --- a/.github/workflows/junit_test.yml +++ /dev/null @@ -1,46 +0,0 @@ -# This workflow will build a Java project with Maven -# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven - -name: Test with Junit - -on: - push: - branches: - - hoxton - - 2021.0 - - 2020.0 - - greenwich - pull_request: - branches: - - hoxton - - 2021.0 - - 2020.0 - - greenwich - -jobs: - junit: - strategy: - matrix: - java: [ 8, 11, 17 ] - os: [ 'windows-latest', 'ubuntu-latest' ] - - runs-on: ${{ matrix.os }} - - steps: - - name: Checkout codes - uses: actions/checkout@v4 - - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: ${{ matrix.java }} - - name: Cache local Maven repository - uses: actions/cache@v4 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- - - name: Test with Maven - run: mvn clean test -B -U -Psonatype - diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 3a9d462a9..70b426b15 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -3,10 +3,11 @@ name: Snapshot on: push: branches: - - 2023.0 - - 2022.0 - - 2021.0 - - 2020.0 + - 2024 + - 2023 + - 2022 + - 2021 + - 2020 - hoxton - greenwich @@ -14,12 +15,12 @@ jobs: check-snapshot: runs-on: ubuntu-latest outputs: - IS_SNAPSHOT: ${{ steps.set_output_1.outputs.IS_SNAPSHOT }} + IS_SNAPSHOT: ${{ steps.check-deploy-type.outputs.IS_SNAPSHOT }} steps: - name: Checkout codes uses: actions/checkout@v4 - name: Check deploy type - id: set_output_1 + id: check-deploy-type run: | line="$(grep SNAPSHOT pom.xml || true)" echo $line @@ -28,17 +29,44 @@ jobs: else echo "IS_SNAPSHOT=false" >> $GITHUB_OUTPUT fi + set-jdk: + runs-on: ubuntu-latest + outputs: + jdk: ${{ steps.set-jdk.outputs.jdk }} + steps: + - name: Set JDK based on branch + id: set-jdk + run: | + shopt -s nocasematch + if [[ "${{ github.ref_name }}" == "2024" ]]; then + echo "jdk=17" >> $GITHUB_OUTPUT + elif [[ "${{ github.ref_name }}" == "2023" ]]; then + echo "jdk=17" >> $GITHUB_OUTPUT + elif [[ "${{ github.ref_name }}" == "2022" ]]; then + echo "jdk=17" >> $GITHUB_OUTPUT + elif [[ "${{ github.ref_name }}" == "2021" ]]; then + echo "jdk=8" >> $GITHUB_OUTPUT + elif [[ "${{ github.ref_name }}" == "2020" ]]; then + echo "jdk=8" >> $GITHUB_OUTPUT + elif [[ "${{ github.ref_name }}" == "hoxton" ]]; then + echo "jdk=8" >> $GITHUB_OUTPUT + elif [[ "${{ github.ref_name }}" == "greenwich" ]]; then + echo "jdk=8" >> $GITHUB_OUTPUT + else + echo "jdk=17" >> $GITHUB_OUTPUT + fi + shopt -u nocasematch snapshot: runs-on: ubuntu-latest - needs: check-snapshot + needs: [ check-snapshot, set-jdk ] if: ${{ needs.check-snapshot.outputs.IS_SNAPSHOT == 'true' }} steps: - name: Checkout codes uses: actions/checkout@v4 - - name: Set up JDK 17 + - name: Set up JDK ${{ needs.set-jdk.outputs.jdk }} uses: actions/setup-java@v4 with: - java-version: '17' + java-version: ${{ needs.set-jdk.outputs.jdk }} distribution: 'temurin' server-id: nexus-snapshots server-username: MAVEN_USERNAME diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fb60893d..8bcf48996 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,3 +32,4 @@ - [feat:use polaris-all for shading third-party dependencies.](https://github.com/Tencent/spring-cloud-tencent/pull/1549) - [feat:support default instance circuit breaker rule.](https://github.com/Tencent/spring-cloud-tencent/pull/1551) - [fix: fix count circuit breaker in gateway & return 404 when context api does not match.](https://github.com/Tencent/spring-cloud-tencent/pull/1552) +- [docs:simplify GitHub Actions.](https://github.com/Tencent/spring-cloud-tencent/pull/1553) diff --git a/README.md b/README.md index 0ec14dc27..254b994c9 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Contributors](https://img.shields.io/github/contributors/Tencent/spring-cloud-tencent)](https://github.com/Tencent/spring-cloud-tencent/graphs/contributors) [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Test with Junit](https://github.com/Tencent/spring-cloud-tencent/actions/workflows/junit_test.yml/badge.svg)](https://github.com/Tencent/spring-cloud-tencent/actions/workflows/junit_test.yml) +[![Junit Test](https://github.com/Tencent/spring-cloud-tencent/actions/workflows/junit.yml/badge.svg?branch=hoxton)](https://github.com/Tencent/spring-cloud-tencent/actions/workflows/junit.yml) [![codecov.io](https://codecov.io/gh/Tencent/spring-cloud-tencent/branch/hoxton/graph/badge.svg)](https://codecov.io/gh/Tencent/spring-cloud-tencent?branch=hoxton) English | [简体中文](./README-zh.md) @@ -63,7 +63,7 @@ dependencies. > Notice: > -> Support Spring Cloud 2023.0, 2022.0, 2021.0, 2020.0, Hoxton. +> Support Spring Cloud 2023, 2022, 2021, 2020, Hoxton. > > The version list of Spring Cloud Tencent can be found > in diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java index 56ed7aca1..af758762e 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java @@ -28,6 +28,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestHeader; @@ -42,6 +43,7 @@ import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; * * @author Haotian Zhang */ +@RefreshScope @RestController @RequestMapping("/quickstart/callee") public class QuickstartCalleeController { diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java index 396a3fd0f..660e4aafe 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java @@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -43,6 +44,7 @@ import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; * * @author Haotian Zhang */ +@RefreshScope @RestController @RequestMapping("/quickstart/callee") public class QuickstartCalleeController { diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml index cefd6f6f8..995e2eb5e 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml @@ -48,3 +48,14 @@ spring: - Path=/QuickstartCallerService/** filters: - StripPrefix=1 + - id: QuickstartCalleeService + uri: lb://QuickstartCalleeService + predicates: + - Path=/QuickstartCalleeService/** + filters: + - StripPrefix=1 +logging: + file: + name: /sct-demo-logs/${spring.application.name}/root.log + level: + root: INFO diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-security-protection-plugin/src/test/java/com/tencent/cloud/plugin/protection/SecurityProtectionAutoConfigurationTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-security-protection-plugin/src/test/java/com/tencent/cloud/plugin/protection/SecurityProtectionAutoConfigurationTest.java deleted file mode 100644 index cb93c89ea..000000000 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-security-protection-plugin/src/test/java/com/tencent/cloud/plugin/protection/SecurityProtectionAutoConfigurationTest.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making spring-cloud-tencent available. - * - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * 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 com.tencent.cloud.plugin.protection; - -import java.security.Permission; -import java.util.ArrayList; -import java.util.List; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.web.servlet.function.RouterFunction; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -/** - * Test for {@link SecurityProtectionAutoConfiguration}. - */ -@ExtendWith(MockitoExtension.class) -class SecurityProtectionAutoConfigurationTest { - - @Mock - private ConfigurableApplicationContext applicationContext; - - @Test - void testServletProtectionNoRouterFunctions() { - // Arrange - SecurityProtectionAutoConfiguration.ServletProtectionConfiguration config = - new SecurityProtectionAutoConfiguration.ServletProtectionConfiguration(); - config.applicationContext = applicationContext; - config.routerFunctions = null; - - // Act - config.afterPropertiesSet(); - - // Verify - // Should not call exit when no RouterFunctions present - verify(applicationContext, never()).close(); - } - - @Test - void testServletProtectionEmptyRouterFunctions() { - // Arrange - SecurityProtectionAutoConfiguration.ServletProtectionConfiguration config = - new SecurityProtectionAutoConfiguration.ServletProtectionConfiguration(); - config.applicationContext = applicationContext; - config.routerFunctions = new ArrayList<>(); - - // Act - config.afterPropertiesSet(); - - // Verify - // Should not call exit when RouterFunctions list is empty - verify(applicationContext, never()).close(); - } - - @Test - void testServletProtectionWithRouterFunctions() { - // Arrange - SecurityProtectionAutoConfiguration.ServletProtectionConfiguration config = - new SecurityProtectionAutoConfiguration.ServletProtectionConfiguration(); - config.applicationContext = mock(ConfigurableApplicationContext.class); - List routerFunctions = new ArrayList<>(); - routerFunctions.add(mock(RouterFunction.class)); - config.routerFunctions = routerFunctions; - - SecurityManager originalSecurityManager = System.getSecurityManager(); - System.setSecurityManager(new ExitSecurityManager()); - - try { - config.afterPropertiesSet(); - } - catch (SecurityException e) { - // Ignore - } - finally { - System.setSecurityManager(originalSecurityManager); - } - } - - @Test - void testReactiveProtectionNoRouterFunctions() { - // Arrange - SecurityProtectionAutoConfiguration.ReactiveProtectionConfiguration config = - new SecurityProtectionAutoConfiguration.ReactiveProtectionConfiguration(); - config.applicationContext = applicationContext; - config.routerFunctions = null; - - // Act - config.afterPropertiesSet(); - - // Verify - verify(applicationContext, never()).close(); - } - - @Test - void testReactiveProtectionEmptyRouterFunctions() { - // Arrange - SecurityProtectionAutoConfiguration.ReactiveProtectionConfiguration config = - new SecurityProtectionAutoConfiguration.ReactiveProtectionConfiguration(); - config.applicationContext = applicationContext; - config.routerFunctions = new ArrayList<>(); - - // Act - config.afterPropertiesSet(); - - // Verify - verify(applicationContext, never()).close(); - } - - @Test - void testReactiveProtectionWithRouterFunctions() { - // Arrange - SecurityProtectionAutoConfiguration.ReactiveProtectionConfiguration config = - new SecurityProtectionAutoConfiguration.ReactiveProtectionConfiguration(); - config.applicationContext = mock(ConfigurableApplicationContext.class); - List routerFunctions = new ArrayList<>(); - routerFunctions.add(mock(org.springframework.web.reactive.function.server.RouterFunction.class)); - config.routerFunctions = routerFunctions; - - SecurityManager originalSecurityManager = System.getSecurityManager(); - System.setSecurityManager(new ExitSecurityManager()); - - try { - config.afterPropertiesSet(); - } - catch (SecurityException e) { - // Ignore - } - finally { - System.setSecurityManager(originalSecurityManager); - } - } - - @Test - void testInterruptedExceptionHandling() throws InterruptedException { - // Arrange - ConfigurableApplicationContext mockContext = mock(ConfigurableApplicationContext.class); - Thread testThread = new Thread(() -> ExitUtils.exit(mockContext, 3000)); - - - - SecurityManager originalSecurityManager = System.getSecurityManager(); - System.setSecurityManager(new ExitSecurityManager()); - - try { - // Act - testThread.start(); - testThread.interrupt(); - Thread.sleep(6000); - } - catch (SecurityException e) { - // Ignore - } - finally { - System.setSecurityManager(originalSecurityManager); - } - } - - public static class ExitSecurityManager extends SecurityManager { - - @Override - public void checkPermission(Permission perm) { - if (perm.getName().contains("exitVM")) { - throw new SecurityException("System.exit is not allowed"); - } - } - } -} diff --git a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/listener/FailedEventApplicationListenerTest.java b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/listener/FailedEventApplicationListenerTest.java deleted file mode 100644 index 8e38f769f..000000000 --- a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/listener/FailedEventApplicationListenerTest.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making spring-cloud-tencent available. - * - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * 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 com.tencent.cloud.polaris.context.listener; - -import java.security.Permission; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import org.springframework.boot.context.event.ApplicationFailedEvent; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ConfigurableApplicationContext; - -import static org.mockito.Mockito.when; - - -class FailedEventApplicationListenerTest { - - @Mock - private ConfigurableApplicationContext mockConfigurableContext; - - @Mock - private ApplicationContext mockApplicationContext; - - @Mock - private ApplicationFailedEvent mockFailedEvent; - - private FailedEventApplicationListener listener; - - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - listener = new FailedEventApplicationListener(); - } - - @Test - void testSetApplicationContext() { - // Test setting application context - listener.setApplicationContext(mockApplicationContext); - } - - @Test - void testOnApplicationEventWithConfigurableContext() { - // Arrange - listener.setApplicationContext(mockConfigurableContext); - when(mockFailedEvent.getException()).thenReturn(new RuntimeException("Test Exception")); - - SecurityManager originalSecurityManager = System.getSecurityManager(); - System.setSecurityManager(new ExitSecurityManager()); - - try { - // Act - listener.onApplicationEvent(mockFailedEvent); - } - catch (SecurityException e) { - // Ignore - } - finally { - System.setSecurityManager(originalSecurityManager); - } - } - - @Test - void testOnApplicationEventWithNonConfigurableContext() { - // Arrange - listener.setApplicationContext(mockApplicationContext); - when(mockFailedEvent.getException()).thenReturn(new RuntimeException("Test Exception")); - - SecurityManager originalSecurityManager = System.getSecurityManager(); - System.setSecurityManager(new ExitSecurityManager()); - - try { - // Act - listener.onApplicationEvent(mockFailedEvent); - } - catch (SecurityException e) { - // Ignore - } - finally { - System.setSecurityManager(originalSecurityManager); - } - } - - @Test - void testOnApplicationEventWithInterruptedException() { - // Arrange - listener.setApplicationContext(mockConfigurableContext); - Thread.currentThread().interrupt(); // Simulate interruption - - - SecurityManager originalSecurityManager = System.getSecurityManager(); - System.setSecurityManager(new ExitSecurityManager()); - - try { - // Act - listener.onApplicationEvent(mockFailedEvent); - } - catch (SecurityException e) { - // Ignore - } - finally { - System.setSecurityManager(originalSecurityManager); - } - } - - @Test - void testOnApplicationEventWithNullException() { - // Arrange - listener.setApplicationContext(mockConfigurableContext); - when(mockFailedEvent.getException()).thenReturn(null); - - - SecurityManager originalSecurityManager = System.getSecurityManager(); - System.setSecurityManager(new ExitSecurityManager()); - - try { - // Act - listener.onApplicationEvent(mockFailedEvent); - } - catch (SecurityException e) { - // Ignore - } - finally { - System.setSecurityManager(originalSecurityManager); - } - } - - public static class ExitSecurityManager extends SecurityManager { - - @Override - public void checkPermission(Permission perm) { - if (perm.getName().contains("exitVM")) { - throw new SecurityException("System.exit is not allowed"); - } - } - } -}