diff --git a/flashlib.core.scheduling/src/main/java/com/flash3388/flashlib/scheduling/impl/SingleThreadedScheduler.java b/flashlib.core.scheduling/src/main/java/com/flash3388/flashlib/scheduling/impl/SingleThreadedScheduler.java index 8d641a5f4..e95deae96 100644 --- a/flashlib.core.scheduling/src/main/java/com/flash3388/flashlib/scheduling/impl/SingleThreadedScheduler.java +++ b/flashlib.core.scheduling/src/main/java/com/flash3388/flashlib/scheduling/impl/SingleThreadedScheduler.java @@ -14,6 +14,7 @@ import com.flash3388.flashlib.scheduling.impl.triggers.GenericTrigger; import com.flash3388.flashlib.scheduling.impl.triggers.ManualBasedTrigger; import com.flash3388.flashlib.scheduling.impl.triggers.TriggerActionController; +import com.flash3388.flashlib.scheduling.impl.triggers.TriggerActionControllerImpl; import com.flash3388.flashlib.scheduling.impl.triggers.TriggerBaseImpl; import com.flash3388.flashlib.scheduling.triggers.ManualTrigger; import com.flash3388.flashlib.scheduling.triggers.Trigger; @@ -263,7 +264,7 @@ public ActionGroup newActionGroup(ActionGroupType type) { } private void executeTriggers() { - TriggerActionController controller = new TriggerActionController(); + TriggerActionControllerImpl controller = new TriggerActionControllerImpl(); for (GenericTrigger trigger : mTriggers) { trigger.update(controller); } diff --git a/flashlib.core.scheduling/src/main/java/com/flash3388/flashlib/scheduling/impl/triggers/TriggerActionController.java b/flashlib.core.scheduling/src/main/java/com/flash3388/flashlib/scheduling/impl/triggers/TriggerActionController.java index b4d1125c8..1257a0d4e 100644 --- a/flashlib.core.scheduling/src/main/java/com/flash3388/flashlib/scheduling/impl/triggers/TriggerActionController.java +++ b/flashlib.core.scheduling/src/main/java/com/flash3388/flashlib/scheduling/impl/triggers/TriggerActionController.java @@ -2,42 +2,9 @@ import com.flash3388.flashlib.scheduling.actions.Action; -import java.util.ArrayList; -import java.util.List; +public interface TriggerActionController { -public class TriggerActionController { - - private final List mActionsToStartIfRunning; - private final List mActionsToStopIfRunning; - private final List mActionsToToggle; - - public TriggerActionController() { - mActionsToStartIfRunning = new ArrayList<>(2); - mActionsToStopIfRunning = new ArrayList<>(2); - mActionsToToggle = new ArrayList<>(2); - } - - public List getActionsToStartIfRunning() { - return mActionsToStartIfRunning; - } - - public List getActionsToStopIfRunning() { - return mActionsToStopIfRunning; - } - - public List getActionsToToggle() { - return mActionsToToggle; - } - - public void addActionToStartIfRunning(Action action) { - mActionsToStartIfRunning.add(action); - } - - public void addActionToStopIfRunning(Action action) { - mActionsToStopIfRunning.add(action); - } - - public void addActionToToggle(Action action) { - mActionsToToggle.add(action); - } + void addActionToStartIfRunning(Action action); + void addActionToStopIfRunning(Action action); + void addActionToToggle(Action action); } diff --git a/flashlib.core.scheduling/src/main/java/com/flash3388/flashlib/scheduling/impl/triggers/TriggerActionControllerImpl.java b/flashlib.core.scheduling/src/main/java/com/flash3388/flashlib/scheduling/impl/triggers/TriggerActionControllerImpl.java new file mode 100644 index 000000000..f413bd68f --- /dev/null +++ b/flashlib.core.scheduling/src/main/java/com/flash3388/flashlib/scheduling/impl/triggers/TriggerActionControllerImpl.java @@ -0,0 +1,46 @@ +package com.flash3388.flashlib.scheduling.impl.triggers; + +import com.flash3388.flashlib.scheduling.actions.Action; + +import java.util.ArrayList; +import java.util.List; + +public class TriggerActionControllerImpl implements TriggerActionController { + + private final List mActionsToStartIfRunning; + private final List mActionsToStopIfRunning; + private final List mActionsToToggle; + + public TriggerActionControllerImpl() { + mActionsToStartIfRunning = new ArrayList<>(2); + mActionsToStopIfRunning = new ArrayList<>(2); + mActionsToToggle = new ArrayList<>(2); + } + + public List getActionsToStartIfRunning() { + return mActionsToStartIfRunning; + } + + public List getActionsToStopIfRunning() { + return mActionsToStopIfRunning; + } + + public List getActionsToToggle() { + return mActionsToToggle; + } + + @Override + public void addActionToStartIfRunning(Action action) { + mActionsToStartIfRunning.add(action); + } + + @Override + public void addActionToStopIfRunning(Action action) { + mActionsToStopIfRunning.add(action); + } + + @Override + public void addActionToToggle(Action action) { + mActionsToToggle.add(action); + } +} diff --git a/flashlib.core.scheduling/src/test/java/com/flash3388/flashlib/scheduling/impl/SingleThreadedSchedulerTest.java b/flashlib.core.scheduling/src/test/java/com/flash3388/flashlib/scheduling/impl/SingleThreadedSchedulerTest.java index 1a94f34dd..dbaa1c5bd 100644 --- a/flashlib.core.scheduling/src/test/java/com/flash3388/flashlib/scheduling/impl/SingleThreadedSchedulerTest.java +++ b/flashlib.core.scheduling/src/test/java/com/flash3388/flashlib/scheduling/impl/SingleThreadedSchedulerTest.java @@ -9,6 +9,9 @@ import com.flash3388.flashlib.scheduling.actions.Action; import com.flash3388.flashlib.scheduling.actions.ActionBase; import com.flash3388.flashlib.scheduling.actions.ActionsMock; +import com.flash3388.flashlib.scheduling.impl.triggers.GenericTrigger; +import com.flash3388.flashlib.scheduling.impl.triggers.TriggerActionController; +import com.flash3388.flashlib.scheduling.triggers.Trigger; import com.flash3388.flashlib.time.ClockMock; import com.flash3388.flashlib.util.FlashLibMainThread; import org.hamcrest.collection.IsMapContaining; @@ -16,6 +19,7 @@ import org.junit.jupiter.api.Test; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -29,6 +33,7 @@ class SingleThreadedSchedulerTest { private Map mPendingActions; private Map mRunningActions; + private Collection mTriggers; private Map mRequirementsUsage; private Map mDefaultActions; @@ -38,6 +43,7 @@ class SingleThreadedSchedulerTest { public void setUp() throws Exception { mPendingActions = new HashMap<>(); mRunningActions = new HashMap<>(); + mTriggers = new ArrayList<>(); mRequirementsUsage = new HashMap<>(); mDefaultActions = new HashMap<>(); @@ -48,7 +54,7 @@ public void setUp() throws Exception { mPendingActions, mRunningActions, new ArrayList<>(), - new ArrayList<>(), + mTriggers, mRequirementsUsage, mDefaultActions); } @@ -384,4 +390,115 @@ public void end(FinishReason reason) {} assertThat(mRunningActions, IsMapContaining.hasKey(actionToStart)); } + + @Test + public void run_withTriggersWithActionNotRunning_startsActionFromTrigger() throws Exception { + Action action = ActionsMock.actionMocker().build(); + + GenericTrigger trigger = new GenericTrigger() { + @Override + public void update(TriggerActionController controller) { + controller.addActionToStartIfRunning(action); + } + }; + mTriggers.add(trigger); + + mScheduler.run(SchedulerModeMock.mockNotDisabledMode()); + + assertThat(mRunningActions, IsMapContaining.hasKey(action)); + } + + @Test + public void run_withTriggersWithActionRunning_notStartsActionFromTrigger() throws Exception { + Action action = ActionsMock.actionMocker().build(); + RunningActionContext context = mock(RunningActionContext.class); + when(context.iterate()).thenReturn(false); + mRunningActions.put(action, context); + + GenericTrigger trigger = new GenericTrigger() { + @Override + public void update(TriggerActionController controller) { + controller.addActionToStartIfRunning(action); + } + }; + mTriggers.add(trigger); + + mScheduler.run(SchedulerModeMock.mockNotDisabledMode()); + + assertThat(mRunningActions, IsMapContaining.hasKey(action)); + } + + @Test + public void run_withTriggersAndActionRunning_stopsActionFromTrigger() throws Exception { + Action action = ActionsMock.actionMocker().build(); + RunningActionContext context = mock(RunningActionContext.class); + when(context.iterate()).thenReturn(false); + mRunningActions.put(action, context); + + GenericTrigger trigger = new GenericTrigger() { + @Override + public void update(TriggerActionController controller) { + controller.addActionToStopIfRunning(action); + } + }; + mTriggers.add(trigger); + + mScheduler.run(SchedulerModeMock.mockNotDisabledMode()); + + assertThat(mRunningActions, not(IsMapContaining.hasKey(action))); + } + + @Test + public void run_withTriggersAndActionNotRunning_notStopsActionFromTrigger() throws Exception { + Action action = ActionsMock.actionMocker().build(); + + GenericTrigger trigger = new GenericTrigger() { + @Override + public void update(TriggerActionController controller) { + controller.addActionToStopIfRunning(action); + } + }; + mTriggers.add(trigger); + + mScheduler.run(SchedulerModeMock.mockNotDisabledMode()); + + assertThat(mRunningActions, not(IsMapContaining.hasKey(action))); + } + + @Test + public void run_withTriggersAndActionNotRunning_toggleToStartActionFromTrigger() throws Exception { + Action action = ActionsMock.actionMocker().build(); + + GenericTrigger trigger = new GenericTrigger() { + @Override + public void update(TriggerActionController controller) { + controller.addActionToToggle(action); + } + }; + mTriggers.add(trigger); + + mScheduler.run(SchedulerModeMock.mockNotDisabledMode()); + + assertThat(mRunningActions, IsMapContaining.hasKey(action)); + } + + @Test + public void run_withTriggersAndActionRunning_toggleToStopActionFromTrigger() throws Exception { + Action action = ActionsMock.actionMocker().build(); + RunningActionContext context = mock(RunningActionContext.class); + when(context.iterate()).thenReturn(false); + mRunningActions.put(action, context); + + GenericTrigger trigger = new GenericTrigger() { + @Override + public void update(TriggerActionController controller) { + controller.addActionToToggle(action); + } + }; + mTriggers.add(trigger); + + mScheduler.run(SchedulerModeMock.mockNotDisabledMode()); + + assertThat(mRunningActions, not(IsMapContaining.hasKey(action))); + } } \ No newline at end of file diff --git a/flashlib.core.scheduling/src/test/java/com/flash3388/flashlib/scheduling/impl/triggers/TriggerBaseImplTest.java b/flashlib.core.scheduling/src/test/java/com/flash3388/flashlib/scheduling/impl/triggers/TriggerBaseImplTest.java index b308b91b6..7539d7476 100644 --- a/flashlib.core.scheduling/src/test/java/com/flash3388/flashlib/scheduling/impl/triggers/TriggerBaseImplTest.java +++ b/flashlib.core.scheduling/src/test/java/com/flash3388/flashlib/scheduling/impl/triggers/TriggerBaseImplTest.java @@ -18,12 +18,12 @@ public void setState_stateChanges_updatesListenersWithChange() throws Exception TriggerBaseImpl trigger = new TriggerBaseImpl(TriggerState.INACTIVE); trigger.addStateListener(listener); - trigger.setState(TriggerState.ACTIVE, mock(TriggerActionController.class)); + trigger.setState(TriggerState.ACTIVE, mock(TriggerActionControllerImpl.class)); verify(listener, times(1)).onStateChange( eq(TriggerState.ACTIVE), eq(TriggerState.INACTIVE), - any(TriggerActionController.class)); + any(TriggerActionControllerImpl.class)); } @Test @@ -33,7 +33,7 @@ public void whenActive_triggerActivates_startAction() throws Exception { TriggerBaseImpl trigger = new TriggerBaseImpl(TriggerState.INACTIVE); trigger.whenActive(mockAction); - TriggerActionController controller = new TriggerActionController(); + TriggerActionControllerImpl controller = new TriggerActionControllerImpl(); trigger.setState(TriggerState.ACTIVE, controller); assertThat(controller.getActionsToStartIfRunning(), IsIterableContainingInOrder.contains(mockAction)); @@ -46,7 +46,7 @@ public void whenInactive_triggerDeactivates_startAction() throws Exception { TriggerBaseImpl trigger = new TriggerBaseImpl(TriggerState.ACTIVE); trigger.whenInactive(mockAction); - TriggerActionController controller = new TriggerActionController(); + TriggerActionControllerImpl controller = new TriggerActionControllerImpl(); trigger.setState(TriggerState.INACTIVE, controller); assertThat(controller.getActionsToStartIfRunning(), IsIterableContainingInOrder.contains(mockAction)); @@ -61,7 +61,7 @@ public void cancelWhenActive_triggerActivatesAndActionRunning_cancelsAction() th TriggerBaseImpl trigger = new TriggerBaseImpl(TriggerState.INACTIVE); trigger.cancelWhenActive(mockAction); - TriggerActionController controller = new TriggerActionController(); + TriggerActionControllerImpl controller = new TriggerActionControllerImpl(); trigger.setState(TriggerState.ACTIVE, controller); assertThat(controller.getActionsToStopIfRunning(), IsIterableContainingInOrder.contains(mockAction)); @@ -76,7 +76,7 @@ public void cancelWhenInactive_triggerDeactivatesAndActionRunning_cancelsAction( TriggerBaseImpl trigger = new TriggerBaseImpl(TriggerState.ACTIVE); trigger.cancelWhenInactive(mockAction); - TriggerActionController controller = new TriggerActionController(); + TriggerActionControllerImpl controller = new TriggerActionControllerImpl(); trigger.setState(TriggerState.INACTIVE, controller); assertThat(controller.getActionsToStopIfRunning(), IsIterableContainingInOrder.contains(mockAction)); @@ -89,7 +89,7 @@ public void whileActive_triggerActivates_startAction() throws Exception { TriggerBaseImpl trigger = new TriggerBaseImpl(TriggerState.INACTIVE); trigger.whileActive(mockAction); - TriggerActionController controller = new TriggerActionController(); + TriggerActionControllerImpl controller = new TriggerActionControllerImpl(); trigger.setState(TriggerState.ACTIVE, controller); assertThat(controller.getActionsToStartIfRunning(), IsIterableContainingInOrder.contains(mockAction)); @@ -104,7 +104,7 @@ public void whileActive_triggerDeactivatesAndActionRunning_cancelsAction() throw TriggerBaseImpl trigger = new TriggerBaseImpl(TriggerState.ACTIVE); trigger.whileActive(mockAction); - TriggerActionController controller = new TriggerActionController(); + TriggerActionControllerImpl controller = new TriggerActionControllerImpl(); trigger.setState(TriggerState.INACTIVE, controller); assertThat(controller.getActionsToStopIfRunning(), IsIterableContainingInOrder.contains(mockAction)); diff --git a/flashlib.net.core/src/main/java/com/flash3388/flashlib/net/util/NetInterfaces.java b/flashlib.core/src/main/java/com/flash3388/flashlib/util/net/NetInterfaces.java similarity index 63% rename from flashlib.net.core/src/main/java/com/flash3388/flashlib/net/util/NetInterfaces.java rename to flashlib.core/src/main/java/com/flash3388/flashlib/util/net/NetInterfaces.java index cdb96c01d..82c030266 100644 --- a/flashlib.net.core/src/main/java/com/flash3388/flashlib/net/util/NetInterfaces.java +++ b/flashlib.core/src/main/java/com/flash3388/flashlib/util/net/NetInterfaces.java @@ -1,10 +1,11 @@ -package com.flash3388.flashlib.net.util; +package com.flash3388.flashlib.util.net; import java.io.IOException; import java.net.Inet4Address; import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; +import java.util.Enumeration; import java.util.NoSuchElementException; public class NetInterfaces { @@ -35,4 +36,21 @@ public static InterfaceAddress getIpv4AddressByInterface(NetworkInterface networ throw new NoSuchElementException("address not found"); } + + public static byte[] getMacAddress() throws IOException { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + if (!interfaces.hasMoreElements()) { + throw new IOException("no network interfaces available"); + } + + while (interfaces.hasMoreElements()) { + NetworkInterface networkInterface = interfaces.nextElement(); + byte[] hardwareAddress = networkInterface.getHardwareAddress(); + if (hardwareAddress != null) { + return hardwareAddress; + } + } + + throw new IOException("unable to obtain hardware address"); + } } diff --git a/flashlib.core/src/main/java/com/flash3388/flashlib/util/unique/InstanceId.java b/flashlib.core/src/main/java/com/flash3388/flashlib/util/unique/InstanceId.java index 348ac28cb..39688ee2d 100644 --- a/flashlib.core/src/main/java/com/flash3388/flashlib/util/unique/InstanceId.java +++ b/flashlib.core/src/main/java/com/flash3388/flashlib/util/unique/InstanceId.java @@ -6,6 +6,7 @@ import java.io.DataOutput; import java.io.IOException; import java.util.Arrays; +import java.util.Objects; public class InstanceId { private static final int PROCESS_ID_SIZE = Long.BYTES; @@ -14,6 +15,9 @@ public class InstanceId { private final byte[] mProcessId; public InstanceId(byte[] machineId, byte[] processId) { + Objects.requireNonNull(machineId, "machineId"); + Objects.requireNonNull(processId, "processId"); + assert machineId.length > 1; assert PROCESS_ID_SIZE == processId.length; diff --git a/flashlib.core/src/main/java/com/flash3388/flashlib/util/unique/InstanceIdGenerator.java b/flashlib.core/src/main/java/com/flash3388/flashlib/util/unique/InstanceIdGenerator.java index 4c13f5e1f..f15182ec9 100644 --- a/flashlib.core/src/main/java/com/flash3388/flashlib/util/unique/InstanceIdGenerator.java +++ b/flashlib.core/src/main/java/com/flash3388/flashlib/util/unique/InstanceIdGenerator.java @@ -3,11 +3,13 @@ import com.castle.util.os.KnownOperatingSystem; import com.flash3388.flashlib.util.Binary; import com.flash3388.flashlib.util.logging.Logging; +import com.flash3388.flashlib.util.net.NetInterfaces; import org.slf4j.Logger; import java.io.IOException; import java.lang.management.ManagementFactory; import java.net.NetworkInterface; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -15,6 +17,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Enumeration; import java.util.List; +import java.util.Optional; public class InstanceIdGenerator { @@ -37,58 +40,98 @@ public static InstanceId generate() { private static byte[] getMachineId() { if (KnownOperatingSystem.LINUX.isCurrent()) { - Path machineIdFile = Paths.get("/etc/machine-id"); - if (Files.exists(machineIdFile)) { - try { - LOGGER.debug("Using /etc/machine-id for machine-id"); - byte[] id = Files.readAllBytes(machineIdFile); - - MessageDigest digest = MessageDigest.getInstance("MD5"); - digest.update(id); - return digest.digest(); - } catch (IOException | NoSuchAlgorithmException e) { - // failed to get id from file - LOGGER.error("Failed retrieving machine id from /etc/machine-id", e); - } + Optional optional = getMachineIdLinux(); + if (optional.isPresent()) { + return optional.get(); } + } else if (KnownOperatingSystem.WINDOWS.isCurrent()) { + Optional optional = getMachineIdWindows(); + if (optional.isPresent()) { + return optional.get(); + } + } + + return getMachineIdFallback(); + } + + private static Optional getMachineIdLinux() { + Path machineIdFile = Paths.get("/etc/machine-id"); + if (Files.exists(machineIdFile)) { + try { + LOGGER.debug("Using /etc/machine-id for machine-id"); + byte[] id = Files.readAllBytes(machineIdFile); + + MessageDigest digest = MessageDigest.getInstance("MD5"); + digest.update(id); + byte[] result = digest.digest(); + return Optional.of(result); + } catch (IOException | NoSuchAlgorithmException e) { + // failed to get id from file + LOGGER.error("Failed retrieving machine id from /etc/machine-id", e); + } + } else { + LOGGER.debug("/etc/machine-id does not exist"); } + return Optional.empty(); + } + + private static Optional getMachineIdWindows() { + try { + String serialNumber = Wmic.getBiosSerialNumber(); + byte[] id = serialNumber.getBytes(StandardCharsets.UTF_8); + return Optional.of(id); + } catch (IOException e) { + LOGGER.error("Failed retrieving serial number from wmic", e); + } + + return Optional.empty(); + } + + private static byte[] getMachineIdFallback() { try { // although not fool-proof, we'll use MAC address from the machine. // MAC addresses can actually change, but for now this will do. LOGGER.debug("Using MAC address for machine-id"); - return getMacAddress(); + return NetInterfaces.getMacAddress(); } catch (IOException e) { throw new IdGenerationException("failed retrieving MAC address", e); } } - private static byte[] getMacAddress() throws IOException { - Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); - if (!interfaces.hasMoreElements()) { - throw new IOException("no network interfaces available"); + private static long getPid() { + if (KnownOperatingSystem.LINUX.isCurrent()) { + Optional optionalPid = getPidLinux(); + if (optionalPid.isPresent()) { + return optionalPid.get(); + } } - NetworkInterface networkInterface = interfaces.nextElement(); - return networkInterface.getHardwareAddress(); + return getPidFallback(); } - private static long getPid() { - if (KnownOperatingSystem.LINUX.isCurrent()) { - Path processStat = Paths.get("/proc/self/stat"); - if (Files.exists(processStat)) { - try { - LOGGER.debug("Using /proc/self for process-id"); - List lines = Files.readAllLines(processStat); - String pidString = lines.get(0).split(" ")[0]; - return Long.parseLong(pidString); - } catch (IOException | NumberFormatException e) { - // failed to get id from file - LOGGER.error("Failed retrieving machine id from /proc/self", e); - } + private static Optional getPidLinux() { + Path processStat = Paths.get("/proc/self/stat"); + if (Files.exists(processStat)) { + try { + LOGGER.debug("Using /proc/self for process-id"); + + List lines = Files.readAllLines(processStat); + String pidString = lines.get(0).split(" ")[0]; + long pid = Long.parseLong(pidString); + return Optional.of(pid); + } catch (IOException | NumberFormatException e) { + // failed to get id from file + LOGGER.error("Failed retrieving machine id from /proc/self", e); } + } else { + LOGGER.debug("/proc/self/stat does not exist"); } + return Optional.empty(); + } + + private static long getPidFallback() { try { LOGGER.debug("Using ManagementFactory.getRuntimeMXBean() for process-id"); diff --git a/flashlib.core/src/main/java/com/flash3388/flashlib/util/unique/Wmic.java b/flashlib.core/src/main/java/com/flash3388/flashlib/util/unique/Wmic.java new file mode 100644 index 000000000..c3bc052b3 --- /dev/null +++ b/flashlib.core/src/main/java/com/flash3388/flashlib/util/unique/Wmic.java @@ -0,0 +1,56 @@ +package com.flash3388.flashlib.util.unique; + +import com.castle.util.closeables.Closeables; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Scanner; + +public class Wmic { + + private Wmic() {} + + public static String getBiosSerialNumber() throws IOException { + return getWmicOutputLine( + new String[]{"bios", "get", "serialNumber"}, + "SerialNumber"); + } + + public static String getWmicOutputLine(String[] cmd, String outputLine) throws IOException { + // https://stackoverflow.com/questions/1986732/how-to-get-a-unique-computer-identifier-in-java-like-disk-id-or-motherboard-id + String[] cmdFull = new String[cmd.length + 1]; + cmdFull[0] = "wmic"; + System.arraycopy(cmd, 0, cmdFull, 1, cmd.length); + + Runtime runtime = Runtime.getRuntime(); + Process process = runtime.exec(cmdFull); + try { + process.getOutputStream().close(); + + InputStream procOutput = process.getInputStream(); + try { + Scanner scanner = new Scanner(procOutput); + while (scanner.hasNext()) { + String text = scanner.next(); + if (text.equals(outputLine)) { + if (!scanner.hasNext()) { + throw new IOException("found line, but proc output has reached its end"); + } + + return scanner.next(); + } + } + + throw new IOException("wanted line not found"); + } finally { + Closeables.silentClose(procOutput); + } + } finally { + Closeables.silentClose(()-> { + if (process.isAlive()) { + process.destroyForcibly(); + } + }); + } + } +} diff --git a/gradle.properties b/gradle.properties index 7fb24e303..d84a4e9b9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ GROUP = com.flash3388.flashlib -VERSION = 3.2.0 +VERSION = 3.2.1 NEXUS_SNAPSHOT_REPOSITORY_URL = https\://oss.sonatype.org/content/repositories/snapshots NEXUS_RELEASE_REPOSITORY_URL = https\://oss.sonatype.org/service/local/staging/deploy/maven2