faster proxy

This commit is contained in:
tursom 2023-01-20 17:50:37 +08:00
parent d170678182
commit 3ae1044999
43 changed files with 634 additions and 236 deletions

View File

@ -1,7 +1,7 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { plugins {
kotlin("jvm") version "1.6.20" kotlin("jvm") version "1.8.0"
`maven-publish` `maven-publish`
id("ts-gradle") id("ts-gradle")
} }
@ -10,12 +10,7 @@ allprojects {
group = "cn.tursom" group = "cn.tursom"
version = "1.0-SNAPSHOT" version = "1.0-SNAPSHOT"
repositories { useTursomRepositories()
//mavenCentral()
maven {
url = uri("https://nvm.tursom.cn/repository/maven-public/")
}
}
tasks.withType<JavaCompile> { tasks.withType<JavaCompile> {
tasks.withType<KotlinCompile>().configureEach { tasks.withType<KotlinCompile>().configureEach {
@ -23,9 +18,7 @@ allprojects {
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
} }
if (project.gradle.startParameter.taskNames.firstOrNull { taskName -> if (!isTestRunning) {
taskName.endsWith(":test")
} == null) {
tasks.withType<Test> { tasks.withType<Test> {
enabled = false enabled = false
} }
@ -37,6 +30,8 @@ allprojects {
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
//kotlinOptions.useIR = true //kotlinOptions.useIR = true
} }
autoConfigPublish()
} }
@ -50,7 +45,3 @@ dependencies {
artifacts { artifacts {
archives(tasks["kotlinSourcesJar"]) archives(tasks["kotlinSourcesJar"])
} }
publishing {
publish(this)
}

View File

@ -19,3 +19,6 @@ android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete": # Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official kotlin.code.style=official
project.groupId=cn.tursom
project.version=1.0-SNAPSHOT

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -15,6 +15,4 @@ dependencies {
testApi(group = "junit", name = "junit", version = "4.13.2") testApi(group = "junit", name = "junit", version = "4.13.2")
} }
autoConfigPublish()

View File

@ -4,7 +4,7 @@ import cn.tursom.core.uncheckedCast
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
class ArrayContextEnv : ContextEnv { class ArrayContextEnv : ContextEnv {
val envId = ContextEnv.newEnvId() override val envId = ContextEnv.newEnvId()
private val idGenerator = AtomicInteger() private val idGenerator = AtomicInteger()
private val emptyContext = EmptyArrayContext(envId, idGenerator) private val emptyContext = EmptyArrayContext(envId, idGenerator)

View File

@ -8,6 +8,8 @@ interface ContextEnv {
fun newEnvId() = contextEnvIdGenerator.incrementAndGet() fun newEnvId() = contextEnvIdGenerator.incrementAndGet()
} }
val envId: Int
fun emptyContext(): Context = newContext() fun emptyContext(): Context = newContext()
fun newContext(): Context fun newContext(): Context
fun <T> newKey(): ContextKey<T> fun <T> newKey(): ContextKey<T>

View File

@ -4,7 +4,7 @@ import cn.tursom.core.uncheckedCast
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
class HashMapContextEnv : ContextEnv { class HashMapContextEnv : ContextEnv {
val envId = ContextEnv.newEnvId() override val envId = ContextEnv.newEnvId()
private val idGenerator = AtomicInteger() private val idGenerator = AtomicInteger()
override fun newContext(): Context = HashMapContext(envId) override fun newContext(): Context = HashMapContext(envId)

View File

@ -1,12 +1,33 @@
import java.math.BigInteger import java.math.BigInteger
enum class Status(val id: Int) : (Int) -> Int {
S1(1), S2(2), S3(3);
override fun invoke(i: Int): Int {
return 0
}
infix fun or(status: Status) = status.id or id
infix fun or(status: Int) = id or status
}
infix fun Int.or(status: Status) = this or status.id
inline fun <reified T> Any.instanceOf() = this is T
fun main() { fun main() {
val two = BigInteger.valueOf(2) println(1.instanceOf<Int>())
val three = BigInteger.valueOf(3) println(1L.instanceOf<Int>())
val ten = BigInteger.TEN println(1f.instanceOf<Int>())
var i = BigInteger.ONE
repeat(1000) { //var i1 = 1 or Status.S1
i *= two //
print("${i / ten / ten / ten % ten}") //val two = BigInteger.valueOf(2)
} //val three = BigInteger.valueOf(3)
//val ten = BigInteger.TEN
//var i = BigInteger.ONE
//repeat(1000) {
// i *= two
// print("${i / ten / ten / ten % ten}")
//}
} }

View File

@ -0,0 +1,8 @@
import kotlinx.coroutines.delay
tailrec fun pow(i: Int, n: Int = 1): Int = if (i <= 0) n else pow(i - 1, i * n)
suspend fun main() {
delay(pow(10).toLong())
println("finished")
}

View File

@ -0,0 +1,16 @@
package cn.tursom.core.curry
import cn.tursom.core.allMemberPropertiesSequence
import java.util.concurrent.ConcurrentHashMap
fun example(f: (Int) -> (Int) -> (Int) -> Int) {
f(1)(2)(3)
f(1, 2, 3)
}
fun example2(f: (Int, Int, Int) -> Int) {
f(1, 2, 3)
f(1, 2)(3)
}

View File

@ -8,10 +8,12 @@ import kotlin.reflect.KProperty
* 如果你还需要对这个属性进行加锁你就可以在后方加一个 .locked 即可 * 如果你还需要对这个属性进行加锁你就可以在后方加一个 .locked 即可
* 如果还需要用指定的锁在后面再加一个 (lock) 就玩成了 * 如果还需要用指定的锁在后面再加一个 (lock) 就玩成了
* 使用例 * 使用例
* ```
* class XXXImpl: XXX, FieldChangeListener by FieldChangeListenerImpl() { * class XXXImpl: XXX, FieldChangeListener by FieldChangeListenerImpl() {
* val lock = ReentrantLock() * val lock = ReentrantLock()
* val field by listened(0).locker(lock) * val field by listened(0).locker(lock)
* } * }
* ```
*/ */
interface DelegatedField<in T, out V> { interface DelegatedField<in T, out V> {
/** /**

View File

@ -0,0 +1,49 @@
package cn.tursom.core.delegation.observer
import cn.tursom.core.delegation.expirable
import cn.tursom.core.delegation.filter
import cn.tursom.core.delegation.notNull
import java.lang.Thread.sleep
class A {
@OptIn(Listenable::class)
var field by listenable(0)
.filter { _, new ->
new >= 0
}
.expirable(100)
.notNull {
throw IllegalAccessError()
}
@OptIn(Listenable::class)
var canServer by listenable(true)
@OptIn(Listenable::class)
var count: Int by listenable(0)
}
fun f(obj: A) {
obj::field.listen { old: Int?, new: Int? ->
println("old: $old, new: $new")
}
obj::canServer.listen { old, new ->
println(new)
}
obj::count.listen { old, new ->
}
}
fun main() {
val a = A()
f(a)
a.field = 1
println(a.field)
sleep(1000)
println(a.field)
}

View File

View File

@ -11,7 +11,7 @@ dependencies {
api(project(":ts-core")) api(project(":ts-core"))
api(project(":ts-core:ts-reflectasm")) api(project(":ts-core:ts-reflectasm"))
api(group = "cglib", name = "cglib", version = "3.3.0") api(group = "cglib", name = "cglib", version = "3.3.0")
implementation(group = "net.bytebuddy", name = "byte-buddy", version = "1.12.22") //implementation(group = "net.bytebuddy", name = "byte-buddy", version = "1.12.22")
implementation(group = "org.apache.commons", name = "commons-lang3", version = "3.8.1") implementation(group = "org.apache.commons", name = "commons-lang3", version = "3.8.1")
testApi(group = "junit", name = "junit", version = "4.13.2") testApi(group = "junit", name = "junit", version = "4.13.2")
} }

View File

@ -0,0 +1,34 @@
package cn.tursom.proxy.function;
import cn.tursom.proxy.container.ProxyContainer;
import cn.tursom.proxy.container.ProxyMethodCacheFunction;
import com.esotericsoftware.reflectasm.MethodAccess;
import net.sf.cglib.proxy.MethodProxy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Method;
public class JavaReflectASMProxyMethodInvoker implements ProxyMethodCacheFunction {
private final Object self;
private final MethodAccess methodAccess;
private final int index;
public JavaReflectASMProxyMethodInvoker(Object self, MethodAccess methodAccess, int index) {
this.self = self;
this.methodAccess = methodAccess;
this.index = index;
}
@Nullable
@Override
public Object invoke(
@Nullable Object obj,
@NotNull ProxyContainer c,
@Nullable Method method,
@Nullable Object[] args,
@Nullable MethodProxy proxy
) {
return methodAccess.invoke(self, index, args);
}
}

View File

@ -7,6 +7,7 @@ import cn.tursom.proxy.container.ListProxyContainer
import cn.tursom.proxy.container.MutableProxyContainer import cn.tursom.proxy.container.MutableProxyContainer
import cn.tursom.proxy.container.ProxyContainer import cn.tursom.proxy.container.ProxyContainer
import cn.tursom.proxy.function.ProxyMethod import cn.tursom.proxy.function.ProxyMethod
import cn.tursom.proxy.interceptor.CachedMethodInterceptor
import cn.tursom.proxy.interceptor.LocalCachedProxyInterceptor import cn.tursom.proxy.interceptor.LocalCachedProxyInterceptor
import cn.tursom.proxy.interceptor.ProxyInterceptor import cn.tursom.proxy.interceptor.ProxyInterceptor
import cn.tursom.reflect.final import cn.tursom.reflect.final
@ -23,14 +24,18 @@ object Proxy {
it.final = false it.final = false
} }
fun getContainer(obj: Any): ProxyContainer? { fun getContainer(obj: Factory): ProxyContainer? {
if (obj !is Factory) return null
val interceptor = obj.getCallback(0) as? ProxyInterceptor ?: return null val interceptor = obj.getCallback(0) as? ProxyInterceptor ?: return null
return interceptor.container return interceptor.container
} }
fun getMutableContainer(obj: Factory): MutableProxyContainer? {
val interceptor = obj.getCallback(0) as? ProxyInterceptor ?: return null
return interceptor.container as? MutableProxyContainer
}
fun addProxy(obj: Any, proxy: ProxyMethod): Boolean { fun addProxy(obj: Any, proxy: ProxyMethod): Boolean {
val container = getContainer(obj) as? MutableProxyContainer ?: return false val container = getContainer(obj as Factory) as? MutableProxyContainer ?: return false
container.addProxy(proxy) container.addProxy(proxy)
return true return true
} }
@ -48,7 +53,7 @@ object Proxy {
container.target = obj container.target = obj
container.ctx[directAccessorKey] = directAccessor container.ctx[directAccessorKey] = directAccessor
injectCallback(obj as Factory, container, directAccessor) injectCallback(obj as Factory, container, directAccessor as Factory)
return obj to container return obj to container
} }
@ -137,6 +142,7 @@ object Proxy {
fun <T : Any> newEnhancer(clazz: Class<T>, vararg interfaces: Class<*>): Enhancer { fun <T : Any> newEnhancer(clazz: Class<T>, vararg interfaces: Class<*>): Enhancer {
val enhancer = Enhancer() val enhancer = Enhancer()
enhancer.setSuperclass(clazz) enhancer.setSuperclass(clazz)
if (interfaces.isNotEmpty()) { if (interfaces.isNotEmpty()) {
enhancer.setInterfaces(interfaces) enhancer.setInterfaces(interfaces)
@ -151,15 +157,17 @@ object Proxy {
} }
@JvmOverloads @JvmOverloads
fun injectCallback(obj: Any, container: ProxyContainer = defaultContainer(), target: Any = obj): ProxyContainer { fun injectCallback(
obj as Factory obj: Factory,
container: ProxyContainer = defaultContainer(),
target: Factory = obj,
): ProxyContainer {
if (obj.getCallback(0) != null && obj.getCallback(0) is ProxyInterceptor) { if (obj.getCallback(0) != null && obj.getCallback(0) is ProxyInterceptor) {
return (obj.getCallback(0) as ProxyInterceptor).container return (obj.getCallback(0) as ProxyInterceptor).container
} }
val nonProxyClasses: MutableSet<Class<*>> = HashSet(listOf(Any::class.java))
repeat(obj.callbacks.size) { repeat(obj.callbacks.size) {
obj.setCallback(it, LocalCachedProxyInterceptor(container, nonProxyClasses, target)) obj.setCallback(it, LocalCachedProxyInterceptor(container, target))
} }
return container return container
} }
@ -170,27 +178,30 @@ object Proxy {
fun <T : Any> getSuperCaller( fun <T : Any> getSuperCaller(
obj: T, obj: T,
): T = getContainer(obj)?.ctx?.get(directAccessorKey).uncheckedCast() ): T = getContainer(obj as Factory)?.ctx?.get(directAccessorKey).uncheckedCast()
fun addNonProxyClass(target: Any, nonProxyClass: Class<*>): Boolean { fun addNonProxyClass(target: Factory, nonProxyClass: Class<*>): Boolean {
if (target !is Factory || val container = getMutableContainer(target) ?: throw IllegalArgumentException()
target.getCallback(0) == null || return container.nonProxyClasses.add(nonProxyClass)
target.getCallback(0) !is ProxyInterceptor
) {
throw IllegalArgumentException()
} }
return (target.getCallback(0) as ProxyInterceptor).nonProxyClasses.add(nonProxyClass) fun removeNonProxyClass(target: Factory, nonProxyClass: Class<*>): Boolean {
val container = getMutableContainer(target) ?: throw IllegalArgumentException()
return container.nonProxyClasses.remove(nonProxyClass)
} }
fun removeNonProxyClass(target: Any, nonProxyClass: Class<*>): Boolean { fun clearCallbackCache(target: Factory, container: ProxyContainer) {
if (target !is Factory || target.callbacks.forEachIndexed { index, callback ->
target.getCallback(0) == null || if (callback == null) {
target.getCallback(0) !is ProxyInterceptor target.setCallback(index, LocalCachedProxyInterceptor(container, target))
) { return@forEachIndexed
throw IllegalArgumentException()
} }
return (target.getCallback(0) as ProxyInterceptor).nonProxyClasses.remove(nonProxyClass) if (callback !is CachedMethodInterceptor) {
return@forEachIndexed
}
callback.clearCache()
}
} }
} }

View File

@ -1,19 +1,22 @@
package cn.tursom.proxy.container package cn.tursom.proxy.container
import cn.tursom.core.context.Context import cn.tursom.core.context.Context
import cn.tursom.proxy.Proxy
import cn.tursom.proxy.function.ProxyMethod import cn.tursom.proxy.function.ProxyMethod
import cn.tursom.proxy.util.CglibUtil import net.sf.cglib.proxy.Factory
import net.sf.cglib.proxy.MethodProxy
class ListProxyContainer( class ListProxyContainer(
private val proxyList: MutableCollection<Any> = ArrayList(), private val proxyList: MutableCollection<Any> = ArrayList(),
override val nonProxyClasses: MutableSet<Class<*>> = HashSet(listOf(Any::class.java)),
) : MutableProxyContainer { ) : MutableProxyContainer {
override lateinit var target: Any override lateinit var target: Any
override val ctx: Context = ProxyContainer.ctxEnv.newContext() override val ctx: Context = ProxyContainer.ctxEnv.newContext()
private fun clearCache() { private fun clearCache() {
ctx[ProxyMethodCache.ctxKey].clear() ctx[ProxyMethodCache.ctxKey].clear()
Proxy.clearCallbackCache(target as Factory, this)
} }
override fun addProxy(proxy: Any) { override fun addProxy(proxy: Any) {

View File

@ -2,6 +2,7 @@ package cn.tursom.proxy.container
interface MutableProxyContainer : ProxyContainer { interface MutableProxyContainer : ProxyContainer {
override var target: Any override var target: Any
override val nonProxyClasses: MutableSet<Class<*>>
fun addProxy(proxy: Any) fun addProxy(proxy: Any)
fun addAllProxy(proxy: Collection<Any>?) fun addAllProxy(proxy: Collection<Any>?)

View File

@ -11,4 +11,5 @@ interface ProxyContainer : Iterable<Any> {
// to impl, use override val context: Context = ProxyContainer.contextEnv.newContext() // to impl, use override val context: Context = ProxyContainer.contextEnv.newContext()
val ctx: Context val ctx: Context
val target: Any val target: Any
val nonProxyClasses: Set<Class<*>>
} }

View File

@ -1,7 +1,9 @@
package cn.tursom.proxy.container package cn.tursom.proxy.container
import cn.tursom.proxy.function.ProxyMethod
import cn.tursom.proxy.util.IntMap import cn.tursom.proxy.util.IntMap
import net.sf.cglib.proxy.MethodProxy import net.sf.cglib.proxy.MethodProxy
import java.lang.reflect.Method
class ProxyMethodCache { class ProxyMethodCache {
companion object { companion object {
@ -18,9 +20,22 @@ class ProxyMethodCache {
} }
} }
fun update(proxy: MethodProxy, function: ProxyMethodCacheFunction) { fun update(
obj: Any,
container: ProxyContainer,
method: Method,
proxy: MethodProxy,
function: ProxyMethodCacheFunction,
) {
var handler = function
container.forEach {
if (it !is ProxyMethod) return@forEach
handler = it.onProxyHandlerCacheUpdate(handler, obj, container, method, proxy)
}
synchronized(this) { synchronized(this) {
functionMap[proxy.superIndex] = function functionMap[proxy.superIndex] = handler
} }
} }

View File

@ -1,13 +1,14 @@
package cn.tursom.proxy.container package cn.tursom.proxy.container
import cn.tursom.proxy.container.ProxyContainer
import net.sf.cglib.proxy.MethodProxy import net.sf.cglib.proxy.MethodProxy
import java.lang.reflect.Method import java.lang.reflect.Method
fun interface ProxyMethodCacheFunction : ( fun interface ProxyMethodCacheFunction {
Any?, operator fun invoke(
ProxyContainer, obj: Any?,
Method?, c: ProxyContainer,
Array<out Any?>?, method: Method?,
MethodProxy?, args: Array<out Any?>?,
) -> Any? proxy: MethodProxy?,
): Any?
}

View File

@ -15,11 +15,10 @@ class CachedOnForEachProxyImpl(
a: Array<out Any?>?, a: Array<out Any?>?,
proxy: MethodProxy?, proxy: MethodProxy?,
): Any? { ): Any? {
proxy!!
proxyList.forEach { p -> proxyList.forEach { p ->
p(o, c, m, a, proxy) p(o, c, m, a, proxy)
} }
return proxy.invokeSuper(o, a)
return proxy!!.invokeSuper(o, a)
} }
} }

View File

@ -2,10 +2,22 @@ package cn.tursom.proxy.function
import cn.tursom.proxy.container.ProxyContainer import cn.tursom.proxy.container.ProxyContainer
import cn.tursom.proxy.container.ProxyMethodCacheFunction import cn.tursom.proxy.container.ProxyMethodCacheFunction
import cn.tursom.reflect.asm.ReflectAsmUtils
import net.sf.cglib.proxy.MethodProxy import net.sf.cglib.proxy.MethodProxy
import java.lang.reflect.Method import java.lang.reflect.Method
object CallSuperProxyMethodCacheFunction : ProxyMethodCacheFunction { object CallSuperProxyMethodCacheFunction : ProxyMethodCacheFunction {
operator fun get(obj: Any, method: Method): ProxyMethodCacheFunction {
val (methodAccess, index) = ReflectAsmUtils.getMethodByRegex(
obj.javaClass,
"CGLIB\\\$${method.name}\\\$.*".toRegex(),
*method.parameterTypes,
method.returnType,
) ?: return CallSuperProxyMethodCacheFunction
return ReflectASMProxyMethodInvoker(obj, methodAccess, index).toJava()
}
override fun invoke( override fun invoke(
obj: Any?, obj: Any?,
c: ProxyContainer, c: ProxyContainer,

View File

@ -4,21 +4,20 @@ import cn.tursom.proxy.annotation.ForEachProxy
import cn.tursom.proxy.annotation.ForFirstProxy import cn.tursom.proxy.annotation.ForFirstProxy
import cn.tursom.proxy.container.ProxyContainer import cn.tursom.proxy.container.ProxyContainer
import cn.tursom.proxy.container.ProxyMethodCacheFunction import cn.tursom.proxy.container.ProxyMethodCacheFunction
import cn.tursom.reflect.asm.ReflectAsmInvoker
import net.sf.cglib.proxy.MethodProxy import net.sf.cglib.proxy.MethodProxy
import java.lang.reflect.Method import java.lang.reflect.Method
internal class JavaReflectProxyMethodInvoker( internal class JvmReflectProxyMethodInvoker(
private val self: Any, private val self: Any,
private val method: Method, private val method: Method,
) : ProxyMethodCacheFunction { ) : ProxyMethodCacheFunction {
companion object { companion object {
private val fastInvoker: Method.(Any?, Array<out Any?>?) -> Any? = Method::invoke
operator fun get( operator fun get(
proxy: Any, proxy: Any,
method: Method, method: Method,
): JavaReflectProxyMethodInvoker? { ): JvmReflectProxyMethodInvoker? {
var invoker: JavaReflectProxyMethodInvoker? = null var invoker: JvmReflectProxyMethodInvoker? = null
val selfMethod: Method val selfMethod: Method
try { try {
@ -39,9 +38,7 @@ internal class JavaReflectProxyMethodInvoker(
selfMethod = proxy.javaClass.getMethod(methodName, *method.parameterTypes) selfMethod = proxy.javaClass.getMethod(methodName, *method.parameterTypes)
selfMethod.isAccessible = true selfMethod.isAccessible = true
invoker = JavaReflectProxyMethodInvoker(proxy, method) invoker = JvmReflectProxyMethodInvoker(proxy, method)
//handlerCacheMap[method] = ProxyResult(invoker, true)
} catch (_: Exception) { } catch (_: Exception) {
} }
@ -56,6 +53,6 @@ internal class JavaReflectProxyMethodInvoker(
args: Array<out Any?>?, args: Array<out Any?>?,
proxy: MethodProxy?, proxy: MethodProxy?,
): Any? { ): Any? {
return fastInvoker(this.method, self, args) return ReflectAsmInvoker.invoke(this.method, self, args)
} }
} }

View File

@ -30,7 +30,6 @@ class OnForEachProxyImpl(
proxy: MethodProxy?, proxy: MethodProxy?,
): Any? { ): Any? {
m!! m!!
proxy!!
val proxyList = if (cache) ArrayList() else emptyProxyList val proxyList = if (cache) ArrayList() else emptyProxyList
c.forEach { p -> c.forEach { p ->
@ -42,9 +41,13 @@ class OnForEachProxyImpl(
} }
} }
} }
proxy!!
if (cache) { if (cache) {
c.ctx[ProxyMethodCache.ctxKey].update( c.ctx[ProxyMethodCache.ctxKey].update(
proxy, CachedOnForEachProxyImpl(proxyList) o!!, c, m, proxy,
CachedOnForEachProxyImpl(proxyList),
) )
} }
return proxy.invokeSuper(o, a) return proxy.invokeSuper(o, a)

View File

@ -32,6 +32,7 @@ class OnForFirstProxyImpl(
): Any? { ): Any? {
method!! method!!
proxy!! proxy!!
obj!!
container.forEach { p -> container.forEach { p ->
if (classes.isNotEmpty() && classes.none { c: Class<*> -> c.isInstance(p) }) { if (classes.isNotEmpty() && classes.none { c: Class<*> -> c.isInstance(p) }) {
@ -40,7 +41,7 @@ class OnForFirstProxyImpl(
val handler = ProxyMethod.getHandler(p, method) ?: return@forEach val handler = ProxyMethod.getHandler(p, method) ?: return@forEach
if (ffpAnnotation.cache) { if (ffpAnnotation.cache) {
container.ctx[ProxyMethodCache.ctxKey].update(proxy, handler) container.ctx[ProxyMethodCache.ctxKey].update(obj, container, method, proxy, handler)
} }
return handler(obj, container, method, args, proxy) return handler(obj, container, method, args, proxy)
} }
@ -68,15 +69,15 @@ class OnForFirstProxyImpl(
val exceptionConstructor = ffpAnnotation.errClass.java.getConstructor(String::class.java) val exceptionConstructor = ffpAnnotation.errClass.java.getConstructor(String::class.java)
if (ffpAnnotation.cache) { if (ffpAnnotation.cache) {
container.ctx[ProxyMethodCache.ctxKey].update( container.ctx[ProxyMethodCache.ctxKey].update(
proxy, ExceptionProxyMethodCacheFunctionImpl(exceptionConstructor, errMsg) obj, container, method, proxy, ExceptionProxyMethodCacheFunctionImpl(exceptionConstructor, errMsg)
) )
} }
throw exceptionConstructor.newInstance(errMsg) throw exceptionConstructor.newInstance(errMsg)
} }
if (ffpAnnotation.cache) { if (ffpAnnotation.cache) {
container.ctx[ProxyMethodCache.ctxKey].update( container.ctx[ProxyMethodCache.ctxKey].update(
proxy, obj, container, method, proxy,
CallSuperProxyMethodCacheFunction, CallSuperProxyMethodCacheFunction[obj, method]
) )
} }
return proxy.invokeSuper(obj, args) return proxy.invokeSuper(obj, args)

View File

@ -14,6 +14,13 @@ interface ProxyMethod {
// NO-OP // NO-OP
} }
fun onGet(f: ProxyMethodCacheFunction, method: Method): ProxyMethodCacheFunction = f
/**
* disabled on default.
*
* override onCached to enable it
*/
fun onProxyInvoke( fun onProxyInvoke(
o: Any?, o: Any?,
c: ProxyContainer, c: ProxyContainer,
@ -25,12 +32,25 @@ interface ProxyMethod {
return next(o, c, m, a, proxy) return next(o, c, m, a, proxy)
} }
/**
* 当有缓存更新时被调用
*
* 你可以以此替换缓存方法
*/
fun onProxyHandlerCacheUpdate(
f: ProxyMethodCacheFunction,
obj: Any,
container: ProxyContainer,
method: Method,
proxy: MethodProxy,
) = f
companion object { companion object {
fun getHandler(proxy: Any, method: Method): ProxyMethodCacheFunction? { fun getHandler(proxy: Any, method: Method): ProxyMethodCacheFunction? {
var handler = getReflectHandler(proxy, method) ?: return null var handler = getReflectHandler(proxy, method) ?: return null
if (proxy is ProxyMethod) { if (proxy is ProxyMethod) {
handler = ProxyMethodInvoker(proxy, handler) handler = proxy.onGet(handler, method)
} }
return handler return handler
@ -39,10 +59,10 @@ interface ProxyMethod {
private fun getReflectHandler(proxy: Any, method: Method): ProxyMethodCacheFunction? { private fun getReflectHandler(proxy: Any, method: Method): ProxyMethodCacheFunction? {
val reflectAsmHandler = ReflectASMProxyMethodInvoker[proxy, method] val reflectAsmHandler = ReflectASMProxyMethodInvoker[proxy, method]
if (reflectAsmHandler != null) { if (reflectAsmHandler != null) {
return reflectAsmHandler return reflectAsmHandler.toJava()
} }
val javaReflectHandler = JavaReflectProxyMethodInvoker[proxy, method] val javaReflectHandler = JvmReflectProxyMethodInvoker[proxy, method]
if (javaReflectHandler != null) { if (javaReflectHandler != null) {
return javaReflectHandler return javaReflectHandler
} }

View File

@ -2,6 +2,7 @@ package cn.tursom.proxy.function
import cn.tursom.proxy.container.ProxyContainer import cn.tursom.proxy.container.ProxyContainer
import cn.tursom.proxy.container.ProxyMethodCacheFunction import cn.tursom.proxy.container.ProxyMethodCacheFunction
import cn.tursom.reflect.asm.ReflectAsmInvoker
import cn.tursom.reflect.asm.ReflectAsmUtils import cn.tursom.reflect.asm.ReflectAsmUtils
import com.esotericsoftware.reflectasm.MethodAccess import com.esotericsoftware.reflectasm.MethodAccess
import net.sf.cglib.proxy.MethodProxy import net.sf.cglib.proxy.MethodProxy
@ -13,19 +14,35 @@ internal class ReflectASMProxyMethodInvoker(
private val index: Int, private val index: Int,
) : ProxyMethodCacheFunction { ) : ProxyMethodCacheFunction {
companion object { companion object {
private val fastInvoker: MethodAccess.(Any, Int, Array<out Any?>?) -> Any? = MethodAccess::invoke
operator fun get( operator fun get(
proxy: Any, proxy: Any,
method: Method, method: Method,
): ReflectASMProxyMethodInvoker? { ): ReflectASMProxyMethodInvoker? {
val reflectAsmMethod = try { val reflectAsmMethod = try {
ReflectAsmUtils.getMethod( val methodParamTypes = method.parameterTypes
val matchedMethods = ReflectAsmUtils.getMethodSequence(
proxy.javaClass, proxy.javaClass,
method.name, method.name,
paramTypes = method.parameterTypes, paramTypes = methodParamTypes,
returnType = method.returnType, returnType = method.returnType,
) ).toList()
when {
matchedMethods.isEmpty() -> null
matchedMethods.size == 1 -> matchedMethods.first()
else -> matchedMethods.minBy { (methodAccess, methodIndex) ->
var parameterIndex = 0
methodAccess.parameterTypes[methodIndex].sumOf { parameterType ->
if (methodParamTypes[parameterIndex++] != parameterType) {
0L
} else {
1L
}
}
}
}
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
null null
@ -36,6 +53,8 @@ internal class ReflectASMProxyMethodInvoker(
} }
} }
fun toJava() = JavaReflectASMProxyMethodInvoker(self, methodAccess, index)
override fun invoke( override fun invoke(
obj: Any?, obj: Any?,
c: ProxyContainer, c: ProxyContainer,
@ -43,6 +62,6 @@ internal class ReflectASMProxyMethodInvoker(
args: Array<out Any?>?, args: Array<out Any?>?,
proxy: MethodProxy?, proxy: MethodProxy?,
): Any? { ): Any? {
return fastInvoker(methodAccess, self, index, args) return ReflectAsmInvoker.invoke(methodAccess, self, index, args)
} }
} }

View File

@ -0,0 +1,7 @@
package cn.tursom.proxy.interceptor
import net.sf.cglib.proxy.MethodInterceptor
interface CachedMethodInterceptor : MethodInterceptor {
fun clearCache()
}

View File

@ -1,5 +1,6 @@
package cn.tursom.proxy.interceptor package cn.tursom.proxy.interceptor
import cn.tursom.reflect.asm.ReflectAsmInvoker
import cn.tursom.reflect.asm.ReflectAsmUtils import cn.tursom.reflect.asm.ReflectAsmUtils
import com.esotericsoftware.reflectasm.MethodAccess import com.esotericsoftware.reflectasm.MethodAccess
import net.sf.cglib.proxy.InvocationHandler import net.sf.cglib.proxy.InvocationHandler
@ -8,10 +9,6 @@ import java.lang.reflect.Method
class LocalCachedNoProxyInvocationHandler( class LocalCachedNoProxyInvocationHandler(
val proxy: Any, val proxy: Any,
) : InvocationHandler { ) : InvocationHandler {
companion object {
private val fastInvoker: MethodAccess.(Any, Int, Array<out Any?>?) -> Any? = MethodAccess::invoke
}
private var handler: (method: Method?, args: Array<out Any>?) -> Any? = DefaultHandler() private var handler: (method: Method?, args: Array<out Any>?) -> Any? = DefaultHandler()
override fun invoke(ignore: Any, method: Method?, args: Array<out Any>?): Any? { override fun invoke(ignore: Any, method: Method?, args: Array<out Any>?): Any? {
@ -29,7 +26,7 @@ class LocalCachedNoProxyInvocationHandler(
method.returnType, method.returnType,
)!! )!!
handler = MethodAccessHandler(methodAccess, index) handler = MethodAccessHandler(methodAccess, index)
return fastInvoker(methodAccess, proxy, index, args) return ReflectAsmInvoker.invoke(methodAccess, proxy, index, args)
} }
} }
@ -37,6 +34,7 @@ class LocalCachedNoProxyInvocationHandler(
private val methodAccess: MethodAccess, private val methodAccess: MethodAccess,
private val index: Int, private val index: Int,
) : (Method?, Array<out Any>?) -> Any? { ) : (Method?, Array<out Any>?) -> Any? {
override fun invoke(method: Method?, args: Array<out Any>?) = fastInvoker(methodAccess, proxy, index, args) override fun invoke(method: Method?, args: Array<out Any>?) =
ReflectAsmInvoker.invoke(methodAccess, proxy, index, args)
} }
} }

View File

@ -3,29 +3,36 @@ package cn.tursom.proxy.interceptor
import cn.tursom.proxy.container.ProxyContainer import cn.tursom.proxy.container.ProxyContainer
import cn.tursom.proxy.container.ProxyMethodCache import cn.tursom.proxy.container.ProxyMethodCache
import cn.tursom.proxy.container.ProxyMethodCacheFunction import cn.tursom.proxy.container.ProxyMethodCacheFunction
import net.sf.cglib.proxy.Factory
import net.sf.cglib.proxy.MethodProxy import net.sf.cglib.proxy.MethodProxy
import java.lang.reflect.Method import java.lang.reflect.Method
class LocalCachedProxyInterceptor( class LocalCachedProxyInterceptor(
container: ProxyContainer, container: ProxyContainer,
nonProxyClasses: MutableSet<Class<*>>, val target: Factory,
val target: Any, ) : ProxyInterceptor(container), CachedMethodInterceptor {
) : ProxyInterceptor(container, nonProxyClasses) {
private var cache: ProxyMethodCacheFunction? = null private var cache: ProxyMethodCacheFunction? = null
private val c: ProxyContainer = container
override fun intercept(obj: Any?, method: Method?, args: Array<out Any?>?, proxy: MethodProxy): Any? { override fun clearCache() {
cache = null
}
override fun intercept(obj: Any?, method: Method?, args: Array<out Any?>?, proxy: MethodProxy?): Any? {
var cache = this.cache var cache = this.cache
if (cache != null) { if (cache != null) {
return cache(target, container, method, args, proxy) return cache(target, c, method, args, proxy)
} }
val methodCache = container.ctx[ProxyMethodCache.ctxKey] proxy!!
val methodCache = c.ctx[ProxyMethodCache.ctxKey]
this.cache = methodCache[proxy] this.cache = methodCache[proxy]
cache = this.cache cache = this.cache
if (cache != null) { if (cache != null) {
return cache(target, container, method, args, proxy) return cache(target, c, method, args, proxy)
} }
return super.intercept(target, method, args, proxy) return super.intercept(target, method, args, proxy)

View File

@ -13,25 +13,25 @@ import net.sf.cglib.proxy.MethodProxy
import java.lang.reflect.Method import java.lang.reflect.Method
open class ProxyInterceptor( open class ProxyInterceptor(
val container: ProxyContainer = ListProxyContainer(), val container: ProxyContainer = ListProxyContainer(nonProxyClasses = HashSet(listOf(Any::class.java))),
val nonProxyClasses: MutableSet<Class<*>> = HashSet(listOf(Any::class.java)),
) : MethodInterceptor { ) : MethodInterceptor {
override fun intercept(obj: Any?, method: Method?, args: Array<out Any?>?, proxy: MethodProxy): Any? { override fun intercept(obj: Any?, method: Method?, args: Array<out Any?>?, proxy: MethodProxy?): Any? {
val cache = container.ctx[ProxyMethodCache.ctxKey] val cache = container.ctx[ProxyMethodCache.ctxKey]
var handler = cache[proxy] var handler = cache[proxy!!]
if (handler != null) { if (handler != null) {
return handler(obj, container, method, args, proxy) return handler(obj, container, method, args, proxy)
} }
obj!!
method!! method!!
nonProxyClasses.forEach { nonProxyClass -> container.nonProxyClasses.forEach { nonProxyClass ->
nonProxyClass.declaredMethods.forEach { nonProxyClass.declaredMethods.forEach {
if (it.name == method.name && if (it.name == method.name &&
it.returnType.isAssignableFrom(method.returnType) && it.returnType.isAssignableFrom(method.returnType) &&
it.parameterTypes.contentEquals(method.parameterTypes) it.parameterTypes.contentEquals(method.parameterTypes)
) { ) {
cache.update(proxy, CallSuperProxyMethodCacheFunction) cache.update(obj, container, method, proxy, CallSuperProxyMethodCacheFunction[obj, method])
return proxy.invokeSuper(obj, args) return proxy.invokeSuper(obj, args)
} }
} }

View File

@ -2,37 +2,32 @@ package cn.tursom.proxy
import cn.tursom.core.allFieldsSequence import cn.tursom.core.allFieldsSequence
import cn.tursom.core.static import cn.tursom.core.static
import cn.tursom.proxy.container.ProxyContainer
import cn.tursom.proxy.container.ProxyMethodCacheFunction
import cn.tursom.proxy.function.ProxyMethod
import com.esotericsoftware.reflectasm.MethodAccess import com.esotericsoftware.reflectasm.MethodAccess
import net.sf.cglib.proxy.InvocationHandler import net.sf.cglib.proxy.InvocationHandler
import net.sf.cglib.proxy.MethodProxy import net.sf.cglib.proxy.MethodProxy
import org.junit.Test import org.junit.Test
import org.objectweb.asm.ClassWriter import org.objectweb.asm.ClassWriter
import java.io.File import java.io.File
import java.lang.reflect.Method
class Example { class Example {
companion object { companion object {
var bytes: ByteArray? = null var bytes: ByteArray? = null
fun saveBytes(b: ByteArray) {
bytes = b
}
} }
open class TestClass protected constructor() { open class TestClass protected constructor() {
open var a: Int = 0 open var a: Int? = 0
} }
class GetA( class GetA(
t: TestClass, t: TestClass,
) { ) : ProxyMethod {
val t: TestClass = Proxy.getSuperCaller(t) val t: TestClass = Proxy.getSuperCaller(t)
val a: Int val a get() = (t.a ?: 0) + 1
get() = t.a + 1
//fun getA(): Int {
// return t.a + 1
//}
} }
@Test @Test
@ -95,9 +90,35 @@ class Example {
container.addProxy(GetA(t)) container.addProxy(GetA(t))
println(t.javaClass) println(t.javaClass)
repeat(1000000000) { for (l in 0..10_000_000_000L) {
t.a = t.a t.a = t.a
//println(t.a) }
}
interface IntContainer {
var i: Int?
}
class IntContainerImpl(override var i: Int?) : IntContainer
class IntProxy(
private val c: IntContainer,
) : IntContainer {
override var i: Int?
get() = (c.i ?: 0) + 1
set(value) {
c.i = value
}
}
private val a: IntContainerImpl = IntContainerImpl(0)
@Test
fun benchmarkOrigin() {
val p: IntContainer = IntProxy(a)
for (l in 0..10000000000L) {
p.i = p.i
} }
} }
} }

View File

@ -0,0 +1,19 @@
package cn.tursom.reflect.asm;
import com.esotericsoftware.reflectasm.MethodAccess;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectAsmInvoker {
@Nullable
public static Object invoke(MethodAccess methodAccess, Object obj, int index, Object[] args) {
return methodAccess.invoke(obj, index, args);
}
@Nullable
public static Object invoke(Method method, Object obj, Object[] args) throws InvocationTargetException, IllegalAccessException {
return method.invoke(obj, args);
}
}

View File

@ -62,6 +62,7 @@ object ReflectAsmUtils {
} catch (_: Exception) { } catch (_: Exception) {
} }
} }
fieldAccessList.add(MethodAccess.get(analyzeFieldAccessClass)!!)
methodAccessMap[this] = fieldAccessList methodAccessMap[this] = fieldAccessList
fieldAccessList fieldAccessList
} }
@ -84,6 +85,41 @@ object ReflectAsmUtils {
return null return null
} }
fun getMethodSequence(
clazz: Class<*>,
methodName: String,
vararg paramTypes: Class<*>,
returnType: Class<*> = Any::class.java,
) = sequence {
clazz.methodAccessList.forEach { methodAccess ->
repeat(methodAccess.methodNames.size) { i ->
if (methodAccess.methodNames[i] == methodName && methodAccess.parameterTypes[i] match paramTypes &&
methodAccess.returnTypes[i] canCast returnType
) {
yield(methodAccess to i)
}
}
}
}
fun getMethodByRegex(
clazz: Class<*>,
methodName: Regex,
vararg paramTypes: Class<*>,
returnType: Class<*> = Any::class.java,
): Pair<MethodAccess, Int>? {
clazz.methodAccessList.forEach { methodAccess ->
repeat(methodAccess.methodNames.size) { i ->
if (methodName.matches(methodAccess.methodNames[i]) && methodAccess.parameterTypes[i] match paramTypes &&
methodAccess.returnTypes[i] canCast returnType
) {
return methodAccess to i
}
}
}
return null
}
fun getMethod(method: Method): Pair<MethodAccess, Int>? = getMethod( fun getMethod(method: Method): Pair<MethodAccess, Int>? = getMethod(
method.declaringClass, method.declaringClass,
method.name, method.name,

View File

@ -1,6 +1,6 @@
package cn.tursom.database.ktorm.ext package cn.tursom.database.ktorm.ext
import cn.tursom.proxy.ProxyMethod import cn.tursom.proxy.function.ProxyMethod
import cn.tursom.reflect.asm.ReflectAsmKtField import cn.tursom.reflect.asm.ReflectAsmKtField
import org.ktorm.expression.SqlExpression import org.ktorm.expression.SqlExpression
import org.ktorm.expression.SqlFormatter import org.ktorm.expression.SqlFormatter

View File

@ -2,7 +2,7 @@
import java.util.* import java.util.*
plugins { plugins {
kotlin("jvm") version "1.3.72" kotlin("jvm") version "1.7.10"
`java-gradle-plugin` `java-gradle-plugin`
`maven-publish` `maven-publish`
} }
@ -14,10 +14,10 @@ try {
ext.set(k.toString(), v) ext.set(k.toString(), v)
try { try {
setProperty(k.toString(), v) setProperty(k.toString(), v)
} catch (e: Exception) { } catch (_: Exception) {
} }
} }
} catch (e: Exception) { } catch (_: Exception) {
} }
group = "cn.tursom" group = "cn.tursom"
@ -25,11 +25,13 @@ group = "cn.tursom"
version = "1.0-SNAPSHOT" version = "1.0-SNAPSHOT"
repositories { repositories {
mavenCentral() maven {
url = uri("https://nvm.tursom.cn/repository/maven-public/")
}
} }
dependencies { dependencies {
implementation(group = "org.yaml", name = "snakeyaml", version = "1.29") implementation(group = "org.yaml", name = "snakeyaml", version = "1.33")
implementation(fileTree(mapOf("dir" to "libs", "include" to arrayOf("*.jar")))) implementation(fileTree(mapOf("dir" to "libs", "include" to arrayOf("*.jar"))))
} }
@ -60,7 +62,7 @@ publishing {
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
println("cannot push to repository tursom") println("cannot push to repository tursom: ${e.javaClass}: ${e.message}")
} }
try { try {
maven { maven {

View File

@ -1,12 +1,15 @@
import org.gradle.api.DomainObjectCollection import org.gradle.api.DomainObjectCollection
import org.gradle.api.NamedDomainObjectCollection
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.dsl.RepositoryHandler
import org.gradle.api.artifacts.repositories.PasswordCredentials
import org.gradle.api.publish.PublicationContainer
import org.gradle.api.publish.PublishingExtension import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication import org.gradle.api.publish.maven.MavenPublication
import org.gradle.internal.authentication.DefaultBasicAuthentication
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
var nettyVersion = "4.1.68.Final"
fun Project.excludeTest() { fun Project.excludeTest() {
if (gradle.startParameter.taskNames.firstOrNull { taskName -> if (gradle.startParameter.taskNames.firstOrNull { taskName ->
taskName.contains("test", true) taskName.contains("test", true)
@ -17,92 +20,13 @@ fun Project.excludeTest() {
named("compileTestJava") { it.enabled = false } named("compileTestJava") { it.enabled = false }
try { try {
named("compileTestKotlin") { it.enabled = false } named("compileTestKotlin") { it.enabled = false }
} catch (e: Exception) { } catch (_: Exception) {
} }
named("processTestResources") { it.enabled = false } named("processTestResources") { it.enabled = false }
} }
} }
} }
fun Project.publish(publish: PublishingExtension) {
val properties = rootProject.properties
publish.repositories { repositoryHandler ->
try {
repositoryHandler.maven { repository ->
repository.name = "tursom"
repository.url = if (version.toString().endsWith("SNAPSHOT")) {
uri("https://nvm.tursom.cn/repository/maven-snapshots/")
} else {
uri("https://nvm.tursom.cn/repository/maven-releases/")
}
repository.credentials { credentials ->
val artifactoryUser: String = rootProject.ext["tursom.artifactoryUser"]!!.toString()
val artifactoryPassword: String = rootProject.ext["tursom.artifactoryPassword"]!!.toString()
credentials.username = artifactoryUser
credentials.password = artifactoryPassword
}
}
} catch (e: Exception) {
println("cannot publish to repository tursom:\n${e.javaClass}: ${e.message}")
}
val repositoriesRegex = "publishRepositories\\.[a-zA-z][a-zA-z0-9]*".toRegex()
properties.keys.asSequence().filter {
it matches repositoriesRegex
}.forEach { repositoryName ->
try {
val artifactoryUser = rootProject.ext["$repositoryName.artifactoryUser"]?.toString()
?: throw Exception("no artifactory user found")
val artifactoryPassword = rootProject.ext["$repositoryName.artifactoryPassword"]?.toString()
?: throw Exception("no artifactory password found")
repositoryHandler.maven { repository ->
repository.name = properties["$repository.name"]?.toString()
?: repositoryName.substringAfterLast('.')
val releasesRepoUrl = properties["$repositoryName.release"]?.let {
uri(it.toString())
}
val snapshotRepoUrl = properties["$repositoryName.snapshot"]?.let {
uri(it.toString())
}
val repoUrl = properties["$repositoryName.url"]?.let {
uri(it.toString())
}
repository.url = if (version.toString().endsWith("SNAPSHOT") && snapshotRepoUrl != null) {
snapshotRepoUrl
} else {
releasesRepoUrl
} ?: repoUrl ?: throw Exception("no repo found")
repository.credentials {
it.username = artifactoryUser
it.password = artifactoryPassword
}
}
} catch (e: Exception) {
println(
"cannot publish to repository ${repositoryName.substringAfterLast('.')}:\n" +
"${e.javaClass}: ${e.message}"
)
}
}
}
publish.publications {
it.create("maven", MavenPublication::class.java) { mavenPublication ->
mavenPublication.groupId = project.group.toString()
mavenPublication.artifactId = project.name
mavenPublication.version = project.version.toString()
try {
mavenPublication.from(components.getByName("java"))
} catch (e: Exception) {
}
try {
mavenPublication.artifact(tasks.getByName("kotlinSourcesJar"))
} catch (e: Exception) {
}
}
}
}
fun DomainObjectCollection<Configuration>.noExpire() { fun DomainObjectCollection<Configuration>.noExpire() {
all { all {
it.resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS) it.resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS)
@ -110,7 +34,7 @@ fun DomainObjectCollection<Configuration>.noExpire() {
} }
} }
fun Project.userTursomRepositories( fun Project.useTursomRepositories(
useAliyunMirror: Boolean = false, useAliyunMirror: Boolean = false,
mavenCentral: Boolean = false, mavenCentral: Boolean = false,
tursom: Boolean = true tursom: Boolean = true
@ -132,6 +56,19 @@ fun Project.userTursomRepositories(
} }
try { try {
configurations.noExpire() configurations.noExpire()
} catch (_: Exception) {
}
}
fun <T> NamedDomainObjectCollection<T>.contains(name: String) = try {
findByName(name)
} catch (e: Exception) { } catch (e: Exception) {
} null
} } != null
operator fun Project.get(key: String) = ext[key]?.toString()
val Project.isTestRunning
get() = gradle.startParameter.taskNames.firstOrNull { taskName ->
taskName.endsWith(":test")
} != null

View File

@ -1,5 +1,6 @@
package cn.tursom.gradle package cn.tursom.gradle
import contains
import excludeTest import excludeTest
import ext import ext
import org.gradle.api.DefaultTask import org.gradle.api.DefaultTask
@ -37,19 +38,7 @@ class TursomGradlePlugin : Plugin<Project> {
target.excludeTest() target.excludeTest()
try { if (!target.tasks.contains("install")) run install@{
target.extensions.configure<PublishingExtension>("publishing") {
target.publish(it)
}
} catch (e: Exception) {
}
if (try {
target.tasks.findByName("install")
} catch (e: Exception) {
null
} == null
) run install@{
val publishToMavenLocal = target.tasks.findByName("publishToMavenLocal") ?: return@install val publishToMavenLocal = target.tasks.findByName("publishToMavenLocal") ?: return@install
target.tasks.register("install", DefaultTask::class.java) { target.tasks.register("install", DefaultTask::class.java) {
it.finalizedBy(publishToMavenLocal) it.finalizedBy(publishToMavenLocal)
@ -85,6 +74,7 @@ fun put(target: Project, key: String, value: Any?) {
null -> return null -> return
is String, is Byte, is Short, is Int, is Long, is Float, is Double, is Char -> is String, is Byte, is Short, is Int, is Long, is Float, is Double, is Char ->
setProperty(target, key, value) setProperty(target, key, value)
else -> { else -> {
setProperty(target, key, value) setProperty(target, key, value)
if (value is Map<*, *>) { if (value is Map<*, *>) {

View File

@ -0,0 +1 @@
var nettyVersion = "4.1.68.Final"

View File

@ -0,0 +1,176 @@
import org.gradle.api.Project
import org.gradle.api.artifacts.dsl.RepositoryHandler
import org.gradle.api.artifacts.repositories.PasswordCredentials
import org.gradle.api.publish.PublicationContainer
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.authentication.http.BasicAuthentication
fun Project.autoConfigPublish() {
try {
extensions.configure("publishing", ::publish)
} catch (e: Exception) {
println("auto config publish failed: ${e.javaClass} ${e.message}")
}
}
fun Project.publish(publish: PublishingExtension) {
publish.repositories { repositoryHandler ->
createTursomPublishRepository(repositoryHandler)
scanAndCreatePublishRepository(repositoryHandler)
}
publish.publications(::createMavenPublications)
}
/**
* create publish repository for tursom's server
*/
private fun Project.createTursomPublishRepository(repositoryHandler: RepositoryHandler) {
try {
repositoryHandler.maven { repository ->
repository.name = "tursom"
val version = getVersionWithProperties()
if (warnVersionNotSet(version)) {
return@maven
}
repository.url = if (version.endsWith("SNAPSHOT")) {
uri("https://nvm.tursom.cn/repository/maven-snapshots/")
} else {
uri("https://nvm.tursom.cn/repository/maven-releases/")
}
repository.authentication{ ac ->
ac.forEach {
}
}
repository.credentials(PasswordCredentials::class.java) { credentials ->
val artifactoryUser: String = rootProject.ext["tursom.artifactoryUser"]!!.toString()
val artifactoryPassword: String = rootProject.ext["tursom.artifactoryPassword"]!!.toString()
credentials.username = artifactoryUser
credentials.password = artifactoryPassword
}
}
} catch (e: Exception) {
println("cannot publish to repository tursom:\n${e.javaClass}: ${e.message}")
}
}
/**
* scan properties begin with "publishRepositories" to create user defined publish repository
*/
private fun Project.scanAndCreatePublishRepository(repositoryHandler: RepositoryHandler) {
val properties = rootProject.properties
val repositoriesRegex = "^publishRepositories\\.[a-zA-z][a-zA-z0-9]*$".toRegex()
properties.keys.asSequence().filter {
it matches repositoriesRegex
}.forEach { repositoryName ->
try {
val artifactoryUser = rootProject.ext["$repositoryName.artifactoryUser"]?.toString()
?: throw Exception("no artifactory user found")
val artifactoryPassword = rootProject.ext["$repositoryName.artifactoryPassword"]?.toString()
?: throw Exception("no artifactory password found")
repositoryHandler.maven { repository ->
repository.name = properties["$repository.name"]?.toString()
?: repositoryName.substringAfterLast('.')
val releasesRepoUrl = properties["$repositoryName.release"]?.let {
uri(it.toString())
}
val snapshotRepoUrl = properties["$repositoryName.snapshot"]?.let {
uri(it.toString())
}
val repoUrl = properties["$repositoryName.url"]?.let {
uri(it.toString())
}
repository.url = if (version.toString().endsWith("SNAPSHOT") && snapshotRepoUrl != null) {
snapshotRepoUrl
} else {
releasesRepoUrl
} ?: repoUrl ?: throw Exception("no repo found")
repository.credentials {
it.username = artifactoryUser
it.password = artifactoryPassword
}
}
} catch (e: Exception) {
println(
"cannot publish to repository ${repositoryName.substringAfterLast('.')}:\n" +
"${e.javaClass}: ${e.message}"
)
}
}
}
private fun Project.createMavenPublications(pc: PublicationContainer) {
pc.maybeCreate("maven", MavenPublication::class.java).let { mavenPublication ->
val groupId = project.group.toString()
.ifBlank { ext.properties["project.groupId"]?.toString() }
if (warnGroupIdNotSet(groupId)) {
return
}
val version = getVersionWithProperties()
if (warnVersionNotSet(version)) {
return
}
mavenPublication.groupId = groupId
mavenPublication.artifactId = project.name
mavenPublication.version = version
try {
mavenPublication.from(components.getByName("java"))
} catch (_: Exception) {
}
try {
mavenPublication.artifact(tasks.getByName("kotlinSourcesJar"))
} catch (_: Exception) {
}
}
}
/**
* warn user that group id is not set.
* @return true if group id is not set
* false if group id is set.
*/
private fun Project.warnGroupIdNotSet(groupId: String?) = if (groupId.isNullOrEmpty()) {
println(
"cannot publish to maven of project $this cause group id is not set. " +
"you can specific property \"project.groupId\" to solve it."
)
true
} else {
false
}
/**
* warn user that group id is not set.
* @return true if group id is not set
* false if group id is set.
*/
private fun Project.warnVersionNotSet(version: String?) = if (isEmptyVersion(version)) {
println(
"cannot publish to maven of project $this cause version is not set. " +
"you can specific property \"project.version\" to solve it."
)
true
} else {
false
}
private fun isEmptyVersion(version: String?) = version.isNullOrEmpty() || version == Project.DEFAULT_VERSION
private fun Project.getVersionWithProperties(): String {
var version = this.version.toString()
if (isEmptyVersion(version)) {
version = ext["project.version"]?.toString() ?: Project.DEFAULT_VERSION
}
return version
}

View File

@ -313,7 +313,6 @@ open class RoutedHttpHandler(
fun autoReturn(result: Any?, content: HttpContent, doLog: Boolean = true) { fun autoReturn(result: Any?, content: HttpContent, doLog: Boolean = true) {
if (content.finished || result is Unit) return if (content.finished || result is Unit) return
if (doLog) log?.debug("{}: autoReturn: {}", content.remoteAddress, result) if (doLog) log?.debug("{}: autoReturn: {}", content.remoteAddress, result)
result ?: return
when (result) { when (result) {
null -> content.finish(404) null -> content.finish(404)
is ByteBuffer -> content.finishText(result) is ByteBuffer -> content.finishText(result)
@ -336,7 +335,6 @@ open class RoutedHttpHandler(
fun finishHtml(result: Any?, content: HttpContent, doLog: Boolean = true) { fun finishHtml(result: Any?, content: HttpContent, doLog: Boolean = true) {
if (content.finished || result is Unit) return if (content.finished || result is Unit) return
if (doLog) log?.debug("{} finishHtml {}", content.remoteAddress, result) if (doLog) log?.debug("{} finishHtml {}", content.remoteAddress, result)
result ?: return
when (result) { when (result) {
null -> content.finish(404) null -> content.finish(404)
is ByteBuffer -> content.finishHtml(result) is ByteBuffer -> content.finishHtml(result)
@ -355,7 +353,6 @@ open class RoutedHttpHandler(
fun finishText(result: Any?, content: HttpContent, doLog: Boolean = true) { fun finishText(result: Any?, content: HttpContent, doLog: Boolean = true) {
if (content.finished || result is Unit) return if (content.finished || result is Unit) return
if (doLog) log?.debug("{} finishText {}", content.remoteAddress, result) if (doLog) log?.debug("{} finishText {}", content.remoteAddress, result)
result ?: return
when (result) { when (result) {
null -> content.finish(404) null -> content.finish(404)
is ByteBuffer -> content.finishText(result) is ByteBuffer -> content.finishText(result)
@ -374,7 +371,6 @@ open class RoutedHttpHandler(
fun finishJson(result: Any?, content: HttpContent, doLog: Boolean = true) { fun finishJson(result: Any?, content: HttpContent, doLog: Boolean = true) {
if (content.finished || result is Unit) return if (content.finished || result is Unit) return
if (doLog) log?.debug("{} finishJson {}", content.remoteAddress, result) if (doLog) log?.debug("{} finishJson {}", content.remoteAddress, result)
result ?: return
when (result) { when (result) {
null -> content.finish(404) null -> content.finish(404)
is ByteBuffer -> content.finishJson(result) is ByteBuffer -> content.finishJson(result)

View File

@ -15,6 +15,7 @@ class NettyChunkedInput(private val chunked: Chunked) : ChunkedInput<ByteBuf> {
override fun length() = chunked.length override fun length() = chunked.length
override fun isEndOfInput(): Boolean = chunked.endOfInput override fun isEndOfInput(): Boolean = chunked.endOfInput
@Deprecated("Deprecated in Java", ReplaceWith("readChunk(allocator)"))
override fun readChunk(ctx: ChannelHandlerContext?): ByteBuf = readChunk() override fun readChunk(ctx: ChannelHandlerContext?): ByteBuf = readChunk()
override fun readChunk(allocator: ByteBufAllocator?): ByteBuf = readChunk() override fun readChunk(allocator: ByteBufAllocator?): ByteBuf = readChunk()