Scheduler JavaFX and Swing now have Future

This commit is contained in:
huangyuhui
2017-08-06 11:45:12 +08:00
parent 736a8c1b30
commit f1ffa5ca03
22 changed files with 255 additions and 209 deletions

View File

@@ -30,7 +30,7 @@ private class CoupleTask<P: Task>(private val pred: P, private val succ: Task.(P
}
}
infix fun <T: Task> T.then(b: Task): Task = CoupleTask(this, { b }, true)
infix fun Task.then(b: Task): Task = CoupleTask(this, { b }, true)
/**
* @param b A runnable that decides what to do next, You can also do something here.

View File

@@ -33,7 +33,7 @@ import java.net.URL
import java.math.BigInteger
import java.util.logging.Level
class FileDownloadTask(val url: URL, val file: File, val hash: String? = null, val retry: Int = 5, val proxy: Proxy = Proxy.NO_PROXY): Task() {
class FileDownloadTask @JvmOverloads constructor(val url: URL, val file: File, val hash: String? = null, val retry: Int = 5, val proxy: Proxy = Proxy.NO_PROXY): Task() {
override val scheduler: Scheduler = Scheduler.IO_THREAD
var onFailed = EventManager<FailedEvent<URL>>()

View File

@@ -25,7 +25,7 @@ import java.net.Proxy
import java.net.URL
import java.nio.charset.Charset
class GetTask(val url: URL, val encoding: Charset = Charsets.UTF_8, private val retry: Int = 5, private val proxy: Proxy = Proxy.NO_PROXY): TaskResult<String>() {
class GetTask @JvmOverloads constructor(val url: URL, val encoding: Charset = Charsets.UTF_8, private val retry: Int = 5, private val proxy: Proxy = Proxy.NO_PROXY): TaskResult<String>() {
override val scheduler: Scheduler = Scheduler.IO_THREAD
override fun execute() {

View File

@@ -18,38 +18,51 @@
package org.jackhuang.hmcl.task
import javafx.application.Platform
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.Future
import java.util.concurrent.*
import java.util.concurrent.atomic.AtomicReference
import javax.swing.SwingUtilities
interface Scheduler {
fun schedule(block: Runnable): Future<*>?
fun schedule(block: Callable<Unit>): Future<*>?
companion object Schedulers {
val IMMEDIATE = object : Scheduler {
override fun schedule(block: Runnable): Future<*>? {
block.run()
return null
}
}
val JAVAFX: Scheduler = object : Scheduler {
override fun schedule(block: Runnable): Future<*>? {
Platform.runLater(block)
return null
}
}
val SWING: Scheduler = object : Scheduler {
override fun schedule(block: Runnable): Future<*>? {
SwingUtilities.invokeLater(block)
return null
val JAVAFX: Scheduler = SchedulerImpl(Platform::runLater)
val SWING: Scheduler = SchedulerImpl(SwingUtilities::invokeLater)
private class SchedulerImpl(val executor: (() -> Unit) -> Unit) : Scheduler {
override fun schedule(block: Callable<Unit>): Future<*>? {
val latch = CountDownLatch(1)
val wrapper = AtomicReference<Exception>()
executor {
try {
block.call()
} catch (e: Exception) {
wrapper.set(e)
} finally {
latch.countDown()
}
}
return object : Future<Unit> {
override fun get(timeout: Long, unit: TimeUnit) {
latch.await(timeout, unit)
val e = wrapper.get()
if (e != null) throw ExecutionException(e)
}
override fun get() {
latch.await()
val e = wrapper.get()
if (e != null) throw ExecutionException(e)
}
override fun isDone() = latch.count == 0L
override fun isCancelled() = false
override fun cancel(mayInterruptIfRunning: Boolean) = false
}
}
}
val NEW_THREAD: Scheduler = object : Scheduler {
override fun schedule(block: Runnable) = CACHED_EXECUTOR.submit(block)
override fun schedule(block: Callable<Unit>) = CACHED_EXECUTOR.submit(block)
}
val IO_THREAD: Scheduler = object : Scheduler {
override fun schedule(block: Runnable) = IO_EXECUTOR.submit(block)
override fun schedule(block: Callable<Unit>) = IO_EXECUTOR.submit(block)
}
val DEFAULT = NEW_THREAD
private val CACHED_EXECUTOR: ExecutorService by lazy {
@@ -57,11 +70,11 @@ interface Scheduler {
}
private val IO_EXECUTOR: ExecutorService by lazy {
Executors.newFixedThreadPool(6, { r: Runnable ->
Executors.newFixedThreadPool(6) { r: Runnable ->
val thread: Thread = Executors.defaultThreadFactory().newThread(r)
thread.isDaemon = true
thread
})
}
}
fun shutdown() {

View File

@@ -17,7 +17,7 @@
*/
package org.jackhuang.hmcl.task
internal class SimpleTask(private val runnable: () -> Unit, override val scheduler: Scheduler = Scheduler.DEFAULT) : Task() {
internal class SimpleTask @JvmOverloads constructor(private val runnable: () -> Unit, override val scheduler: Scheduler = Scheduler.DEFAULT) : Task() {
override fun execute() {
runnable()
}

View File

@@ -17,7 +17,9 @@
*/
package org.jackhuang.hmcl.task
import javafx.beans.property.ReadOnlyDoubleProperty
import javafx.beans.property.ReadOnlyDoubleWrapper
import javafx.beans.property.ReadOnlyStringProperty
import javafx.beans.property.ReadOnlyStringWrapper
import org.jackhuang.hmcl.event.EventManager
import org.jackhuang.hmcl.util.*
@@ -69,19 +71,23 @@ abstract class Task {
protected open val progressInterval = 1000L
private var lastTime = Long.MIN_VALUE
private val progressUpdate = AtomicReference<Double>()
val progressProperty = ReadOnlyDoubleWrapper(this, "progress", 0.0)
private val progressPropertyImpl = ReadOnlyDoubleWrapper(this, "progress", 0.0)
val progressProperty: ReadOnlyDoubleProperty = progressPropertyImpl.readOnlyProperty
@JvmName("progressProperty") get
protected fun updateProgress(progress: Int, total: Int) = updateProgress(1.0 * progress / total)
protected fun updateProgress(progress: Double) {
val now = System.currentTimeMillis()
if (now - lastTime >= progressInterval) {
progressProperty.updateAsync(progress, progressUpdate)
progressPropertyImpl.updateAsync(progress, progressUpdate)
lastTime = now
}
}
private val messageUpdate = AtomicReference<String>()
val messageProperty = ReadOnlyStringWrapper(this, "message", null)
protected fun updateMessage(newMessage: String) = messageProperty.updateAsync(newMessage, messageUpdate)
private val messagePropertyImpl = ReadOnlyStringWrapper(this, "message", null)
val messageProperty: ReadOnlyStringProperty = messagePropertyImpl.readOnlyProperty
@JvmName("messageProperty") get
protected fun updateMessage(newMessage: String) = messagePropertyImpl.updateAsync(newMessage, messageUpdate)
val onDone = EventManager<TaskEvent>()
@@ -97,11 +103,11 @@ abstract class Task {
}
private val subTaskRunnable = { task: Task ->
this.messageProperty.bind(task.messageProperty)
this.progressProperty.bind(task.progressProperty)
this.messagePropertyImpl.bind(task.messagePropertyImpl)
this.progressPropertyImpl.bind(task.progressPropertyImpl)
task.run()
this.messageProperty.unbind()
this.progressProperty.unbind()
this.messagePropertyImpl.unbind()
this.progressPropertyImpl.unbind()
}
fun executor() = TaskExecutor().submit(this)

View File

@@ -52,7 +52,7 @@ class TaskExecutor() {
while (!taskQueue.isEmpty() && !canceled) {
val task = taskQueue.poll()
if (task != null) {
val future = task.scheduler.schedule(Runnable { executeTask(task) })
val future = task.scheduler.schedule(Callable { executeTask(task); Unit })
try {
future?.get()
} catch (e: InterruptedException) {
@@ -142,8 +142,8 @@ class TaskExecutor() {
return flag
}
private inner class Invoker(val task: Task, val latch: CountDownLatch, val boolean: AtomicBoolean): Runnable {
override fun run() {
private inner class Invoker(val task: Task, val latch: CountDownLatch, val boolean: AtomicBoolean): Callable<Unit> {
override fun call() {
try {
Thread.currentThread().name = task.title
if (!executeTask(task))

View File

@@ -15,6 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
@file:JvmName("Constants")
package org.jackhuang.hmcl.util
import javafx.application.Platform

View File

@@ -15,6 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
@file:JvmName("HMCLog")
package org.jackhuang.hmcl.util
import java.io.ByteArrayOutputStream

View File

@@ -23,7 +23,6 @@ import java.lang.reflect.Method
import java.security.PrivilegedExceptionAction
import java.security.AccessController
object ReflectionHelper {
private lateinit var unsafe: Unsafe

View File

@@ -21,7 +21,7 @@ import java.io.IOException
import java.io.InputStream
import java.util.logging.Level
internal class StreamPump(
internal class StreamPump @JvmOverloads constructor(
val inputStream: InputStream,
val callback: (String) -> Unit = {}
) : Runnable {

View File

@@ -23,13 +23,6 @@ import java.io.IOException
import java.util.zip.ZipOutputStream
import java.util.zip.ZipInputStream
@Throws(IOException::class)
fun zip(src: String, destZip: String) {
zip(File(src), File(destZip), null)
}
/**
* 功能:把 src 目录下的所有文件进行 zip 格式的压缩,保存为指定 zip 文件
@@ -43,8 +36,9 @@ fun zip(src: String, destZip: String) {
* *
* @throws java.io.IOException 压缩失败或无法读取
*/
@JvmOverloads
@Throws(IOException::class)
fun zip(src: File, destZip: File, pathNameCallback: ((String, Boolean) -> String?)?) {
fun zip(src: File, destZip: File, pathNameCallback: ((String, Boolean) -> String?)? = null) {
ZipOutputStream(destZip.outputStream()).use { zos ->
val basePath: String
if (src.isDirectory)
@@ -103,11 +97,6 @@ private fun zipFile(src: File,
}
}
@Throws(IOException::class)
fun unzip(zip: File, dest: File) {
unzip(zip, dest, null, true)
}
/**
* 将文件压缩成zip文件
@@ -121,8 +110,9 @@ fun unzip(zip: File, dest: File) {
* *
* @throws java.io.IOException 解压失败或无法写入
*/
@JvmOverloads
@Throws(IOException::class)
fun unzip(zip: File, dest: File, callback: ((String) -> Boolean)?, ignoreExistsFile: Boolean) {
fun unzip(zip: File, dest: File, callback: ((String) -> Boolean)? = null, ignoreExistsFile: Boolean = true) {
val buf = ByteArray(1024)
dest.mkdirs()
ZipInputStream(zip.inputStream()).use { zipFile ->