Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2dd62ec7c4 | ||
|
|
c8b183da71 | ||
|
|
620afef715 | ||
|
|
816e672843 | ||
|
|
8842566ee2 | ||
|
|
306bfd36f7 | ||
|
|
7267aec1fd | ||
|
|
6de65562be | ||
|
|
e243203535 | ||
|
|
e4f4c77c19 |
@@ -1,14 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/KNElib"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk-19">
|
||||
<classpathentry kind="lib" path="lib/gson-2.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/javassist.jar" sourcepath="C:/Users/ADMINI~1/AppData/Local/Temp/1/.org.sf.feeling.decompiler1686963856070/source/javassist-3.29.2-GA-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/ini4j.jar"/>
|
||||
<classpathentry kind="lib" path="lib/JFreeChart1.5.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/toml4j-0.7.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/pcap4j-core-1.8.2.jar" sourcepath="C:/Users/ADMINI~1/AppData/Local/Temp/1/.org.sf.feeling.decompiler1725520274095/source/pcap4j-core-1.8.2-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/pcap4j-packetfactory-propertiesbased-1.8.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/pcap4j-packetfactory-static-1.8.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/pcap4j-sample-1.8.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/slf4j-api-2.0.9.jar"/>
|
||||
<classpathentry kind="lib" path="lib/slf4j-api-2.0.9-javadoc.jar"/>
|
||||
<classpathentry kind="lib" path="lib/slf4j-api-2.0.9-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/slf4j-api-2.0.9-tests.jar"/>
|
||||
<classpathentry kind="lib" path="lib/disruptor-4.0.0.jar" sourcepath="lib/disruptor-4.0.0-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/disruptor-4.0.0-javadoc.jar"/>
|
||||
<classpathentry kind="lib" path="lib/disruptor-4.0.0-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/KNElib1.0.jar"/>
|
||||
<classpathentry kind="lib" path="lib/KNEOptimize.jar"/>
|
||||
<classpathentry kind="lib" path="lib/JavaTUN0.3.jar"/>
|
||||
<classpathentry kind="lib" path="lib/uuid-creator-6.1.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jctools-core-4.0.6.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jctools-core-4.0.6-javadoc.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jctools-core-4.0.6-sources.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk-26.0.1">
|
||||
<attributes>
|
||||
<attribute name="module" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="lib" path="lib/gson-2.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/javassist.jar" sourcepath="C:/Users/ADMINI~1/AppData/Local/Temp/1/.org.sf.feeling.decompiler1686963856070/source/javassist-3.29.2-GA-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/ini4j.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Ignored default folder with query files
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2">
|
||||
<output url="file://$PROJECT_DIR$/classes" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/KLALB.iml" filepath="$PROJECT_DIR$/KLALB.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,253 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="EclipseModuleManager">
|
||||
<libelement value="jar://$MODULE_DIR$/lib/gson-2.1.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/javassist.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/ini4j.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/JFreeChart1.5.2.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/toml4j-0.7.1.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/pcap4j-core-1.8.2.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/pcap4j-packetfactory-propertiesbased-1.8.2.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/pcap4j-packetfactory-static-1.8.2.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/pcap4j-sample-1.8.2.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/slf4j-api-2.0.9.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/slf4j-api-2.0.9-javadoc.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/slf4j-api-2.0.9-sources.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/slf4j-api-2.0.9-tests.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/disruptor-4.0.0.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/disruptor-4.0.0-javadoc.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/disruptor-4.0.0-sources.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/KNElib1.0.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/KNEOptimize.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/JavaTUN0.3.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/uuid-creator-6.1.1.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/jctools-core-4.0.6.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/jctools-core-4.0.6-javadoc.jar!/" />
|
||||
<libelement value="jar://$MODULE_DIR$/lib/jctools-core-4.0.6-sources.jar!/" />
|
||||
<src_description expected_position="0">
|
||||
<src_folder value="file://$MODULE_DIR$/src" expected_position="0" />
|
||||
</src_description>
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
<output url="file://$MODULE_DIR$/bin" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module-library">
|
||||
<library name="gson-2.1.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/gson-2.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="javassist.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/javassist.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="file://$MODULE_DIR$/../../../../Users/ADMINI~1/AppData/Local/Temp/1/.org.sf.feeling.decompiler1686963856070/source/javassist-3.29.2-GA-sources.jar" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="ini4j.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/ini4j.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="JFreeChart1.5.2.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/JFreeChart1.5.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="toml4j-0.7.1.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/toml4j-0.7.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="pcap4j-core-1.8.2.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/pcap4j-core-1.8.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="file://$MODULE_DIR$/../../../../Users/ADMINI~1/AppData/Local/Temp/1/.org.sf.feeling.decompiler1725520274095/source/pcap4j-core-1.8.2-sources.jar" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="pcap4j-packetfactory-propertiesbased-1.8.2.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/pcap4j-packetfactory-propertiesbased-1.8.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="pcap4j-packetfactory-static-1.8.2.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/pcap4j-packetfactory-static-1.8.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="pcap4j-sample-1.8.2.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/pcap4j-sample-1.8.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="slf4j-api-2.0.9.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/slf4j-api-2.0.9.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="slf4j-api-2.0.9-javadoc.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/slf4j-api-2.0.9-javadoc.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="slf4j-api-2.0.9-sources.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/slf4j-api-2.0.9-sources.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="slf4j-api-2.0.9-tests.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/slf4j-api-2.0.9-tests.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="disruptor-4.0.0.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/disruptor-4.0.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$MODULE_DIR$/lib/disruptor-4.0.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="disruptor-4.0.0-javadoc.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/disruptor-4.0.0-javadoc.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="disruptor-4.0.0-sources.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/disruptor-4.0.0-sources.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="KNElib1.0.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/KNElib1.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="KNEOptimize.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/KNEOptimize.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="JavaTUN0.3.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/JavaTUN0.3.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="uuid-creator-6.1.1.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/uuid-creator-6.1.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="jctools-core-4.0.6.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/jctools-core-4.0.6.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="jctools-core-4.0.6-javadoc.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/jctools-core-4.0.6-javadoc.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="jctools-core-4.0.6-sources.jar">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/jctools-core-4.0.6-sources.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="jdk" jdkName="jdk-26.0.1" jdkType="JavaSDK" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,123 @@
|
||||
[
|
||||
{
|
||||
"language": "ZH_CN",
|
||||
"nogui": false,
|
||||
"VirtualAddress": "2486:1:0:0:0:0:0:8888",
|
||||
"VirtualASN": 2142606939373348329,
|
||||
"DNS": [
|
||||
"2486:1:0:0:0:0:0:8888"
|
||||
],
|
||||
"TCPListen": "0.0.0.0:4565",
|
||||
"UDPListen": "{UDP}0.0.0.0:4572",
|
||||
"VirtualSocketName": "KLALB_Stream",
|
||||
"LineTable": [
|
||||
"07f4acdef99b.ofalias.net:4565"
|
||||
],
|
||||
"ConnectLineTable": [
|
||||
"home-ipv6.sliveridc1.cn:4565",
|
||||
"home-ltipv6.sliveridc1.cn:4565",
|
||||
"cn-gd-gz.sliveridc1.cn:4565"
|
||||
],
|
||||
"ntpServerTable": [
|
||||
"{UDP}ntp1.aliyun.com:123",
|
||||
"{UDP}ntp2.aliyun.com:123",
|
||||
"{UDP}ntp3.aliyun.com:123",
|
||||
"{UDP}ntp4.aliyun.com:123",
|
||||
"{UDP}ntp5.aliyun.com:123",
|
||||
"{UDP}ntp6.aliyun.com:123",
|
||||
"{UDP}ntp7.aliyun.com:123",
|
||||
"{UDP}ntp1.tencent.com:123",
|
||||
"{UDP}ntp2.tencent.com:123",
|
||||
"{UDP}ntp3.tencent.com:123",
|
||||
"{UDP}ntp4.tencent.com:123",
|
||||
"{UDP}ntp5.tencent.com:123",
|
||||
"{UDP}time.google.com:123",
|
||||
"{UDP}time.apple.com:123",
|
||||
"{UDP}pool.ntp.org:123",
|
||||
"{UDP}ntp.ntsc.ac.cn:123",
|
||||
"{UDP}us.ntp.org.cn:123"
|
||||
],
|
||||
"denyLineTableQuery": true,
|
||||
"denyLineTableBroadcast": true,
|
||||
"congestionAlgorithm": "BBR",
|
||||
"burstLimit": 1.5,
|
||||
"delayUpperBound": 1.3,
|
||||
"delayLowerBound": 1.3,
|
||||
"nagleDelayTime": 1000000,
|
||||
"linkNagleDelayTime": 0,
|
||||
"linkConnectionsCount": 1,
|
||||
"TUNName": "KLALB_SRv6",
|
||||
"NetworkInterfaceExcepts": [],
|
||||
"Type": "KLALBController"
|
||||
},
|
||||
{
|
||||
"Listen": "0.0.0.0:4572",
|
||||
"Bridge": {
|
||||
"KLALB": "SocketBridge",
|
||||
"RDP": "SocketBridge",
|
||||
"HTTP": "SocketBridge",
|
||||
"HTTPS": "SocketBridge",
|
||||
"DEFAULT": "MinecraftSocketBridge23332"
|
||||
},
|
||||
"Connect": {
|
||||
"KLALB": "127.0.0.1:4565",
|
||||
"RDP": "127.0.0.1:3389",
|
||||
"HTTP": "127.0.0.1:5212",
|
||||
"HTTPS": "192.168.1.235:443",
|
||||
"DEFAULT": "127.0.0.1:36555"
|
||||
},
|
||||
"Type": "SocketBridge"
|
||||
},
|
||||
{
|
||||
"Listen": "{KLALB_Stream}[::0]:23332",
|
||||
"Bridge": {
|
||||
"DEFAULT": "MinecraftSocketBridge23332"
|
||||
},
|
||||
"Connect": {
|
||||
"DEFAULT": "127.0.0.1:36555"
|
||||
},
|
||||
"Type": "SocketBridge"
|
||||
},
|
||||
{
|
||||
"Listen": "{KLALB_Stream}[::0]:23333",
|
||||
"Bridge": {
|
||||
"DEFAULT": "SocketBridge"
|
||||
},
|
||||
"Connect": {
|
||||
"DEFAULT": "127.0.0.1:5212"
|
||||
},
|
||||
"Type": "SocketBridge"
|
||||
},
|
||||
{
|
||||
"Listen": "{KLALB_Stream}[::0]:25565",
|
||||
"Bridge": {
|
||||
"DEFAULT": "SocketBridge"
|
||||
},
|
||||
"Connect": {
|
||||
"DEFAULT": "127.0.0.1:25566"
|
||||
},
|
||||
"Type": "SocketBridge"
|
||||
},
|
||||
{
|
||||
"Listen": "0.0.0.0:25561",
|
||||
"Bridge": {
|
||||
"KLALB": "SocketBridge",
|
||||
"DEFAULT": "MinecraftSocketBridge23330"
|
||||
},
|
||||
"Connect": {
|
||||
"KLALB": "127.0.0.1:4565",
|
||||
"DEFAULT": "127.0.0.1:25562"
|
||||
},
|
||||
"Type": "SocketBridge"
|
||||
},
|
||||
{
|
||||
"Listen": "{KLALB_Stream}[::0]:23330",
|
||||
"Bridge": {
|
||||
"DEFAULT": "MinecraftSocketBridge23330"
|
||||
},
|
||||
"Connect": {
|
||||
"DEFAULT": "127.0.0.1:25562"
|
||||
},
|
||||
"Type": "SocketBridge"
|
||||
}
|
||||
]
|
||||
@@ -1,3 +0,0 @@
|
||||
#Tue Jul 25 19:03:09 CST 2023
|
||||
local=0.0.0.0\:35000
|
||||
server=127.0.0.1\:4569
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
[
|
||||
{"Type":"KLALBController" ,
|
||||
"TCPListen" : "0.0.0.0:4565",
|
||||
"UDPListen" : "{UDP}0.0.0.0:4572",
|
||||
"VirtualSocketName" : "KLALB_Stream",
|
||||
"LineTable":["43.248.189.107:65529",
|
||||
"cn-bj-bgp-3.openfrp.top:65529",
|
||||
"180.76.147.250:65529",
|
||||
"cn-ah-dx-1.natfrp.cloud:65529",
|
||||
"cn-nn-dx-1.natfrp.cloud:65529",
|
||||
"cn-wh-dx-1.natfrp.cloud:65529",
|
||||
"cn-zz-bgp-10.natfrp.cloud:23330",
|
||||
"cn-zz-bgp-7.natfrp.cloud:33336",
|
||||
"43.143.109.64:49965",
|
||||
"frp.104300.xyz:49965",
|
||||
"us.afrps.cn:49966",
|
||||
"hk.afrps.cn:49966",
|
||||
"la.afrps.cn:49966",
|
||||
"frp.freefrp.net:49965",
|
||||
"frp1.freefrp.net:49965",
|
||||
"frp2.freefrp.net:49965",
|
||||
"frp4.freefrp.net:49965",
|
||||
"cn-he-plc-2.openfrp.top:4572",
|
||||
"{UDP}cn-he-plc-2.openfrp.top:4572",
|
||||
"frp-mom.top:22226",
|
||||
"frp-man.top:36555",
|
||||
"us-sjc-bgp-2.openfrp.top:36555",
|
||||
"us-sjc-bgp-1.openfrp.top:36555",
|
||||
"[240e:340:d856:b700:6d02:6a6a:f9fc:865b]:4572"]
|
||||
},
|
||||
{"Type":"SocketBridge" ,
|
||||
"Listen" : "0.0.0.0:4572",
|
||||
"Bridge":{
|
||||
"KLALB" : "SocketBridge",
|
||||
"RDP":"SocketBridge",
|
||||
"HTTP":"SocketBridge",
|
||||
"HTTPS":"SocketBridge",
|
||||
"DEFAULT":"MinecraftSocketBridge23332"
|
||||
} ,
|
||||
"Connect" : {
|
||||
"KLALB" : "127.0.0.1:4565",
|
||||
"RDP":"127.0.0.1:3389",
|
||||
"HTTP":"127.0.0.1:5212",
|
||||
"HTTPS":"192.168.1.235:443",
|
||||
"DEFAULT":"127.0.0.1:36555"
|
||||
}
|
||||
},
|
||||
{"Type":"SocketBridge" ,
|
||||
"Listen" : "{KLALB_Stream}[::0]:23332",
|
||||
"Bridge":"MinecraftSocketBridge23332",
|
||||
"Connect" : "127.0.0.1:36555"
|
||||
},
|
||||
{ "Type":"SocketBridge" ,
|
||||
"Listen" : "{KLALB_Stream}[::0]:23333",
|
||||
"Bridge":"SocketBridge",
|
||||
"Connect" : "127.0.0.1:5212"
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{"Type":"SocketBridge" ,
|
||||
"Listen" : "0.0.0.0:25561",
|
||||
"Bridge":{
|
||||
"KLALB" : "SocketBridge",
|
||||
"DEFAULT":"MinecraftSocketBridge23330"
|
||||
} ,
|
||||
"Connect" : {
|
||||
"KLALB" : "127.0.0.1:4565",
|
||||
"DEFAULT":"127.0.0.1:25562"
|
||||
}
|
||||
},
|
||||
{"Type":"SocketBridge" ,
|
||||
"Listen" : "{KLALB_Stream}[::0]:23330",
|
||||
"Bridge":"MinecraftSocketBridge23330",
|
||||
"Connect" : "127.0.0.1:25562"
|
||||
}
|
||||
]
|
||||
@@ -1,3 +0,0 @@
|
||||
virtualip=67c:72ce:765e:4db1:a02e:92fa:1959:29eb
|
||||
bind=0.0.0.0:4569
|
||||
local=127.0.0.1:36555
|
||||
@@ -1,2 +0,0 @@
|
||||
{UDP}192.168.1.233:4569
|
||||
{UDP}192.168.0.233:4569
|
||||
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,107 @@
|
||||
srv6acc=SRv6 network accelerator system
|
||||
networkgraph=Network graph
|
||||
language=Language
|
||||
basicsettings=Basic settings
|
||||
ipv6addr=IPv6 address
|
||||
dnsserver=DNS server
|
||||
asnumber=AS number
|
||||
tcplistening=TCP listening
|
||||
udplistening=UDP listening
|
||||
openlinetable=Open line table
|
||||
autoconnectlinetable=Auto connect line table
|
||||
advancedsettings=Advanced settings
|
||||
congresscontrolalgorithm=Congress control algorithm
|
||||
savesettings=Save settings
|
||||
locate=Locate
|
||||
find=Find
|
||||
home=Home
|
||||
uploadspeed=Upload speed
|
||||
downloadspeed=Download speed
|
||||
uploadpps=Upload PPS
|
||||
downloadpps=Download PPS
|
||||
uploaddelay=Upload delay
|
||||
downloaddelay=Download delay
|
||||
copy=Copy
|
||||
onlinedevices=Online devices
|
||||
monitor=Monitor
|
||||
showofflines=Show offline remotelines
|
||||
lineaddressport=Line address:port
|
||||
addline=Add line
|
||||
reconnectall=Reconnect All
|
||||
remotelines=Remote lines
|
||||
settings=Settings
|
||||
saveconfigsuccess=Save config success
|
||||
warning=Warning
|
||||
invaildipv6addr=IPv6 address:Invaild Input
|
||||
invailddnsserver=DNS server:Invaild Input
|
||||
invaildasnumber=AS number:Invaild Input
|
||||
invaildtcplisten=TCP listen:Invaild Input
|
||||
invaildudplisten=UDP listen:Invaild Input
|
||||
invaildopenlinetable=Open line table:Invaild Input
|
||||
invaildconnectlinetable=Connect line table:Invaild Input
|
||||
invaildntpservertable=NTP server addresses:Invaild Input
|
||||
unknown=Unknown
|
||||
viewlinemonitor=View line monitor
|
||||
copylineaddress=Copy line address
|
||||
copyvirtualaddress=Copy virtual address
|
||||
tryreconnect=Try reconnect
|
||||
forcedisconnect=Force disconnect
|
||||
removeline=Remove line
|
||||
time=Time
|
||||
speermonitor=Speed monitor
|
||||
delaymonitor=Delay monitor
|
||||
speed=Speed
|
||||
delay=Delay
|
||||
virtualnetsettings=Virtual network settings
|
||||
tunnelnetsettings=Tunnel network settings
|
||||
linksettings=Link settings
|
||||
klalbperf=KLALB-perf Speedtest
|
||||
speedtest=Network speed test
|
||||
starttest=Start test
|
||||
testreport=Test report
|
||||
invaildinput=Invaild input
|
||||
stoptest=Stop test
|
||||
bandwidth=Bandwidth
|
||||
nodeinf=Node information
|
||||
selectinterface=Select network interface
|
||||
add=Add
|
||||
edit=Edit
|
||||
remove=Remove
|
||||
networkinterfaceexcept=Network interface except
|
||||
cancel=Cancel
|
||||
ok=Ok
|
||||
currenttime=Current time
|
||||
timesyncsettings=Time sync settings
|
||||
ntpservers=NTP server addresses
|
||||
nodeinfo=Node information
|
||||
basicinfo=Basic info
|
||||
overview=Overview
|
||||
timerange=Time range
|
||||
error=Error
|
||||
securitysettings=Security settings
|
||||
delayupperbound=Delay upper bound
|
||||
delaylowerbound=Delay lower bound
|
||||
denyaddrquery=Deny address query
|
||||
denyaddrbroadcast=Deny address broadcast
|
||||
random=Random
|
||||
transmitnagledelaytime=Transmit nagle delay time
|
||||
linknagledelaytime=Link nagle delay time
|
||||
linkconnectionscount=Link connections count
|
||||
tunname=Virtual network device name
|
||||
dashboard=Dashboard
|
||||
backplanedelay=Backplane delay
|
||||
backplanepps=Backplane PPS
|
||||
backplaneecnrate=Backplane ECN rate
|
||||
backplanelossrate=Backplane Loss rate
|
||||
uisettings=UI settings
|
||||
nogui=No GUI mode
|
||||
bufferusagemonitor=Buffer usage monitor
|
||||
buffer=Buffer
|
||||
usedbuffer=Used buffer
|
||||
maxbuffer=Max buffer
|
||||
queueused=Used queue
|
||||
downloadbasedelay=Download Base
|
||||
uploadbasedelay=Upload Base
|
||||
burstlimit=Burst limit
|
||||
performancesettings=Performance settings
|
||||
performancestrategy=Performance strategy
|
||||
@@ -0,0 +1,107 @@
|
||||
srv6acc=SRv6 网络加速系统
|
||||
networkgraph=网络拓扑图
|
||||
language=语言
|
||||
basicsettings=基本设置
|
||||
ipv6addr=IPv6地址
|
||||
dnsserver=DNS服务器
|
||||
asnumber=AS号码
|
||||
tcplistening=TCP监听端口
|
||||
udplistening=UDP监听端口
|
||||
openlinetable=开放线路列表
|
||||
autoconnectlinetable=自动连接线路列表
|
||||
advancedsettings=高级设置
|
||||
congresscontrolalgorithm=拥塞控制算法
|
||||
savesettings=保存设置
|
||||
locate=定位
|
||||
find=查找
|
||||
home=本机
|
||||
uploadspeed=上传速度
|
||||
downloadspeed=下载速度
|
||||
uploadpps=上传包转发率
|
||||
downloadpps=下载包转发率
|
||||
uploaddelay=上传延迟
|
||||
downloaddelay=下载延迟
|
||||
copy=复制
|
||||
onlinedevices=在线设备
|
||||
monitor=监视器
|
||||
showofflines=显示离线远程链路
|
||||
lineaddressport=链路地址:端口
|
||||
addline=添加链路
|
||||
reconnectall=全部重连
|
||||
remotelines=远程链路
|
||||
settings=设置
|
||||
saveconfigsuccess=保存配置成功
|
||||
warning=警告
|
||||
invaildipv6addr=IPv6地址:非法输入
|
||||
invailddnsserver=DNS服务器:非法输入
|
||||
invaildasnumber=AS号码:非法输入
|
||||
invaildtcplisten=TCP监听端口:非法输入
|
||||
invaildudplisten=UDP监听端口:非法输入
|
||||
invaildopenlinetable=开放线路列表:非法输入
|
||||
invaildconnectlinetable=自动连接线路列表:非法输入
|
||||
invaildntpservertable==NTP授时服务器地址:非法输入
|
||||
unknown=未知
|
||||
viewlinemonitor=打开链路监视器
|
||||
copylineaddress=复制链路地址
|
||||
copyvirtualaddress=复制虚拟地址
|
||||
tryreconnect=立即尝试重连
|
||||
forcedisconnect=强制断开连接
|
||||
removeline=强制断开连接并移除
|
||||
time=时间
|
||||
speermonitor=速度监视器
|
||||
delaymonitor=延迟监视器
|
||||
speed=速度
|
||||
delay=延迟
|
||||
virtualnetsettings=虚拟网络设置
|
||||
tunnelnetsettings=隧道网络设置
|
||||
linksettings=链路设置
|
||||
klalbperf=KLALB-perf网速测试
|
||||
speedtest=网速测试
|
||||
starttest=开始测试
|
||||
testreport=测速报告
|
||||
invaildinput=非法输入
|
||||
stoptest=停止测试
|
||||
bandwidth=带宽
|
||||
nodeinf=节点信息
|
||||
selectinterface=选择网卡
|
||||
add=添加
|
||||
edit=编辑
|
||||
remove=移除
|
||||
networkinterfaceexcept=网卡排除列表
|
||||
cancel=取消
|
||||
ok=确定
|
||||
currenttime=当前时间
|
||||
timesyncsettings=时钟同步设置
|
||||
ntpservers=NTP授时服务器地址
|
||||
nodeinfo=节点信息
|
||||
basicinfo=基本信息
|
||||
overview=概览
|
||||
timerange=时间范围
|
||||
error=错误
|
||||
securitysettings=安全设置
|
||||
delayupperbound=网络时延上限
|
||||
delaylowerbound=网络时延下限
|
||||
denyaddrquery=禁用IP地址查询
|
||||
denyaddrbroadcast=禁用IP地址广播
|
||||
random=随机
|
||||
transmitnagledelaytime=传输粘包等待时间
|
||||
linknagledelaytime=链路粘包等待时间
|
||||
linkconnectionscount=链路连接数
|
||||
tunname=虚拟网卡名称
|
||||
dashboard=仪表盘
|
||||
backplanedelay=背板处理延迟
|
||||
backplanepps=背板包转发率
|
||||
backplaneecnrate=背板ECN率
|
||||
backplanelossrate=背板丢包率
|
||||
uisettings=UI设置
|
||||
nogui=无GUI模式
|
||||
bufferusagemonitor=缓冲区监视器
|
||||
buffer=缓冲区
|
||||
usedbuffer=已用缓冲区
|
||||
maxbuffer=最大缓冲区
|
||||
queueused=已用队列
|
||||
downloadbasedelay=下载延迟基线
|
||||
uploadbasedelay=上传延迟基线
|
||||
burstlimit=突发限制
|
||||
performancesettings=性能设置
|
||||
performancestrategy=性能策略
|
||||
@@ -0,0 +1,75 @@
|
||||
package org.kne.cloud.clock;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class AdjustedNanoClock {
|
||||
private ReentrantLock lock=new ReentrantLock();
|
||||
|
||||
|
||||
public ReentrantLock getLock() {
|
||||
return lock;
|
||||
}
|
||||
|
||||
|
||||
private volatile long delta=0;
|
||||
private volatile long accuracy=Long.MAX_VALUE;
|
||||
private boolean unsetted=true;
|
||||
public long getCurrentTime() {
|
||||
return System.nanoTime()+delta;
|
||||
}
|
||||
public AdjustedNanoClock(long delta) {
|
||||
super();
|
||||
this.delta = delta;
|
||||
}
|
||||
public AdjustedNanoClock() {
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AdjustedNanoClock [delta=" + delta + ", accuracy=" + accuracy + "]";
|
||||
}
|
||||
public long getDelta() {
|
||||
return delta;
|
||||
}
|
||||
public void setDelta(long delta) {
|
||||
this.delta = delta;
|
||||
}
|
||||
public void setCurrentTime(long curr) {
|
||||
delta=curr-System.nanoTime();
|
||||
}
|
||||
public void setCurrentTime2(long curr) {
|
||||
if(unsetted) {
|
||||
unsetted=false;
|
||||
delta=curr-System.nanoTime();
|
||||
}else {
|
||||
delta=(delta*9+ curr-System.nanoTime())/10;
|
||||
}
|
||||
}
|
||||
public long getAccuracy() {
|
||||
return accuracy;
|
||||
}
|
||||
public void calibrate(long delta,long taccurace) {
|
||||
if(accuracy==Long.MAX_VALUE||taccurace<= accuracy) {
|
||||
accuracy=taccurace;
|
||||
unsetted=false;
|
||||
this.delta=delta;
|
||||
//System.out.println(delta+" "+currentTime+" "+taccurace);
|
||||
}else {
|
||||
accuracy=(accuracy*9999+taccurace)/10000;
|
||||
}
|
||||
}
|
||||
public void calibrate2(long delta,long taccurace) {
|
||||
if(accuracy==Long.MAX_VALUE||taccurace<= accuracy) {
|
||||
accuracy=taccurace;
|
||||
if(unsetted) {
|
||||
unsetted=false;
|
||||
this.delta=delta;
|
||||
}else {
|
||||
this.delta=(this.delta*9+delta)/10;
|
||||
}
|
||||
//System.out.println(delta+" "+currentTime+" "+taccurace);
|
||||
}else {
|
||||
accuracy=(accuracy*9999+taccurace)/10000;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.kne.cloud.clock;
|
||||
|
||||
public class ExponentialBackoffTimeClock {
|
||||
|
||||
private volatile long coolingTime=5000000000L;
|
||||
|
||||
{
|
||||
resetCoolingTime();
|
||||
}
|
||||
public volatile long minCoolingTime=5000000000L,maxCoolingTime=300000000000L;
|
||||
public ExponentialBackoffTimeClock(long minCoolingTime, long maxCoolingTime) {
|
||||
super();
|
||||
this.minCoolingTime = minCoolingTime;
|
||||
this.maxCoolingTime = maxCoolingTime;
|
||||
}
|
||||
public ExponentialBackoffTimeClock() {
|
||||
super();
|
||||
}
|
||||
public long getCoolingTime() {
|
||||
return coolingTime;
|
||||
}
|
||||
public void incCoolingTime() {
|
||||
coolingTime<<=1;
|
||||
if(coolingTime>maxCoolingTime) {
|
||||
coolingTime=maxCoolingTime;
|
||||
}
|
||||
}
|
||||
public void resetCoolingTime() {
|
||||
coolingTime=minCoolingTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
package org.kne.cloud.clock;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.kne.math.Long128;
|
||||
|
||||
public class HighAccuracyClock {
|
||||
|
||||
|
||||
private final long initialCPUNanoTime;
|
||||
private final Long128 initialSystemNanoTime;
|
||||
private volatile long baseCPUNanoTime;
|
||||
private volatile Long128 baseSystemNanoTime;
|
||||
|
||||
private volatile long frequency=1000000000;//1000015000
|
||||
private volatile long frequency2=frequency*0xffffffffL/1000000000L;
|
||||
|
||||
private ReentrantLock lock=new ReentrantLock();
|
||||
|
||||
private static final Long128 NANOS_PER_MILLIS = Long128.valueOf(TimeUnit.MILLISECONDS.toNanos(1));
|
||||
|
||||
|
||||
private static final Long128 NANOS_PER_SECONDS = Long128.valueOf(TimeUnit.SECONDS.toNanos(1));
|
||||
public static final HighAccuracyClock SYSTEM_CLOCK = new HighAccuracyClock();
|
||||
|
||||
|
||||
public HighAccuracyClock() {
|
||||
this.initialSystemNanoTime =Long128.valueOf( System.currentTimeMillis() ).multiply(NANOS_PER_MILLIS);
|
||||
this.initialCPUNanoTime = System.nanoTime();
|
||||
this.baseSystemNanoTime=initialSystemNanoTime;
|
||||
this.baseCPUNanoTime=initialCPUNanoTime;
|
||||
}
|
||||
|
||||
public long getFrequency() {
|
||||
return frequency;
|
||||
}
|
||||
|
||||
public void setFrequency(long frequency) {
|
||||
lock.lock();
|
||||
try {
|
||||
long curr=System.nanoTime();
|
||||
long nanoela=curr-baseCPUNanoTime;
|
||||
baseCPUNanoTime=curr;
|
||||
baseSystemNanoTime=baseSystemNanoTime.add( Long128.valueOf(nanoela).multiply(this.frequency).divide(NANOS_PER_SECONDS));
|
||||
this.frequency = frequency;
|
||||
this.frequency2=frequency*0xffffffffL/1000000000L;
|
||||
}finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void adjustFrequency(long fdelta) {
|
||||
lock.lock();
|
||||
try {
|
||||
compact();
|
||||
this.frequency = frequency+fdelta;
|
||||
this.frequency2=frequency*0xffffffffL/1000000000L;
|
||||
}finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void compact() {
|
||||
lock.lock();
|
||||
try {
|
||||
long curr=System.nanoTime();
|
||||
long nanoela=curr-baseCPUNanoTime;
|
||||
baseCPUNanoTime=curr;
|
||||
baseSystemNanoTime=baseSystemNanoTime.add(Long128.valueOf(nanoela).multiply(this.frequency).divide(NANOS_PER_SECONDS));
|
||||
}finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取从1970-01-01开始的当前时间(纳秒精度)
|
||||
*/
|
||||
public Long128 getCurrentTimeNanos() {
|
||||
Long128 mul=Long128.valueOf(System.nanoTime()-baseCPUNanoTime).multiply(frequency2);
|
||||
return mul.shiftRight(32).add(baseSystemNanoTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取从1970-01-01开始的当前时间(毫秒精度)
|
||||
*/
|
||||
public long getCurrentTimeMillis() {
|
||||
return getCurrentTimeNanos().divide(NANOS_PER_MILLIS).longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 NTPv4 128 位时间戳
|
||||
*/
|
||||
public Long128 getCurrentTimeNTP128() {
|
||||
return NTPTimestamps.nanosToNtp128BitTimestamp(getCurrentTimeNanos());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 NTPv4 64 位时间戳
|
||||
*/
|
||||
public Long128 getCurrentTimeNTP64() {
|
||||
return NTPTimestamps.ntp128To64(getCurrentTimeNTP128());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取时钟创建以来经过的时间(纳秒)
|
||||
*/
|
||||
public long getElapsedNanos() {
|
||||
return System.nanoTime() - initialCPUNanoTime;
|
||||
}
|
||||
|
||||
// ================== 修复的时间同步方法 ==================
|
||||
|
||||
/**
|
||||
* 强制同步到指定时间(正确版本)
|
||||
* @param targetNanos 目标时间(从1970年开始的纳秒数)
|
||||
*/
|
||||
public void syncToTime(Long128 targetNanos) {
|
||||
lock.lock();
|
||||
try {
|
||||
baseCPUNanoTime= System.nanoTime();
|
||||
baseSystemNanoTime=targetNanos;
|
||||
}finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于参考时钟进行同步(更安全的方法)
|
||||
* @param referenceClock 参考时钟
|
||||
*/
|
||||
public void syncToClock(HighAccuracyClock referenceClock) {
|
||||
syncToClock(referenceClock,BigInteger.ZERO);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 基于参考时钟进行同步(更安全的方法)
|
||||
* @param referenceClock 参考时钟
|
||||
* @param delta 网络延迟(纳秒),可选
|
||||
*/
|
||||
public void syncToClock(HighAccuracyClock referenceClock, BigInteger delta) {
|
||||
if (delta == null) {
|
||||
delta = BigInteger.ZERO;
|
||||
}
|
||||
lock.lock();
|
||||
try {
|
||||
baseCPUNanoTime=System.nanoTime();
|
||||
baseSystemNanoTime=referenceClock.getCurrentTimeNanos();
|
||||
}finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于NTP时间戳同步
|
||||
* @param ntp128Timestamp NTP 128位时间戳
|
||||
*/
|
||||
public void syncToNTPTime(Long128 ntp128Timestamp) {
|
||||
Long128 targetNanos = NTPTimestamps.ntp128BitToNanosTimestamp(ntp128Timestamp);
|
||||
syncToTime(targetNanos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 调整时钟(用于时间同步)
|
||||
* @param delta 要调整的纳秒数(正数调快,负数调慢)
|
||||
*/
|
||||
public void adjustClock(Long128 delta) {
|
||||
lock.lock();
|
||||
try {
|
||||
baseSystemNanoTime = baseSystemNanoTime.add(delta);
|
||||
}finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调整时钟(用于时间同步)
|
||||
* @param delta 要调整的纳秒数(正数调快,负数调慢)
|
||||
*/
|
||||
public void adjustClock(Long128 delta, double adjPercent) {
|
||||
BigInteger adjustment=new BigDecimal(delta.toBigInteger()).multiply(BigDecimal.valueOf( adjPercent)).toBigInteger();
|
||||
lock.lock();
|
||||
try {
|
||||
baseSystemNanoTime = baseSystemNanoTime.add(Long128 .valueOf(adjustment));
|
||||
}finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取时钟偏差(当前时间与真实时间的差异)
|
||||
*/
|
||||
public Long128 getClockError(Long128 referenceTime) {
|
||||
return getCurrentTimeNanos().subtract(referenceTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查时钟是否同步(误差在允许范围内)
|
||||
*/
|
||||
public boolean isSynchronized(Long128 referenceTime, Long128 tolerance) {
|
||||
Long128 error = getClockError(referenceTime).abs();
|
||||
return error.compareTo(tolerance) <= 0;
|
||||
}
|
||||
|
||||
|
||||
// ================== toString 方法 ==================
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 转换为详细格式的字符串(包含纳秒)
|
||||
*/
|
||||
public String toString() {
|
||||
Long128 nanos = getCurrentTimeNanos();
|
||||
return NTPTimestamps.nanosSince1970ToString(nanos);
|
||||
}
|
||||
|
||||
public String toString2() {
|
||||
Long128 nanos = getCurrentTimeNanos();
|
||||
return NTPTimestamps.nanosSince1970ToString2(nanos);
|
||||
}
|
||||
|
||||
public long getInitialCPUNanoTime() {
|
||||
return initialCPUNanoTime;
|
||||
}
|
||||
|
||||
public Long128 getInitialSystemNanoTime() {
|
||||
return initialSystemNanoTime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
HighAccuracyClock hac=new HighAccuracyClock();
|
||||
while(true) {
|
||||
System.out.println(hac.getCurrentTimeNanos());
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
package org.kne.cloud.clock;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import org.kne.math.Long128;
|
||||
|
||||
public class NTPTimestamps {
|
||||
|
||||
// 常量定义
|
||||
public static final Long128 NANOS_PER_SECOND = Long128.valueOf(1_000_000_000L);
|
||||
public static final Long128 NANOS_PER_MILLIS = Long128.valueOf(1_000_000L);
|
||||
|
||||
// NTP 纪元 (1900) 和 Unix 纪元 (1970) 之间的纳秒差
|
||||
public static final Long128 NTP_EPOCH_OFFSET_NS = Long128.valueOf(2208988800L)
|
||||
.multiply(NANOS_PER_SECOND);
|
||||
|
||||
// 2^64 值,用于单位转换
|
||||
public static final Long128 TWO_POW_64 = Long128.ONE.shiftLeft(64);
|
||||
|
||||
// 2^32 值,用于 64 位时间戳处理
|
||||
public static final Long128 TWO_POW_32 = Long128.ONE.shiftLeft(32);
|
||||
|
||||
// 掩码常量
|
||||
public static final Long128 MASK_32_BIT = new Long128(0xFFFFFFFF);
|
||||
public static final Long128 MASK_64_BIT = new Long128(0xFFFFFFFFFFFFFFFFL);
|
||||
|
||||
// ================== 核心转换方法 ==================
|
||||
// 2^32 秒,约 136.192 年,一个 NTP 纪元的长度
|
||||
public static final Long128 SECONDS_PER_ERA = Long128.valueOf(0x100000000L);
|
||||
private static final Long128 TWO_POW_N64_PER_NANOS = Long128.valueOf("1208925819614629");
|
||||
|
||||
public static Long128 inferNtp64To128(long remote64Bit,Long128 local128Bit ) {
|
||||
return inferNtp64To128(toUnsignedLong128(remote64Bit),local128Bit);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据本地 128 位时间戳和网络 64 位时间戳,推断并补全纪元信息
|
||||
*
|
||||
* @param remote64Bit 从网络接收的 64 位 NTP 时间戳
|
||||
* @param local128Bit 本地已知的 128 位 NTP 时间戳
|
||||
* @return 推断出的完整 128 位 NTP 时间戳
|
||||
*/
|
||||
public static Long128 inferNtp64To128(Long128 remote64Bit,Long128 local128Bit ) {
|
||||
// 1. 从本地 128 位时间戳中提取纪元号和 64 位时间戳部分
|
||||
Long128 localEra = NTPTimestamps.getEraNumber(local128Bit);
|
||||
Long128 local64Bit = NTPTimestamps.getNtp64Timestamp(local128Bit);
|
||||
|
||||
// 3. 计算本地和远程 64 位时间戳的差异
|
||||
Long128 difference = remote64Bit.subtract(local64Bit);
|
||||
|
||||
// 4. 判断纪元关系并推断远程时间戳的纪元
|
||||
Long128 remoteEra;
|
||||
|
||||
// 如果差异很大(超过半个纪元),可能需要调整纪元
|
||||
Long128 halfEra = Long128.valueOf(Long.MAX_VALUE);
|
||||
|
||||
if (difference.compareTo(halfEra) > 0) {
|
||||
// 远程时间戳比本地小很多,可能属于上一个纪元
|
||||
remoteEra = localEra.subtract(Long128.ONE);
|
||||
} else if (difference.compareTo(halfEra.negate()) < 0) {
|
||||
// 远程时间戳比本地大很多,可能属于下一个纪元
|
||||
remoteEra = localEra.add(Long128.ONE);
|
||||
} else {
|
||||
// 差异不大,属于同一个纪元
|
||||
remoteEra = localEra;
|
||||
}
|
||||
|
||||
// 5. 组合纪元号和 64 位时间戳,得到完整的 128 位时间戳
|
||||
return NTPTimestamps.ntp64To128(remote64Bit, remoteEra);
|
||||
}
|
||||
/**
|
||||
* 将从1970年开始的纳秒数转换为 NTPv4 128 位时间戳
|
||||
* 128位时间戳表示从1900年1月1日起经过的 2⁻⁶⁴ 秒的数量
|
||||
*/
|
||||
public static Long128 nanosToNtp128BitTimestamp(Long128 nanosSince1970) {
|
||||
// 1. 计算从 1900 年开始的总纳秒数
|
||||
Long128 totalNanosFrom1900 = nanosSince1970.add(NTP_EPOCH_OFFSET_NS);
|
||||
|
||||
// 2. 将纳秒转换为 2⁻⁶⁴ 秒单位
|
||||
// return totalNanosFrom1900.multiply(TWO_POW_64).divide(NANOS_PER_SECOND);
|
||||
return totalNanosFrom1900.multiply(TWO_POW_N64_PER_NANOS).shiftRight(16);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 NTPv4 128 位时间戳转换回从1970年开始的纳秒数
|
||||
*/
|
||||
public static Long128 ntp128BitToNanosTimestamp(Long128 ntp128Timestamp) {
|
||||
// 1. 将 2⁻⁶⁴ 秒单位转换回纳秒
|
||||
Long128 totalNanosFrom1900 = ntp128Timestamp.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
|
||||
|
||||
// 2. 计算从 1970 年开始的总纳秒数
|
||||
return totalNanosFrom1900.subtract(NTP_EPOCH_OFFSET_NS);
|
||||
}
|
||||
|
||||
|
||||
public static Long128 nanosToNtp128BitTimeInterval(Long128 nanos) {
|
||||
// 2. 将纳秒转换为 2⁻⁶⁴ 秒单位
|
||||
return nanos.multiply(TWO_POW_64).divide(NANOS_PER_SECOND);
|
||||
}
|
||||
|
||||
|
||||
public static Long128 ntp128BitToNanosInterval(Long128 ntp128Timestamp) {
|
||||
// 1. 将 2⁻⁶⁴ 秒单位转换回纳秒
|
||||
Long128 totalNanosFrom1900 = ntp128Timestamp.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
|
||||
|
||||
return totalNanosFrom1900;
|
||||
}
|
||||
|
||||
|
||||
// ================== 128位 ↔ 64位 转换 ==================
|
||||
|
||||
/**
|
||||
* 将 NTP 128 位时间戳转换为 NTP 64 位时间戳
|
||||
* 64位时间戳就是128位时间戳的中间64位
|
||||
*/
|
||||
public static Long128 ntp128To64(Long128 ntp128Timestamp) {
|
||||
return ntp128Timestamp.shiftRight(32).and(MASK_64_BIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 NTP 64 位时间戳转换为 NTP 128 位时间戳
|
||||
* 64位时间戳放在128位时间戳的中间64位,高32位Era和低32位分数为0
|
||||
*/
|
||||
public static Long128 ntp64To128(Long128 ntp64Timestamp) {
|
||||
return ntp64Timestamp.and(MASK_64_BIT).shiftLeft(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 NTP 64 位时间戳转换为 NTP 128 位时间戳(指定Era Number)
|
||||
*/
|
||||
public static Long128 ntp64To128(Long128 ntp64Timestamp, Long128 eraNumber) {
|
||||
return eraNumber.and(MASK_32_BIT).shiftLeft(96)
|
||||
.or(ntp64Timestamp.and(MASK_64_BIT).shiftLeft(32));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 NTP 128 位时间戳中提取 Era Number(高32位)
|
||||
*/
|
||||
public static Long128 getEraNumber(Long128 ntp128Timestamp) {
|
||||
return ntp128Timestamp.shiftRight(96).and(MASK_32_BIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 NTP 128 位时间戳中提取 64 位时间戳(中间64位)
|
||||
*/
|
||||
public static Long128 getNtp64Timestamp(Long128 ntp128Timestamp) {
|
||||
return ntp128Timestamp.shiftRight(32).and(MASK_64_BIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 NTP 128 位时间戳中提取分数部分(低32位)
|
||||
*/
|
||||
public static Long128 getFraction(Long128 ntp128Timestamp) {
|
||||
return ntp128Timestamp.and(MASK_32_BIT);
|
||||
}
|
||||
|
||||
// ================== 工具方法 ==================
|
||||
|
||||
/**
|
||||
* 从毫秒和纳秒偏移构造 Long128 纳秒
|
||||
*/
|
||||
public static Long128 toNanosSince1970(long unixTimeMillis, long nanosOffset) {
|
||||
return Long128.valueOf(unixTimeMillis)
|
||||
.multiply( NANOS_PER_MILLIS)
|
||||
.add(Long128.valueOf(nanosOffset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 Long128 纳秒提取毫秒和纳秒偏移
|
||||
*/
|
||||
public static long[] toMillisAndNanos(Long128 nanosSince1970) {
|
||||
Long128[] millisAndNanos = nanosSince1970.divideAndRemainder( NANOS_PER_MILLIS);
|
||||
return new long[]{millisAndNanos[0].longValue(), millisAndNanos[1].longValue()};
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个 128 位时间戳之间的时间差(纳秒)
|
||||
*/
|
||||
public static Long128 calculateTimeDifference(Long128 timestamp1, Long128 timestamp2) {
|
||||
Long128 diff = timestamp2.subtract(timestamp1);
|
||||
return diff.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 将 64 位 NTP 时间戳分解为秒数和分数
|
||||
*/
|
||||
public static Long128[] parseNtp64Timestamp(Long128 ntp64Timestamp) {
|
||||
Long128 seconds = ntp64Timestamp.shiftRight(32).and(MASK_32_BIT);
|
||||
Long128 fraction = ntp64Timestamp.and(MASK_32_BIT);
|
||||
return new Long128[]{seconds, fraction};
|
||||
}
|
||||
|
||||
/**
|
||||
* 从秒数和分数构建 64 位 NTP 时间戳
|
||||
*/
|
||||
public static Long128 buildNtp64Timestamp(Long128 seconds, Long128 fraction) {
|
||||
return seconds.and(MASK_32_BIT).shiftLeft(32).or(fraction.and(MASK_32_BIT));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 日期时间格式化器
|
||||
private static final DateTimeFormatter DEFAULT_FORMATTER =
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
|
||||
private static final DateTimeFormatter DETAILED_FORMATTER =
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.n");
|
||||
public static String nanosSince1970ToString(Long128 nanos) {
|
||||
Long128 millis = nanos.divide(Long128.valueOf(1_000_000));
|
||||
Long128 nanosPart = nanos.mod(Long128.valueOf(1_000_000));
|
||||
|
||||
Instant instant = Instant.ofEpochMilli(millis.longValue());
|
||||
LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
|
||||
return String.format("%s.%06d",
|
||||
DEFAULT_FORMATTER.format(dateTime),
|
||||
nanosPart.longValue());
|
||||
}
|
||||
public static String nanosSince1970ToString2(Long128 nanos) {
|
||||
Long128 millis = nanos.divide(Long128.valueOf(1_000_000));
|
||||
|
||||
Instant instant = Instant.ofEpochMilli(millis.longValue());
|
||||
LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
|
||||
return DEFAULT_FORMATTER.format(dateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 128 位时间戳转换为可读字符串
|
||||
*/
|
||||
public static String ntp128ToString(Long128 ntp128Timestamp) {
|
||||
Long128 nanosSince1970 = ntp128BitToNanosTimestamp(ntp128Timestamp);
|
||||
return nanosSince1970ToString(nanosSince1970);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 64 位时间戳转换为可读字符串
|
||||
*/
|
||||
public static String ntp64ToString(Long128 ntp64Timestamp) {
|
||||
Long128 nanosSince1970 = ntp128BitToNanosTimestamp(ntp64To128( ntp64Timestamp));
|
||||
return nanosSince1970ToString(nanosSince1970);
|
||||
}
|
||||
|
||||
public static Long128 toUnsignedLong128(long unsignedLong) {
|
||||
if (unsignedLong >= 0) {
|
||||
return Long128.valueOf(unsignedLong);
|
||||
} else {
|
||||
// 对于负数,通过添加 2^64 来转换为无符号表示
|
||||
return Long128.valueOf(unsignedLong & 0x7FFFFFFFFFFFFFFFL)
|
||||
.setBit(63);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.kne.cloud.clock;
|
||||
|
||||
public class ReliabilityBackoffTimeClock {
|
||||
|
||||
public volatile long maxCoolingTime=300000000000L;
|
||||
public ReliabilityBackoffTimeClock(long maxCoolingTime) {
|
||||
super();
|
||||
this.maxCoolingTime = maxCoolingTime;
|
||||
}
|
||||
public ReliabilityBackoffTimeClock() {
|
||||
super();
|
||||
}
|
||||
public long getCoolingTime(double reliability) {
|
||||
return (long) ((1.0-reliability)*maxCoolingTime);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.kne.cloud.clock;
|
||||
|
||||
public class WatchDogTimer {
|
||||
private volatile long feedtime=System.nanoTime();
|
||||
private long timeout;
|
||||
public WatchDogTimer(long timeout) {
|
||||
super();
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public void feed() {
|
||||
feedtime=System.nanoTime();
|
||||
}
|
||||
|
||||
public boolean isBarking() {
|
||||
return(System.nanoTime()-feedtime)>timeout;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JTextField;
|
||||
import java.awt.BorderLayout;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import org.kne.cloud.network.klalb.ui.UIEnv;
|
||||
|
||||
public class ButtonSettingItem extends SettingItem {
|
||||
protected JButton button;
|
||||
|
||||
|
||||
public JButton getButton() {
|
||||
return button;
|
||||
}
|
||||
public ButtonSettingItem(String text,int w,int h) {
|
||||
this(text,UIEnv.getFont().deriveFont((float) 15.0),w,h);
|
||||
}
|
||||
/**
|
||||
* @wbp.parser.constructor
|
||||
*/
|
||||
public ButtonSettingItem(String text, Font deriveFont,int w,int h) {
|
||||
super(text,deriveFont,w,h);
|
||||
button = new JButton(UIEnv.getRsb().getString("clicktoopen")+">>");
|
||||
button.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
button.setFont(button.getFont().deriveFont(Map.of(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON)));
|
||||
getPanel().add(button, BorderLayout.EAST);
|
||||
button.setBorder(null);
|
||||
button.setOpaque(false);
|
||||
button.setBackground(new Color(0,0,0,0));
|
||||
label.setForeground(Color.GRAY);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import org.kne.cloud.klalb.uitool.SettingItem;
|
||||
import org.kne.cloud.network.klalb.ui.UIEnv;
|
||||
|
||||
public class CheckBoxSettingItem extends SettingItem {
|
||||
protected JCheckBox button;
|
||||
|
||||
|
||||
public JCheckBox getCheckBox() {
|
||||
return button;
|
||||
}
|
||||
public CheckBoxSettingItem(String text,int w,int h) {
|
||||
this(text,UIEnv.getFont().deriveFont((float) 15.0),w,h);
|
||||
}
|
||||
/**
|
||||
* @wbp.parser.constructor
|
||||
*/
|
||||
public CheckBoxSettingItem(String text, Font deriveFont,int w,int h) {
|
||||
super(text,deriveFont,w,h);
|
||||
button = new JCheckBox();
|
||||
button.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
getPanel().add(button, BorderLayout.CENTER);
|
||||
button.setBorder(null);
|
||||
button.setOpaque(false);
|
||||
button.setBackground(new Color(0,0,0,0));
|
||||
label.setForeground(Color.GRAY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import javax.swing.JTextField;
|
||||
import java.awt.BorderLayout;
|
||||
import javax.swing.SwingConstants;
|
||||
import org.kne.cloud.network.klalb.ui.UIEnv;
|
||||
import javax.swing.JComboBox;
|
||||
|
||||
public class ComboSettingItem extends SettingItem {
|
||||
|
||||
|
||||
private JComboBox comboBox;
|
||||
public JComboBox getComboBox() {
|
||||
return comboBox;
|
||||
}
|
||||
public ComboSettingItem(String text,int w,int h) {
|
||||
this(text,UIEnv.getFont().deriveFont((float) 15.0),w, h);
|
||||
}
|
||||
/**
|
||||
* @wbp.parser.constructor
|
||||
*/
|
||||
public ComboSettingItem(String text, Font deriveFont,int w,int h) {
|
||||
super(text,deriveFont,w,h);
|
||||
label.setForeground(Color.GRAY);
|
||||
|
||||
comboBox = new JComboBox();
|
||||
comboBox.setOpaque(false);
|
||||
getPanel().add(comboBox, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.TextArea;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Panel;
|
||||
import java.awt.Window;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import org.kne.cloud.network.klalb.ui.UIEnv;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import java.awt.Label;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.TextField;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Random;
|
||||
|
||||
public class CrashReport extends JDialog{
|
||||
private JLabel name;
|
||||
private TextField type;
|
||||
private JTextArea stack;
|
||||
public CrashReport(Window parent ,boolean modal) {
|
||||
super(parent);
|
||||
setModal(modal);
|
||||
setTitle("错误");
|
||||
setIconImage(UIEnv.getIcon());
|
||||
setSize(500, 400);
|
||||
setLocationRelativeTo(null);
|
||||
stack = new JTextArea();
|
||||
stack.setEditable(false);
|
||||
getContentPane().add(new JScrollPane(stack), BorderLayout.CENTER);
|
||||
|
||||
Panel panel = new Panel();
|
||||
panel.setPreferredSize(new Dimension(500, 100));
|
||||
getContentPane().add(panel, BorderLayout.NORTH);
|
||||
panel.setLayout(null);
|
||||
|
||||
JLabel lblNewLabel = new JLabel("");
|
||||
lblNewLabel.setIcon(new ImageIcon(CrashReport.class.getResource("/assets/error.jpg")));
|
||||
lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
lblNewLabel.setBounds(10, 10, 80, 80);
|
||||
panel.add(lblNewLabel);
|
||||
|
||||
name = new JLabel("");
|
||||
name.setFont(new Font("宋体", Font.PLAIN, 30));
|
||||
name.setForeground(Color.RED);
|
||||
name.setBounds(96, 10, 378, 33);
|
||||
panel.add(name);
|
||||
|
||||
type = new TextField();
|
||||
type.setEditable(false);
|
||||
type.setBounds(96, 67, 378, 23);
|
||||
panel.add(type);
|
||||
|
||||
fny = new JLabel("...?");
|
||||
fny.setFont(new Font("MS Song", Font.PLAIN, 10));
|
||||
getContentPane().add(fny, BorderLayout.SOUTH);
|
||||
}
|
||||
String []s=new String[]{"鎴戜滑鍥㈤槦鍙湁涓�涓▼搴忓憳",
|
||||
"鎯虫洿鏂帮紝娌¢棬",
|
||||
"鎴戜滑鐨勬湇鍔″櫒鐪熺殑鏄笓涓氣�滃埌瀹垛�濅簡",
|
||||
"杩炴帴宸蹭涪澶憋細涓嶅幓鍋氬惎鍔ㄥ櫒灏卞幓濂宠锛屼笉鍘诲コ瑁呭氨鍘诲仛鍚姩鍣�",
|
||||
"鍦熻眴鏈嶅姟鍣ㄥ張鍙戣娊浜�"
|
||||
};
|
||||
private JLabel fny;
|
||||
public void report(Throwable e,String t){
|
||||
e.printStackTrace();
|
||||
name.setText(t);
|
||||
type.setText(e.getClass().getName());
|
||||
StringWriter sw=new StringWriter();
|
||||
PrintWriter pw=new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
pw.close();
|
||||
stack.setText(sw.toString());fny.setText(s[new Random().nextInt(s.length)]);
|
||||
setVisible(true);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package org.knemcl.uitool;
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.plaf.*;
|
||||
@@ -0,0 +1,159 @@
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Image;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.IOException;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.ListModel;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import javax.swing.SwingConstants;
|
||||
import org.kne.cloud.network.klalb.ui.UIEnv;
|
||||
import java.awt.FlowLayout;
|
||||
|
||||
public abstract class ListSettingItem<T> extends SettingItem {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected JList<T> list;
|
||||
|
||||
private Consumer<T> storeRecall;
|
||||
public JList<T> getList() {
|
||||
return list;
|
||||
}
|
||||
public ListSettingItem(String text,int w,int h,XDefaultListModel<T>lm) {
|
||||
this(text,UIEnv.getFont().deriveFont((float) 15.0),w,h,lm);
|
||||
}
|
||||
/**
|
||||
* @wbp.parser.constructor
|
||||
*/
|
||||
public ListSettingItem(String text, Font deriveFont,int w,int h,XDefaultListModel<T> lm) {
|
||||
super(text,deriveFont,w,h);
|
||||
list = new JList<T>(lm);
|
||||
JScrollPane js=new JScrollPane(list);
|
||||
js.getViewport().setOpaque(false);
|
||||
js.setOpaque(false);
|
||||
js.setBackground(new Color(0,0,0,0));
|
||||
getPanel().add(js, BorderLayout.CENTER);
|
||||
list.setBorder(null);
|
||||
list.setOpaque(false);
|
||||
list.setBackground(new Color(0,0,0,0));
|
||||
label.setForeground(Color.GRAY);
|
||||
|
||||
Dimension dss=new Dimension(25,25);
|
||||
JButton jbt3x=new JButton();
|
||||
jbt3x.setToolTipText(UIEnv.getRsb().getString("add"));
|
||||
try {
|
||||
jbt3x.setIcon(new ImageIcon(ImageIO .read(ListSettingItem.class.getResourceAsStream("/assets/add.png")).getScaledInstance(dss.width-2, dss.height-2, Image.SCALE_SMOOTH)));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
jbt3x.setSize(dss);
|
||||
jbt3x.setPreferredSize(dss);
|
||||
jbt3x.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
List<T> x=createEmpty();
|
||||
if(x!=null&&!x.isEmpty())
|
||||
runEdit(x.get(0));
|
||||
}
|
||||
});
|
||||
JButton jbedit=new JButton();
|
||||
jbedit.setToolTipText(UIEnv.getRsb().getString("edit"));
|
||||
try {
|
||||
jbedit.setIcon(new ImageIcon(ImageIO .read(ListSettingItem.class.getResourceAsStream("/assets/edit-fill.png")).getScaledInstance(dss.width-2, dss.height-2, Image.SCALE_SMOOTH)));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
jbedit.setSize(dss);
|
||||
jbedit.setPreferredSize(dss);
|
||||
jbedit.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
T val=list.getSelectedValue();
|
||||
if(val!=null)
|
||||
runEdit(val);
|
||||
}
|
||||
});
|
||||
|
||||
JButton jbt4x=new JButton();
|
||||
jbt4x.setToolTipText(UIEnv.getRsb().getString("remove"));
|
||||
try {
|
||||
jbt4x.setIcon(new ImageIcon(ImageIO .read(ListSettingItem.class.getResourceAsStream("/assets/delete-bin-fill.png")).getScaledInstance(dss.width-2, dss.height-2, Image.SCALE_SMOOTH)));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
jbt4x.setSize(dss);
|
||||
jbt4x.setPreferredSize(dss);
|
||||
jbt4x.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int v=list.getSelectedIndex();
|
||||
if(v>=0) {
|
||||
lm.remove(v);
|
||||
if(storeRecall!=null)
|
||||
storeRecall.accept(list.getSelectedValue());
|
||||
}
|
||||
}
|
||||
});
|
||||
JPanel jp=new JPanel();
|
||||
jp.setPreferredSize(new Dimension(30, h));
|
||||
FlowLayout flowLayout = (FlowLayout) jp.getLayout();
|
||||
flowLayout.setAlignment(FlowLayout.TRAILING);
|
||||
jp.setOpaque(false);
|
||||
getPanel().add(jp,BorderLayout.EAST);
|
||||
jp.add(jbt3x);
|
||||
jp.add(jbedit);
|
||||
jp.add(jbt4x);
|
||||
}
|
||||
abstract protected void runEdit(T val) ;
|
||||
abstract protected List<T> createEmpty() ;
|
||||
public void doAdd(T v) {
|
||||
boolean b=true;
|
||||
for (int i = 0; i < list.getModel().getSize(); i++) {
|
||||
if(list.getModel().getElementAt(i)==v) {
|
||||
b=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(b)
|
||||
((XDefaultListModel<T>) list.getModel()).addElement(v);
|
||||
repaint();
|
||||
if(storeRecall!=null)
|
||||
storeRecall.accept(list.getSelectedValue());
|
||||
}
|
||||
public Consumer<T> getStoreRecall() {
|
||||
return storeRecall;
|
||||
}
|
||||
public void setStoreRecall(Consumer<T> storeRecall) {
|
||||
this.storeRecall = storeRecall;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import javax.swing.*;
|
||||
|
||||
import org.kne.cloud.network.klalb.ui.UIEnv;
|
||||
|
||||
public class PathInput extends JDialog {
|
||||
private JTextField textField;
|
||||
private boolean checkfile=true;
|
||||
private boolean isdir=false;
|
||||
protected JFileChooser jfc;
|
||||
private Consumer<File> al;
|
||||
public Consumer<File> getAl() {
|
||||
return al;
|
||||
}
|
||||
|
||||
public void setAl(Consumer<File> al) {
|
||||
this.al = al;
|
||||
}
|
||||
|
||||
public PathInput(Window d){
|
||||
super(d);
|
||||
setResizable(false);
|
||||
setModal(true);
|
||||
setSize(500, 110);
|
||||
setLocationRelativeTo(d);
|
||||
|
||||
setIconImage(UIEnv.getIcon());
|
||||
|
||||
textField = new JTextField();
|
||||
textField.setPreferredSize(new Dimension(400,80));
|
||||
textField.setFont(new Font("微软雅黑", Font.PLAIN, 12));
|
||||
getContentPane().add(textField, BorderLayout.CENTER);
|
||||
textField.setColumns(10);
|
||||
|
||||
JPanel panel = new JPanel();
|
||||
getContentPane().add(panel, BorderLayout.SOUTH);
|
||||
|
||||
JButton btnok = new JButton(UIEnv.getRsb().getString("ok"));
|
||||
UIEnv.defbut(btnok);
|
||||
panel.add(btnok);
|
||||
btnok.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
File x=new File(textField.getText());
|
||||
if(!checkfile){
|
||||
if(isdir){
|
||||
x.mkdirs();
|
||||
}else{
|
||||
try {
|
||||
x.createNewFile();
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
al.accept(x);
|
||||
setVisible(false);
|
||||
return;
|
||||
}
|
||||
if(x.exists()){
|
||||
al.accept(x);
|
||||
setVisible(false);
|
||||
}else{
|
||||
JOptionPane.showMessageDialog(PathInput.this, UIEnv.getRsb().getString("filenotexist"), UIEnv.getRsb().getString("error"), JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
});
|
||||
JButton btnNewButton_1 = new JButton(UIEnv.getRsb().getString("browse"));
|
||||
UIEnv.defbut(btnNewButton_1);
|
||||
panel.add(btnNewButton_1);
|
||||
btnNewButton_1.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if(jfc.showOpenDialog(PathInput.this)==jfc.APPROVE_OPTION){
|
||||
textField.setText(jfc.getSelectedFile().toString());
|
||||
}
|
||||
/*File f=choose.get();
|
||||
if(f!=null){
|
||||
textField.setText(f.toString());
|
||||
}*/
|
||||
}
|
||||
});
|
||||
JButton button = new JButton(UIEnv.getRsb().getString("cancel"));
|
||||
UIEnv.defbut(button);
|
||||
panel.add(button);
|
||||
button.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
setVisible(false);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
jfc=new JFileChooser();
|
||||
jfc.setMultiSelectionEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
public JTextField getTextField() {
|
||||
return textField;
|
||||
}
|
||||
|
||||
public JFileChooser getJfc() {
|
||||
return jfc;
|
||||
}
|
||||
|
||||
public boolean isCheckfile() {
|
||||
return checkfile;
|
||||
}
|
||||
public void setCheckfile(boolean checkfile) {
|
||||
this.checkfile = checkfile;
|
||||
}
|
||||
public boolean isIsdir() {
|
||||
return isdir;
|
||||
}
|
||||
public void setIsdir(boolean isdir) {
|
||||
this.isdir = isdir;
|
||||
if(isdir) {
|
||||
jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
}else {
|
||||
jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JRadioButton;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import org.kne.cloud.klalb.uitool.SettingItem;
|
||||
import org.kne.cloud.network.klalb.ui.UIEnv;
|
||||
|
||||
public class RadioButtonSettingItem extends SettingItem {
|
||||
protected JRadioButton button;
|
||||
|
||||
|
||||
public JRadioButton getRadioButton() {
|
||||
return button;
|
||||
}
|
||||
public RadioButtonSettingItem(String text,int w,int h) {
|
||||
this(text,UIEnv.getFont().deriveFont((float) 15.0),w,h);
|
||||
}
|
||||
/**
|
||||
* @wbp.parser.constructor
|
||||
*/
|
||||
public RadioButtonSettingItem(String text, Font deriveFont,int w,int h) {
|
||||
super(text,deriveFont,w,h);
|
||||
button = new JRadioButton();
|
||||
button.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
getPanel().add(button, BorderLayout.CENTER);
|
||||
button.setBorder(null);
|
||||
button.setOpaque(false);
|
||||
button.setBackground(new Color(0,0,0,0));
|
||||
label.setForeground(Color.GRAY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.border.LineBorder;
|
||||
|
||||
import org.kne.cloud.network.klalb.ui.UIEnv;
|
||||
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import javax.swing.SpringLayout;
|
||||
|
||||
public class SettingItem extends JPanel {
|
||||
protected JLabel label;
|
||||
private JPanel sub;
|
||||
|
||||
public JLabel getLabel() {
|
||||
return label;
|
||||
}
|
||||
public SettingItem(String text,int w,int h){
|
||||
this(text,UIEnv.getFont().deriveFont(15.0f),w,h);
|
||||
}
|
||||
public JPanel getPanel(){
|
||||
return sub;
|
||||
}
|
||||
/**
|
||||
* @wbp.parser.constructor
|
||||
*/
|
||||
public SettingItem(String text,Font f,int w,int h){
|
||||
setSize(w, h);
|
||||
setPreferredSize(new Dimension(w, h));
|
||||
setBackground(UIEnv.getHalfTransparentDefaultColor());
|
||||
SpringLayout springLayout = new SpringLayout();
|
||||
setLayout(springLayout);
|
||||
//setOpaque(false);
|
||||
sub = new JPanel();
|
||||
springLayout.putConstraint(SpringLayout.NORTH, sub, 0, SpringLayout.NORTH, this);
|
||||
springLayout.putConstraint(SpringLayout.WEST, sub, 20, SpringLayout.WEST, this);
|
||||
springLayout.putConstraint(SpringLayout.SOUTH, sub, 0, SpringLayout.SOUTH, this);
|
||||
springLayout.putConstraint(SpringLayout.EAST, sub, -20, SpringLayout.EAST, this);
|
||||
sub.setOpaque(false);
|
||||
add(sub);
|
||||
sub.setLayout(new BorderLayout(5, 0));
|
||||
label = new JLabel(text);
|
||||
label.setFont(f);
|
||||
sub.add(label, BorderLayout.WEST);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.JTextField;
|
||||
import java.awt.BorderLayout;
|
||||
import javax.swing.SwingConstants;
|
||||
import org.kne.cloud.network.klalb.ui.UIEnv;
|
||||
|
||||
public class SliderSettingItem extends SettingItem {
|
||||
protected JSlider slider;
|
||||
protected JLabel labelx;
|
||||
|
||||
public JLabel getLabelx() {
|
||||
return labelx;
|
||||
}
|
||||
public JSlider getSlider() {
|
||||
return slider;
|
||||
}
|
||||
public SliderSettingItem(String text,int w,int h) {
|
||||
this(text,UIEnv.getFont().deriveFont((float) 15.0),w,h);
|
||||
}
|
||||
/**
|
||||
* @wbp.parser.constructor
|
||||
*/
|
||||
public SliderSettingItem(String text, Font deriveFont,int w,int h) {
|
||||
super(text,deriveFont,w,h);
|
||||
BorderLayout borderLayout = (BorderLayout) getPanel().getLayout();
|
||||
slider = new JSlider();
|
||||
getPanel().add(slider, BorderLayout.CENTER);
|
||||
slider.setBorder(null);
|
||||
slider.setOpaque(false);
|
||||
slider.setBackground(new Color(0,0,0,0));
|
||||
label.setForeground(Color.GRAY);
|
||||
|
||||
labelx = new JLabel();
|
||||
getPanel().add(labelx, BorderLayout.EAST);
|
||||
labelx.setFont(labelx.getFont());
|
||||
labelx.setBorder(null);
|
||||
labelx.setOpaque(false);
|
||||
labelx.setBackground(new Color(0,0,0,0));
|
||||
labelx.setPreferredSize(new Dimension(40, h));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import java.awt.BorderLayout;
|
||||
import javax.swing.SwingConstants;
|
||||
import org.kne.cloud.network.klalb.ui.UIEnv;
|
||||
|
||||
public class TextAreaSettingItem extends SettingItem {
|
||||
protected JTextArea textarea;
|
||||
|
||||
|
||||
public JTextArea getTextArea() {
|
||||
return textarea;
|
||||
}
|
||||
public TextAreaSettingItem(String text,int w,int h) {
|
||||
this(text,UIEnv.getFont().deriveFont((float) 15.0),w,h);
|
||||
}
|
||||
/**
|
||||
* @wbp.parser.constructor
|
||||
*/
|
||||
public TextAreaSettingItem(String text, Font deriveFont,int w,int h) {
|
||||
super(text,deriveFont,w,h);
|
||||
textarea = new JTextArea();
|
||||
JScrollPane sp=new JScrollPane(textarea);
|
||||
sp.getViewport().setOpaque(false);
|
||||
sp.setOpaque(false);
|
||||
sp.setBackground(new Color(0,0,0,0));
|
||||
getPanel().add(sp, BorderLayout.CENTER);
|
||||
textarea.setBorder(null);
|
||||
textarea.setOpaque(false);
|
||||
textarea.setBackground(new Color(0,0,0,0));
|
||||
//textarea.setBackground(UIEnv.getDefaultcolor());
|
||||
label.setForeground(Color.GRAY);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JTextField;
|
||||
import java.awt.BorderLayout;
|
||||
import javax.swing.SwingConstants;
|
||||
import org.kne.cloud.network.klalb.ui.UIEnv;
|
||||
|
||||
public class TextButtonSettingItem extends SettingItem {
|
||||
protected JTextField textField;
|
||||
protected JButton button;
|
||||
|
||||
public JButton getButton() {
|
||||
return button;
|
||||
}
|
||||
public JTextField getTextField() {
|
||||
return textField;
|
||||
}
|
||||
public TextButtonSettingItem(String text,int w,int h) {
|
||||
this(text,UIEnv.getFont().deriveFont((float) 15.0),w,h);
|
||||
}
|
||||
/**
|
||||
* @wbp.parser.constructor
|
||||
*/
|
||||
public TextButtonSettingItem(String text, Font deriveFont,int w,int h) {
|
||||
super(text,deriveFont,w,h);
|
||||
BorderLayout borderLayout = (BorderLayout) getPanel().getLayout();
|
||||
textField = new JTextField();
|
||||
textField.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
getPanel().add(textField, BorderLayout.CENTER);
|
||||
textField.setColumns(10);
|
||||
textField.setBorder(null);
|
||||
textField.setOpaque(false);
|
||||
textField.setBackground(new Color(0,0,0,0));
|
||||
label.setForeground(Color.GRAY);
|
||||
|
||||
button = new JButton();
|
||||
getPanel().add(button, BorderLayout.EAST);
|
||||
button.setFont(button.getFont());
|
||||
//button.setBorder(null);
|
||||
//button.setOpaque(false);
|
||||
button.setBackground(new Color(0,0,0,0));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import javax.swing.JTextField;
|
||||
import java.awt.BorderLayout;
|
||||
import javax.swing.SwingConstants;
|
||||
import org.kne.cloud.network.klalb.ui.UIEnv;
|
||||
|
||||
public class TextSettingItem extends SettingItem {
|
||||
protected JTextField textField;
|
||||
|
||||
|
||||
public JTextField getTextField() {
|
||||
return textField;
|
||||
}
|
||||
public TextSettingItem(String text,int w,int h) {
|
||||
this(text,UIEnv.getFont().deriveFont((float) 15.0),w,h);
|
||||
}
|
||||
/**
|
||||
* @wbp.parser.constructor
|
||||
*/
|
||||
public TextSettingItem(String text, Font deriveFont,int w,int h) {
|
||||
super(text,deriveFont,w,h);
|
||||
textField = new JTextField();
|
||||
textField.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
getPanel().add(textField, BorderLayout.CENTER);
|
||||
textField.setColumns(10);
|
||||
textField.setBorder(null);
|
||||
textField.setOpaque(false);
|
||||
textField.setBackground(new Color(0,0,0,0));
|
||||
label.setForeground(Color.GRAY);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import javax.swing.ListModel;
|
||||
import javax.swing.event.*;
|
||||
import java.io.Serializable;
|
||||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
* The abstract definition for the data model that provides
|
||||
* a <code>List</code> with its contents.
|
||||
* <p>
|
||||
* <strong>Warning:</strong>
|
||||
* Serialized objects of this class will not be compatible with
|
||||
* future Swing releases. The current serialization support is
|
||||
* appropriate for short term storage or RMI between applications running
|
||||
* the same version of Swing. As of 1.4, support for long term storage
|
||||
* of all JavaBeans
|
||||
* has been added to the <code>java.beans</code> package.
|
||||
* Please see {@link java.beans.XMLEncoder}.
|
||||
*
|
||||
* @param <E> the type of the elements of this model
|
||||
*
|
||||
* @author Hans Muller
|
||||
* @since 1.2
|
||||
*/
|
||||
@SuppressWarnings("serial") // Same-version serialization only
|
||||
public abstract class XAbstractListModel<E> implements ListModel<E>, Serializable
|
||||
{
|
||||
/**
|
||||
* The listener list.
|
||||
*/
|
||||
protected EventListenerList listenerList = new EventListenerList();
|
||||
|
||||
/**
|
||||
* Constructor for subclasses to call.
|
||||
*/
|
||||
protected XAbstractListModel() {}
|
||||
|
||||
/**
|
||||
* Adds a listener to the list that's notified each time a change
|
||||
* to the data model occurs.
|
||||
*
|
||||
* @param l the <code>ListDataListener</code> to be added
|
||||
*/
|
||||
public void addListDataListener(ListDataListener l) {
|
||||
listenerList.add(ListDataListener.class, l);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes a listener from the list that's notified each time a
|
||||
* change to the data model occurs.
|
||||
*
|
||||
* @param l the <code>ListDataListener</code> to be removed
|
||||
*/
|
||||
public void removeListDataListener(ListDataListener l) {
|
||||
listenerList.remove(ListDataListener.class, l);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of all the list data listeners
|
||||
* registered on this <code>AbstractListModel</code>.
|
||||
*
|
||||
* @return all of this model's <code>ListDataListener</code>s,
|
||||
* or an empty array if no list data listeners
|
||||
* are currently registered
|
||||
*
|
||||
* @see #addListDataListener
|
||||
* @see #removeListDataListener
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
public ListDataListener[] getListDataListeners() {
|
||||
return listenerList.getListeners(ListDataListener.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <code>AbstractListModel</code> subclasses must call this method
|
||||
* <b>after</b>
|
||||
* one or more elements of the list change. The changed elements
|
||||
* are specified by the closed interval index0, index1 -- the endpoints
|
||||
* are included. Note that
|
||||
* index0 need not be less than or equal to index1.
|
||||
*
|
||||
* @param source the <code>ListModel</code> that changed, typically "this"
|
||||
* @param index0 one end of the new interval
|
||||
* @param index1 the other end of the new interval
|
||||
* @see EventListenerList
|
||||
* @see XDefaultListModel
|
||||
*/
|
||||
protected void fireContentsChanged(Object source, int index0, int index1)
|
||||
{
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
ListDataEvent e = null;
|
||||
|
||||
for (int i = listeners.length - 2; i >= 0; i -= 2) {
|
||||
if (listeners[i] == ListDataListener.class) {
|
||||
if (e == null) {
|
||||
e = new ListDataEvent(source, ListDataEvent.CONTENTS_CHANGED, index0, index1);
|
||||
}
|
||||
((ListDataListener)listeners[i+1]).contentsChanged(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <code>AbstractListModel</code> subclasses must call this method
|
||||
* <b>after</b>
|
||||
* one or more elements are added to the model. The new elements
|
||||
* are specified by a closed interval index0, index1 -- the enpoints
|
||||
* are included. Note that
|
||||
* index0 need not be less than or equal to index1.
|
||||
*
|
||||
* @param source the <code>ListModel</code> that changed, typically "this"
|
||||
* @param index0 one end of the new interval
|
||||
* @param index1 the other end of the new interval
|
||||
* @see EventListenerList
|
||||
* @see XDefaultListModel
|
||||
*/
|
||||
protected void fireIntervalAdded(Object source, int index0, int index1)
|
||||
{
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
ListDataEvent e = null;
|
||||
|
||||
for (int i = listeners.length - 2; i >= 0; i -= 2) {
|
||||
if (listeners[i] == ListDataListener.class) {
|
||||
if (e == null) {
|
||||
e = new ListDataEvent(source, ListDataEvent.INTERVAL_ADDED, index0, index1);
|
||||
}
|
||||
((ListDataListener)listeners[i+1]).intervalAdded(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <code>AbstractListModel</code> subclasses must call this method
|
||||
* <b>after</b> one or more elements are removed from the model.
|
||||
* <code>index0</code> and <code>index1</code> are the end points
|
||||
* of the interval that's been removed. Note that <code>index0</code>
|
||||
* need not be less than or equal to <code>index1</code>.
|
||||
*
|
||||
* @param source the <code>ListModel</code> that changed, typically "this"
|
||||
* @param index0 one end of the removed interval,
|
||||
* including <code>index0</code>
|
||||
* @param index1 the other end of the removed interval,
|
||||
* including <code>index1</code>
|
||||
* @see EventListenerList
|
||||
* @see XDefaultListModel
|
||||
*/
|
||||
protected void fireIntervalRemoved(Object source, int index0, int index1)
|
||||
{
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
ListDataEvent e = null;
|
||||
|
||||
for (int i = listeners.length - 2; i >= 0; i -= 2) {
|
||||
if (listeners[i] == ListDataListener.class) {
|
||||
if (e == null) {
|
||||
e = new ListDataEvent(source, ListDataEvent.INTERVAL_REMOVED, index0, index1);
|
||||
}
|
||||
((ListDataListener)listeners[i+1]).intervalRemoved(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all the objects currently registered as
|
||||
* <code><em>Foo</em>Listener</code>s
|
||||
* upon this model.
|
||||
* <code><em>Foo</em>Listener</code>s
|
||||
* are registered using the <code>add<em>Foo</em>Listener</code> method.
|
||||
* <p>
|
||||
* You can specify the <code>listenerType</code> argument
|
||||
* with a class literal, such as <code><em>Foo</em>Listener.class</code>.
|
||||
* For example, you can query a list model
|
||||
* <code>m</code>
|
||||
* for its list data listeners
|
||||
* with the following code:
|
||||
*
|
||||
* <pre>ListDataListener[] ldls = (ListDataListener[])(m.getListeners(ListDataListener.class));</pre>
|
||||
*
|
||||
* If no such listeners exist,
|
||||
* this method returns an empty array.
|
||||
*
|
||||
* @param <T> the type of {@code EventListener} class being requested
|
||||
* @param listenerType the type of listeners requested;
|
||||
* this parameter should specify an interface
|
||||
* that descends from <code>java.util.EventListener</code>
|
||||
* @return an array of all objects registered as
|
||||
* <code><em>Foo</em>Listener</code>s
|
||||
* on this model,
|
||||
* or an empty array if no such
|
||||
* listeners have been added
|
||||
* @exception ClassCastException if <code>listenerType</code> doesn't
|
||||
* specify a class or interface that implements
|
||||
* <code>java.util.EventListener</code>
|
||||
*
|
||||
* @see #getListDataListeners
|
||||
*
|
||||
* @since 1.3
|
||||
*/
|
||||
public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
|
||||
return listenerList.getListeners(listenerType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JButton;
|
||||
|
||||
public class XButton extends JButton{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public XButton() {
|
||||
super();
|
||||
super.setContentAreaFilled(false);
|
||||
}
|
||||
|
||||
public XButton(Action a) {
|
||||
super(a);
|
||||
super.setContentAreaFilled(false);
|
||||
}
|
||||
|
||||
public XButton(Icon icon) {
|
||||
super(icon);
|
||||
super.setContentAreaFilled(false);
|
||||
}
|
||||
|
||||
public XButton(String text, Icon icon) {
|
||||
super(text, icon);
|
||||
super.setContentAreaFilled(false);
|
||||
}
|
||||
|
||||
public XButton(String text) {
|
||||
super(text);
|
||||
super.setContentAreaFilled(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
g.setColor(getBackground());
|
||||
g.fillRoundRect(0, 0, getWidth()-1, getHeight()-1, 20, 20);
|
||||
super.paint(g);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,584 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package org.kne.cloud.klalb.uitool;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
|
||||
|
||||
/**
|
||||
* This class loosely implements the {@code java.util.Vector}
|
||||
* API, in that it implements the 1.1.x version of
|
||||
* {@code java.util.Vector}, has no collection class support,
|
||||
* and notifies the {@code ListDataListener}s when changes occur.
|
||||
* Presently it delegates to a {@code Vector},
|
||||
* in a future release it will be a real Collection implementation.
|
||||
* <p>
|
||||
* <strong>Warning:</strong>
|
||||
* Serialized objects of this class will not be compatible with
|
||||
* future Swing releases. The current serialization support is
|
||||
* appropriate for short term storage or RMI between applications running
|
||||
* the same version of Swing. As of 1.4, support for long term storage
|
||||
* of all JavaBeans
|
||||
* has been added to the {@code java.beans} package.
|
||||
* Please see {@link java.beans.XMLEncoder}.
|
||||
*
|
||||
* @param <E> the type of the elements of this model
|
||||
*
|
||||
* @author Hans Muller
|
||||
* @since 1.2
|
||||
*/
|
||||
@SuppressWarnings("serial") // Same-version serialization only
|
||||
public class XDefaultListModel<E> extends XAbstractListModel<E> implements Externalizable
|
||||
{
|
||||
private Vector<E> delegate = new Vector<E>();
|
||||
|
||||
/**
|
||||
* Constructs a {@code DefaultListModel}.
|
||||
*/
|
||||
public XDefaultListModel() {}
|
||||
|
||||
/**
|
||||
* Returns the number of components in this list.
|
||||
* <p>
|
||||
* This method is identical to {@code size}, which implements the
|
||||
* {@code List} interface defined in the 1.2 Collections framework.
|
||||
* This method exists in conjunction with {@code setSize} so that
|
||||
* {@code size} is identifiable as a JavaBean property.
|
||||
*
|
||||
* @return the number of components in this list
|
||||
* @see #size()
|
||||
*/
|
||||
public int getSize() {
|
||||
return delegate.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the component at the specified index.
|
||||
* <blockquote>
|
||||
* <b>Note:</b> Although this method is not deprecated, the preferred
|
||||
* method to use is {@code get(int)}, which implements the {@code List}
|
||||
* interface defined in the 1.2 Collections framework.
|
||||
* </blockquote>
|
||||
* @param index an index into this list
|
||||
* @return the component at the specified index
|
||||
* @throws ArrayIndexOutOfBoundsException if the {@code index}
|
||||
* is negative or greater than the current size of this
|
||||
* list
|
||||
* @see #get(int)
|
||||
*/
|
||||
public E getElementAt(int index) {
|
||||
return delegate.elementAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the components of this list into the specified array.
|
||||
* The array must be big enough to hold all the objects in this list,
|
||||
* else an {@code IndexOutOfBoundsException} is thrown.
|
||||
*
|
||||
* @param anArray the array into which the components get copied
|
||||
* @see Vector#copyInto(Object[])
|
||||
*/
|
||||
public void copyInto(Object[] anArray) {
|
||||
delegate.copyInto(anArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims the capacity of this list to be the list's current size.
|
||||
*
|
||||
* @see Vector#trimToSize()
|
||||
*/
|
||||
public void trimToSize() {
|
||||
delegate.trimToSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the capacity of this list, if necessary, to ensure
|
||||
* that it can hold at least the number of components specified by
|
||||
* the minimum capacity argument.
|
||||
*
|
||||
* @param minCapacity the desired minimum capacity
|
||||
* @see Vector#ensureCapacity(int)
|
||||
*/
|
||||
public void ensureCapacity(int minCapacity) {
|
||||
delegate.ensureCapacity(minCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the size of this list.
|
||||
*
|
||||
* @param newSize the new size of this list
|
||||
* @see Vector#setSize(int)
|
||||
*/
|
||||
public void setSize(int newSize) {
|
||||
int oldSize = delegate.size();
|
||||
delegate.setSize(newSize);
|
||||
if (oldSize > newSize) {
|
||||
fireIntervalRemoved(this, newSize, oldSize-1);
|
||||
}
|
||||
else if (oldSize < newSize) {
|
||||
fireIntervalAdded(this, oldSize, newSize-1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current capacity of this list.
|
||||
*
|
||||
* @return the current capacity
|
||||
* @see Vector#capacity()
|
||||
*/
|
||||
public int capacity() {
|
||||
return delegate.capacity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of components in this list.
|
||||
*
|
||||
* @return the number of components in this list
|
||||
* @see Vector#size()
|
||||
*/
|
||||
public int size() {
|
||||
return delegate.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether this list has any components.
|
||||
*
|
||||
* @return {@code true} if and only if this list has
|
||||
* no components, that is, its size is zero;
|
||||
* {@code false} otherwise
|
||||
* @see Vector#isEmpty()
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return delegate.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an enumeration of the components of this list.
|
||||
*
|
||||
* @return an enumeration of the components of this list
|
||||
* @see Vector#elements()
|
||||
*/
|
||||
public Enumeration<E> elements() {
|
||||
return delegate.elements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the specified object is a component in this list.
|
||||
*
|
||||
* @param elem an object
|
||||
* @return {@code true} if the specified object
|
||||
* is the same as a component in this list
|
||||
* @see Vector#contains(Object)
|
||||
*/
|
||||
public boolean contains(Object elem) {
|
||||
return delegate.contains(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for the first occurrence of {@code elem}.
|
||||
*
|
||||
* @param elem an object
|
||||
* @return the index of the first occurrence of the argument in this
|
||||
* list; returns {@code -1} if the object is not found
|
||||
* @see Vector#indexOf(Object)
|
||||
*/
|
||||
public int indexOf(Object elem) {
|
||||
return delegate.indexOf(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for the first occurrence of {@code elem}, beginning
|
||||
* the search at {@code index}.
|
||||
*
|
||||
* @param elem the desired component
|
||||
* @param index the index from which to begin searching
|
||||
* @return the index where the first occurrence of {@code elem}
|
||||
* is found after {@code index}; returns {@code -1}
|
||||
* if the {@code elem} is not found in the list
|
||||
* @see Vector#indexOf(Object,int)
|
||||
*/
|
||||
public int indexOf(Object elem, int index) {
|
||||
return delegate.indexOf(elem, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the last occurrence of {@code elem}.
|
||||
*
|
||||
* @param elem the desired component
|
||||
* @return the index of the last occurrence of {@code elem}
|
||||
* in the list; returns {@code elem} if the object is not found
|
||||
* @see Vector#lastIndexOf(Object)
|
||||
*/
|
||||
public int lastIndexOf(Object elem) {
|
||||
return delegate.lastIndexOf(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches backwards for {@code elem}, starting from the
|
||||
* specified index, and returns an index to it.
|
||||
*
|
||||
* @param elem the desired component
|
||||
* @param index the index to start searching from
|
||||
* @return the index of the last occurrence of the {@code elem}
|
||||
* in this list at position less than {@code index};
|
||||
* returns {@code -1} if the object is not found
|
||||
* @see Vector#lastIndexOf(Object,int)
|
||||
*/
|
||||
public int lastIndexOf(Object elem, int index) {
|
||||
return delegate.lastIndexOf(elem, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the component at the specified index.
|
||||
* <blockquote>
|
||||
* <b>Note:</b> Although this method is not deprecated, the preferred
|
||||
* method to use is {@code get(int)}, which implements the
|
||||
* {@code List} interface defined in the 1.2 Collections framework.
|
||||
* </blockquote>
|
||||
*
|
||||
* @param index an index into this list
|
||||
* @return the component at the specified index
|
||||
* @throws ArrayIndexOutOfBoundsException if the index
|
||||
* is negative or not less than the size of the list
|
||||
* @see #get(int)
|
||||
* @see Vector#elementAt(int)
|
||||
*/
|
||||
public E elementAt(int index) {
|
||||
return delegate.elementAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first component of this list.
|
||||
* @return the first component of this list
|
||||
* @see Vector#firstElement()
|
||||
* @throws java.util.NoSuchElementException if this
|
||||
* vector has no components
|
||||
*/
|
||||
public E firstElement() {
|
||||
return delegate.firstElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last component of the list.
|
||||
*
|
||||
* @return the last component of the list
|
||||
* @see Vector#lastElement()
|
||||
* @throws java.util.NoSuchElementException if this vector
|
||||
* has no components
|
||||
*/
|
||||
public E lastElement() {
|
||||
return delegate.lastElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the component at the specified {@code index} of this
|
||||
* list to be the specified element. The previous component at that
|
||||
* position is discarded.
|
||||
* <blockquote>
|
||||
* <b>Note:</b> Although this method is not deprecated, the preferred
|
||||
* method to use is {@code set(int,Object)}, which implements the
|
||||
* {@code List} interface defined in the 1.2 Collections framework.
|
||||
* </blockquote>
|
||||
*
|
||||
* @param element what the component is to be set to
|
||||
* @param index the specified index
|
||||
* @throws ArrayIndexOutOfBoundsException if the index is invalid
|
||||
* @see #set(int,Object)
|
||||
* @see Vector#setElementAt(Object,int)
|
||||
*/
|
||||
public void setElementAt(E element, int index) {
|
||||
delegate.setElementAt(element, index);
|
||||
fireContentsChanged(this, index, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the component at the specified index.
|
||||
* <blockquote>
|
||||
* <b>Note:</b> Although this method is not deprecated, the preferred
|
||||
* method to use is {@code remove(int)}, which implements the
|
||||
* {@code List} interface defined in the 1.2 Collections framework.
|
||||
* </blockquote>
|
||||
*
|
||||
* @param index the index of the object to remove
|
||||
* @see #remove(int)
|
||||
* @see Vector#removeElementAt(int)
|
||||
* @throws ArrayIndexOutOfBoundsException if the index is invalid
|
||||
*/
|
||||
public void removeElementAt(int index) {
|
||||
delegate.removeElementAt(index);
|
||||
fireIntervalRemoved(this, index, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the specified element as a component in this list at the
|
||||
* specified <code>index</code>.
|
||||
* <blockquote>
|
||||
* <b>Note:</b> Although this method is not deprecated, the preferred
|
||||
* method to use is {@code add(int,Object)}, which implements the
|
||||
* {@code List} interface defined in the 1.2 Collections framework.
|
||||
* </blockquote>
|
||||
*
|
||||
* @param element the component to insert
|
||||
* @param index where to insert the new component
|
||||
* @exception ArrayIndexOutOfBoundsException if the index was invalid
|
||||
* @see #add(int,Object)
|
||||
* @see Vector#insertElementAt(Object,int)
|
||||
*/
|
||||
public void insertElementAt(E element, int index) {
|
||||
delegate.insertElementAt(element, index);
|
||||
fireIntervalAdded(this, index, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified component to the end of this list.
|
||||
*
|
||||
* @param element the component to be added
|
||||
* @see Vector#addElement(Object)
|
||||
*/
|
||||
public void addElement(E element) {
|
||||
int index = delegate.size();
|
||||
delegate.addElement(element);
|
||||
fireIntervalAdded(this, index, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the first (lowest-indexed) occurrence of the argument
|
||||
* from this list.
|
||||
*
|
||||
* @param obj the component to be removed
|
||||
* @return {@code true} if the argument was a component of this
|
||||
* list; {@code false} otherwise
|
||||
* @see Vector#removeElement(Object)
|
||||
*/
|
||||
public boolean removeElement(Object obj) {
|
||||
int index = indexOf(obj);
|
||||
boolean rv = delegate.removeElement(obj);
|
||||
if (index >= 0) {
|
||||
fireIntervalRemoved(this, index, index);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes all components from this list and sets its size to zero.
|
||||
* <blockquote>
|
||||
* <b>Note:</b> Although this method is not deprecated, the preferred
|
||||
* method to use is {@code clear}, which implements the
|
||||
* {@code List} interface defined in the 1.2 Collections framework.
|
||||
* </blockquote>
|
||||
*
|
||||
* @see #clear()
|
||||
* @see Vector#removeAllElements()
|
||||
*/
|
||||
public void removeAllElements() {
|
||||
int index1 = delegate.size()-1;
|
||||
delegate.removeAllElements();
|
||||
if (index1 >= 0) {
|
||||
fireIntervalRemoved(this, 0, index1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a string that displays and identifies this
|
||||
* object's properties.
|
||||
*
|
||||
* @return a String representation of this object
|
||||
*/
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
|
||||
/* The remaining methods are included for compatibility with the
|
||||
* Java 2 platform Vector class.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns an array containing all of the elements in this list in the
|
||||
* correct order.
|
||||
*
|
||||
* @return an array containing the elements of the list
|
||||
* @see Vector#toArray()
|
||||
*/
|
||||
public Object[] toArray() {
|
||||
Object[] rv = new Object[delegate.size()];
|
||||
delegate.copyInto(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element at the specified position in this list.
|
||||
*
|
||||
* @param index index of element to return
|
||||
* @return the element at the specified position in this list
|
||||
* @throws ArrayIndexOutOfBoundsException if the index is out of range
|
||||
* ({@code index < 0 || index >= size()})
|
||||
*/
|
||||
public E get(int index) {
|
||||
return delegate.elementAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the element at the specified position in this list with the
|
||||
* specified element.
|
||||
*
|
||||
* @param index index of element to replace
|
||||
* @param element element to be stored at the specified position
|
||||
* @return the element previously at the specified position
|
||||
* @throws ArrayIndexOutOfBoundsException if the index is out of range
|
||||
* ({@code index < 0 || index >= size()})
|
||||
*/
|
||||
public E set(int index, E element) {
|
||||
E rv = delegate.elementAt(index);
|
||||
delegate.setElementAt(element, index);
|
||||
fireContentsChanged(this, index, index);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the specified element at the specified position in this list.
|
||||
*
|
||||
* @param index index at which the specified element is to be inserted
|
||||
* @param element element to be inserted
|
||||
* @throws ArrayIndexOutOfBoundsException if the index is out of range
|
||||
* ({@code index < 0 || index > size()})
|
||||
*/
|
||||
public void add(int index, E element) {
|
||||
delegate.insertElementAt(element, index);
|
||||
fireIntervalAdded(this, index, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the element at the specified position in this list.
|
||||
* Returns the element that was removed from the list
|
||||
*
|
||||
* @param index the index of the element to removed
|
||||
* @return the element previously at the specified position
|
||||
* @throws ArrayIndexOutOfBoundsException if the index is out of range
|
||||
* ({@code index < 0 || index >= size()})
|
||||
*/
|
||||
public E remove(int index) {
|
||||
E rv = delegate.elementAt(index);
|
||||
delegate.removeElementAt(index);
|
||||
fireIntervalRemoved(this, index, index);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all of the elements from this list. The list will
|
||||
* be empty after this call returns (unless it throws an exception).
|
||||
*/
|
||||
public void clear() {
|
||||
int index1 = delegate.size()-1;
|
||||
delegate.removeAllElements();
|
||||
if (index1 >= 0) {
|
||||
fireIntervalRemoved(this, 0, index1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the components at the specified range of indexes.
|
||||
* The removal is inclusive, so specifying a range of (1,5)
|
||||
* removes the component at index 1 and the component at index 5,
|
||||
* as well as all components in between.
|
||||
*
|
||||
* @param fromIndex the index of the lower end of the range
|
||||
* @param toIndex the index of the upper end of the range
|
||||
* @throws ArrayIndexOutOfBoundsException if the index was invalid
|
||||
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
|
||||
* @see #remove(int)
|
||||
*/
|
||||
public void removeRange(int fromIndex, int toIndex) {
|
||||
if (fromIndex > toIndex) {
|
||||
throw new IllegalArgumentException("fromIndex must be <= toIndex");
|
||||
}
|
||||
for(int i = toIndex; i >= fromIndex; i--) {
|
||||
delegate.removeElementAt(i);
|
||||
}
|
||||
fireIntervalRemoved(this, fromIndex, toIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all of the elements present in the collection to the list.
|
||||
*
|
||||
* @param c the collection which contains the elements to add
|
||||
* @throws NullPointerException if {@code c} is null
|
||||
*/
|
||||
public void addAll(Collection<? extends E> c) {
|
||||
if (c.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int startIndex = getSize();
|
||||
|
||||
delegate.addAll(c);
|
||||
fireIntervalAdded(this, startIndex, getSize() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all of the elements present in the collection, starting
|
||||
* from the specified index.
|
||||
*
|
||||
* @param index index at which to insert the first element from the
|
||||
* specified collection
|
||||
* @param c the collection which contains the elements to add
|
||||
* @throws ArrayIndexOutOfBoundsException if {@code index} does not
|
||||
* fall within the range of number of elements currently held
|
||||
* @throws NullPointerException if {@code c} is null
|
||||
*/
|
||||
public void addAll(int index, Collection<? extends E> c) {
|
||||
if (index < 0 || index > getSize()) {
|
||||
throw new ArrayIndexOutOfBoundsException("index out of range: " +
|
||||
index);
|
||||
}
|
||||
|
||||
if (c.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
delegate.addAll(index, c);
|
||||
fireIntervalAdded(this, index, index + c.size() - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
out.writeObject(delegate);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
delegate=(Vector<E>) in.readObject();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,396 @@
|
||||
package org.kne.cloud.network;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* 修复的BufferedChannel,解决Socket关闭时的数据一致性问题
|
||||
*/
|
||||
public class BufferedChannel implements ReadableByteChannel, WritableByteChannel, ScatteringByteChannel, GatheringByteChannel {
|
||||
private final ReadableByteChannel inputChannel;
|
||||
private final WritableByteChannel outputChannel;
|
||||
private final ByteBuffer readBuffer;
|
||||
private final ByteBuffer writeBuffer;
|
||||
|
||||
|
||||
// private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||
private final AtomicBoolean inputShutdown = new AtomicBoolean(false);
|
||||
private final AtomicBoolean outputShutdown = new AtomicBoolean(false);
|
||||
|
||||
public BufferedChannel(ReadableByteChannel channel, int bufferSize) {
|
||||
this(channel, null, bufferSize);
|
||||
}
|
||||
|
||||
public BufferedChannel(WritableByteChannel channel, int bufferSize) {
|
||||
this(null, channel, bufferSize);
|
||||
}
|
||||
|
||||
public BufferedChannel(ReadableByteChannel inputChannel, WritableByteChannel outputChannel, int bufferSize) {
|
||||
this.inputChannel = inputChannel;
|
||||
this.outputChannel = outputChannel;
|
||||
this.readBuffer = ByteBuffer.allocateDirect(bufferSize);
|
||||
this.writeBuffer = ByteBuffer.allocateDirect(bufferSize);
|
||||
|
||||
// 更安全的初始化
|
||||
this.readBuffer.limit(0); // 明确设置为空
|
||||
this.writeBuffer.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(ByteBuffer dst) throws IOException {
|
||||
if ( inputShutdown.get()) {
|
||||
throw new ClosedChannelException();
|
||||
}
|
||||
|
||||
|
||||
// 检查底层通道是否仍然打开
|
||||
if (inputChannel != null && !inputChannel.isOpen()) {
|
||||
inputShutdown.set(true);
|
||||
return handleInputShutdown();
|
||||
}
|
||||
|
||||
int totalRead = 0;
|
||||
boolean eofEncountered = false;
|
||||
|
||||
while (dst.hasRemaining() && !eofEncountered) {
|
||||
// 如果读缓冲区有数据,先从中读取
|
||||
if (readBuffer.hasRemaining()) {
|
||||
int bytesToCopy = Math.min(readBuffer.remaining(), dst.remaining());
|
||||
|
||||
// 使用绝对位置操作,避免修改缓冲区状态
|
||||
int oldlimit=readBuffer.limit();
|
||||
readBuffer.limit(readBuffer.position()+bytesToCopy);
|
||||
dst.put(readBuffer);
|
||||
readBuffer.limit(oldlimit);
|
||||
|
||||
totalRead += bytesToCopy;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 读缓冲区空了,需要重新填充
|
||||
readBuffer.clear();
|
||||
int bytesRead;
|
||||
try {
|
||||
bytesRead = inputChannel.read(readBuffer);
|
||||
} catch (IOException e) {
|
||||
// 读取时发生IO异常,标记为关闭
|
||||
inputShutdown.set(true);
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (bytesRead == -1) {
|
||||
// 到达EOF
|
||||
inputShutdown.set(true);
|
||||
eofEncountered = true;
|
||||
} else if (bytesRead == 0) {
|
||||
// 没有数据可用,可能是非阻塞模式
|
||||
break;
|
||||
} else {
|
||||
readBuffer.flip();
|
||||
}
|
||||
}
|
||||
|
||||
// 如果遇到EOF且没有读取到任何数据,返回-1
|
||||
if (eofEncountered && totalRead == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return totalRead;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理输入关闭的情况
|
||||
*/
|
||||
private int handleInputShutdown() throws IOException {
|
||||
// 如果读缓冲区还有剩余数据,先返回这些数据
|
||||
if (readBuffer.hasRemaining()) {
|
||||
return readBuffer.remaining();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read(ByteBuffer[] dsts) throws IOException {
|
||||
return read(dsts, 0, dsts.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
|
||||
|
||||
|
||||
long totalRead = 0;
|
||||
for (int i = offset; i < offset + length; i++) {
|
||||
ByteBuffer dst = dsts[i];
|
||||
if (dst == null) {
|
||||
throw new NullPointerException("Destination buffer is null");
|
||||
}
|
||||
|
||||
int bytesRead = read(dst);
|
||||
if (bytesRead == -1) {
|
||||
// 只有在没有读取任何数据时才返回-1
|
||||
return totalRead > 0 ? totalRead : -1;
|
||||
}
|
||||
totalRead += bytesRead;
|
||||
}
|
||||
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int write(ByteBuffer src) throws IOException {
|
||||
|
||||
|
||||
|
||||
// 检查底层通道是否仍然打开
|
||||
if (outputChannel != null && !outputChannel.isOpen()) {
|
||||
outputShutdown.set(true);
|
||||
throw new ClosedChannelException();
|
||||
}
|
||||
|
||||
int totalWritten = 0;
|
||||
|
||||
while (src.hasRemaining()) {
|
||||
// 如果写缓冲区有空间,先填充
|
||||
if (writeBuffer.hasRemaining()) {
|
||||
int bytesToCopy = Math.min(writeBuffer.remaining(), src.remaining());
|
||||
int oldlimit= src.limit();
|
||||
src.limit(src.position()+bytesToCopy);
|
||||
writeBuffer.put(src);
|
||||
src.limit(oldlimit);
|
||||
|
||||
totalWritten += bytesToCopy;
|
||||
}
|
||||
|
||||
// 如果写缓冲区满了或者源数据还很多,刷新缓冲区
|
||||
if (!writeBuffer.hasRemaining() ) {
|
||||
try {
|
||||
flushInternal();
|
||||
} catch (IOException e) {
|
||||
outputShutdown.set(true);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return totalWritten;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long write(ByteBuffer[] srcs) throws IOException {
|
||||
return write(srcs, 0, srcs.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
|
||||
|
||||
|
||||
long totalWritten = 0;
|
||||
for (int i = offset; i < offset + length; i++) {
|
||||
ByteBuffer src = srcs[i];
|
||||
if (src == null) {
|
||||
throw new NullPointerException("Source buffer is null");
|
||||
}
|
||||
|
||||
int bytesWritten = write(src);
|
||||
totalWritten += bytesWritten;
|
||||
}
|
||||
|
||||
return totalWritten;
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全的刷新方法
|
||||
*/
|
||||
public void flush() throws IOException {
|
||||
|
||||
|
||||
if (outputChannel == null || outputShutdown.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
flushInternal();
|
||||
} catch (IOException e) {
|
||||
outputShutdown.set(true);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部刷新方法,假设已经持有writeLock
|
||||
*/
|
||||
private void flushInternal() throws IOException {
|
||||
if (writeBuffer.position() > 0) {
|
||||
writeBuffer.flip();
|
||||
|
||||
try {
|
||||
while (writeBuffer.hasRemaining()) {
|
||||
int written = outputChannel.write(writeBuffer);
|
||||
// System.out.println("发送"+written);
|
||||
if (written == 0) {
|
||||
// 可能遇到阻塞或关闭
|
||||
if (!outputChannel.isOpen()) {
|
||||
outputShutdown.set(true);
|
||||
throw new ClosedChannelException();
|
||||
}
|
||||
// 给其他操作机会
|
||||
Thread.yield();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// 无论发生什么,确保写缓冲区处于可写状态
|
||||
writeBuffer.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全的关闭方法
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
||||
|
||||
IOException exception = null;
|
||||
|
||||
// 先刷新输出缓冲区
|
||||
if (outputChannel != null && !outputShutdown.get()) {
|
||||
|
||||
if (writeBuffer.position() > 0) {
|
||||
try {
|
||||
flushInternal();
|
||||
} catch (IOException e) {
|
||||
exception = e;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 关闭底层通道
|
||||
try {
|
||||
if (inputChannel != null) {
|
||||
inputChannel.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (exception == null) {
|
||||
exception = e;
|
||||
} else {
|
||||
exception.addSuppressed(e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (outputChannel != null) {
|
||||
outputChannel.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (exception == null) {
|
||||
exception = e;
|
||||
} else {
|
||||
exception.addSuppressed(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 清理缓冲区状态
|
||||
|
||||
readBuffer.clear();
|
||||
readBuffer.limit(0); // 标记为已清空
|
||||
|
||||
|
||||
|
||||
writeBuffer.clear();
|
||||
|
||||
|
||||
// 设置关闭状态
|
||||
inputShutdown.set(true);
|
||||
outputShutdown.set(true);
|
||||
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 优雅关闭 - 只关闭输入或输出
|
||||
*/
|
||||
public void shutdownInput() throws IOException {
|
||||
inputShutdown.set(true);
|
||||
|
||||
readBuffer.clear();
|
||||
readBuffer.limit(0);
|
||||
|
||||
|
||||
if (inputChannel instanceof SocketChannel) {
|
||||
((SocketChannel) inputChannel).shutdownInput();
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdownOutput() throws IOException {
|
||||
outputShutdown.set(true);
|
||||
|
||||
if (writeBuffer.position() > 0) {
|
||||
flushInternal();
|
||||
}
|
||||
|
||||
|
||||
if (outputChannel instanceof SocketChannel) {
|
||||
((SocketChannel) outputChannel).shutdownOutput();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return
|
||||
(inputChannel == null || inputChannel.isOpen()) &&
|
||||
(outputChannel == null || outputChannel.isOpen());
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否还有可读数据(包括缓冲区中的)
|
||||
*/
|
||||
public boolean hasRemaining() throws IOException {
|
||||
if ( inputShutdown.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return readBuffer.hasRemaining() ||
|
||||
(inputChannel != null && inputChannel.isOpen());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓冲区状态信息(用于调试)
|
||||
*/
|
||||
public String getBufferState() {
|
||||
|
||||
return String.format(
|
||||
"ReadBuffer[pos=%d, lim=%d, cap=%d], WriteBuffer[pos=%d, lim=%d, cap=%d], " +
|
||||
"closed=%b, inputShutdown=%b, outputShutdown=%b",
|
||||
readBuffer.position(), readBuffer.limit(), readBuffer.capacity(),
|
||||
writeBuffer.position(), writeBuffer.limit(), writeBuffer.capacity(), inputShutdown.get(), outputShutdown.get()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// 其他方法保持不变...
|
||||
public int available() throws IOException {
|
||||
if ( inputShutdown.get()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return readBuffer.remaining();
|
||||
|
||||
}
|
||||
|
||||
public long skip(long n) throws IOException {
|
||||
// 实现保持不变...
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.kne.cloud.network;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
public class ByteArrayPool {
|
||||
private Queue<byte[]> rec;
|
||||
private int maxcount;
|
||||
private int length;
|
||||
public ByteArrayPool(int maxcount, int length) {
|
||||
super();
|
||||
this.maxcount = maxcount;
|
||||
this.length = length;
|
||||
rec=new ConcurrentLinkedQueue<byte[]>();
|
||||
}
|
||||
public void back(byte[]b) {
|
||||
if(b.length!=length)
|
||||
throw new IllegalArgumentException("wrong length");
|
||||
rec.offer(b);
|
||||
}
|
||||
public byte[] borrow() {
|
||||
byte[]b=rec.poll();
|
||||
if(b==null) {
|
||||
b=new byte[length];
|
||||
}
|
||||
return b;
|
||||
}
|
||||
public int getMaxCount() {
|
||||
return maxcount;
|
||||
}
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.kne.cloud.network;
|
||||
|
||||
import java.lang.foreign.Arena;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.kne.membandboost.MembandBoost;
|
||||
|
||||
public class ByteBufferAllocator {
|
||||
|
||||
public ByteBufferAllocator(boolean isDirect) {
|
||||
|
||||
}
|
||||
public ByteBuffer allocate(int capacity) {
|
||||
//if(capacity<1024)
|
||||
return allocateHeap(capacity);
|
||||
// return allocateNative(capacity);
|
||||
|
||||
|
||||
}
|
||||
//private Arena ar=BufferedArena.ofBuffered();
|
||||
//private Arena ara=Arena.ofAuto();
|
||||
public ByteBuffer allocateNative(int capacity) {
|
||||
//return ((jdk.internal.foreign.ArenaImpl)ara).allocateNoInit(capacity,1).asByteBuffer();
|
||||
|
||||
ByteBuffer buf=Arena.ofAuto().allocate(capacity).asByteBuffer();
|
||||
if(buf.capacity()!=capacity)
|
||||
throw new InternalError();
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
public static ByteBuffer allocateHeap(int capacity) {
|
||||
/*if(capacity<=2048) {
|
||||
return MembandBoost.allocateUninitializedHeapBufferBlocked(capacity);
|
||||
}else {*/
|
||||
return MembandBoost.allocateUninitializedHeapBuffer(capacity);
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package org.kne.cloud.network;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.kne.concurrent.SpinLock;
|
||||
import org.kne.debug.TimeDebugger;
|
||||
|
||||
|
||||
public class ByteBufferPool {
|
||||
private AtomicReferenceArray< ByteBuffer> rec;
|
||||
private volatile AtomicInteger pos=new AtomicInteger( 0);
|
||||
//private Lock lock=new SpinLock();
|
||||
|
||||
private int maxcount;
|
||||
private int length;
|
||||
private int mcj;
|
||||
private boolean direct;
|
||||
public ByteBufferPool(int maxcount, int length,boolean direct) {
|
||||
super();
|
||||
this.maxcount = maxcount;
|
||||
this.length = length;
|
||||
this.direct=direct;
|
||||
rec=new AtomicReferenceArray<ByteBuffer>(maxcount);
|
||||
mcj= rec.length()-1;
|
||||
}
|
||||
public ByteBufferPool(int maxcount, int length) {
|
||||
this(maxcount, length, true);
|
||||
}
|
||||
public void back(ByteBuffer b) {
|
||||
if(b.capacity()!=length)
|
||||
throw new IllegalArgumentException("wrong length");
|
||||
b.clear();
|
||||
|
||||
|
||||
if(pos.get()<=mcj) {
|
||||
int d=pos.getAndIncrement();
|
||||
if(d>mcj)
|
||||
d=mcj;
|
||||
if(d<0)
|
||||
d=0;
|
||||
rec.compareAndSet(d,null,b);
|
||||
}
|
||||
|
||||
}
|
||||
public ByteBuffer borrow() {
|
||||
ByteBuffer b=null;
|
||||
|
||||
if(pos.get()>0) {
|
||||
int d=pos.decrementAndGet();
|
||||
if(d>mcj)
|
||||
d=mcj;
|
||||
if(d<0)
|
||||
d=0;
|
||||
b=rec.getAndSet(d,null);
|
||||
}
|
||||
|
||||
if(b==null) {
|
||||
if(direct)
|
||||
b=ByteBuffer.allocateDirect(length);
|
||||
else
|
||||
b=ByteBuffer.allocate(length);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
public int getMaxCount() {
|
||||
return maxcount;
|
||||
}
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package org.kne.cloud.network;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.kne.io.Task;
|
||||
|
||||
public class ChannelBridge extends Task{
|
||||
protected ReadableByteChannel in;
|
||||
protected WritableByteChannel out;
|
||||
protected int blocksize=65535;
|
||||
protected long delay=0;
|
||||
public ChannelBridge(ReadableByteChannel in, WritableByteChannel out) {
|
||||
super();
|
||||
Objects.requireNonNull(in);
|
||||
Objects.requireNonNull(out);
|
||||
this.in = in;
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runTask() {
|
||||
//FileOutputStream fos=null;
|
||||
try {
|
||||
//fos=new FileOutputStream(UUID.randomUUID()+".txt");
|
||||
ByteBuffer b=ByteBuffer.allocateDirect(blocksize);
|
||||
while (in.read(b)!=-1) {
|
||||
b.flip();
|
||||
out.write(b);
|
||||
b.clear();
|
||||
if(delay>0) {
|
||||
try {
|
||||
Thread.sleep(delay);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}else {
|
||||
Thread.yield();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}finally {
|
||||
/*if(fos!=null)
|
||||
try {
|
||||
fos.close();
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}*/
|
||||
try {
|
||||
if(in!=null)
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
if(in!=null)
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
public int getBlocksize() {
|
||||
return blocksize;
|
||||
}
|
||||
|
||||
public void setBlocksize(int blocksize) {
|
||||
this.blocksize = blocksize;
|
||||
}
|
||||
public long getDelay() {
|
||||
return delay;
|
||||
}
|
||||
|
||||
public void setDelay(long delay) {
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
public void runAtNewThread() {
|
||||
runAtNewThread("StreamBridge thread");
|
||||
}
|
||||
public Thread runAtNewThread(String name) {
|
||||
Thread t=ThreadTool.makeVThreadIfSupport(name, this);
|
||||
t.start();
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
package org.kne.cloud.network;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
public class DatagramServerSocket implements java.io.Closeable{
|
||||
public static final ByteArrayPool dataarraypool=new ByteArrayPool(100, 65535);
|
||||
|
||||
private boolean closed=false;
|
||||
private boolean bound=false;
|
||||
private DatagramSocketFactory dgsf;
|
||||
private Set<DatagramDistributor> skts=new HashSet<>();
|
||||
private final Object stateLock = new Object();
|
||||
private BlockingQueue<DatagramSocket> recs;
|
||||
private InetSocketAddress bindpoint;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public DatagramServerSocket() throws SocketException {
|
||||
this(new DefaultDatagramSocketFactory());
|
||||
}
|
||||
|
||||
protected DatagramServerSocket(DatagramSocketFactory impl) throws SocketException {
|
||||
this.dgsf=impl;
|
||||
}
|
||||
|
||||
public DatagramServerSocket(int port, InetAddress laddr) throws SocketException {
|
||||
this(new DefaultDatagramSocketFactory());
|
||||
bind(new InetSocketAddress(laddr, port));
|
||||
}
|
||||
|
||||
public DatagramServerSocket(int port) throws SocketException {
|
||||
this(new DefaultDatagramSocketFactory());
|
||||
bind(new InetSocketAddress(port));
|
||||
}
|
||||
|
||||
public DatagramServerSocket(SocketAddress bindaddr) throws SocketException {
|
||||
this(new DefaultDatagramSocketFactory());
|
||||
bind(bindaddr);
|
||||
}
|
||||
|
||||
public DatagramServerSocket(int port, int backlog) throws SocketException {
|
||||
this(new DefaultDatagramSocketFactory());
|
||||
bind(new InetSocketAddress(port));
|
||||
}
|
||||
|
||||
public DatagramServerSocket(int port, int backlog, InetAddress laddr) throws SocketException {
|
||||
this(new DefaultDatagramSocketFactory());
|
||||
bind(new InetSocketAddress(laddr, port));
|
||||
}
|
||||
public void bind(SocketAddress endpoint) throws SocketException {
|
||||
bind(endpoint, 50);
|
||||
}
|
||||
public void bind(SocketAddress endpoint, int backlog) throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
if (isBound())
|
||||
throw new SocketException("Already bound");
|
||||
if (endpoint == null)
|
||||
endpoint = new InetSocketAddress(0);
|
||||
if (!(endpoint instanceof InetSocketAddress epoint))
|
||||
throw new IllegalArgumentException("Unsupported address type");
|
||||
if (epoint.isUnresolved())
|
||||
throw new SocketException("Unresolved address");
|
||||
if (backlog < 1)
|
||||
backlog = 50;
|
||||
|
||||
|
||||
|
||||
synchronized (stateLock) {
|
||||
if (closed)
|
||||
throw new SocketException("Socket is closed");
|
||||
if (bound)
|
||||
throw new SocketException("Already bound");
|
||||
bind0(epoint);
|
||||
recs=new ArrayBlockingQueue<DatagramSocket>(backlog);
|
||||
bound = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void bind0(InetSocketAddress epoint) throws SocketException {
|
||||
bindpoint=epoint;
|
||||
if(epoint.getAddress().isAnyLocalAddress()) {
|
||||
Enumeration<NetworkInterface>eu= NetworkInterface.getNetworkInterfaces();
|
||||
while (eu.hasMoreElements()) {
|
||||
NetworkInterface networkInterface = (NetworkInterface) eu.nextElement();
|
||||
if(networkInterface.isUp()) {
|
||||
//System.out.println(networkInterface+" "+networkInterface.isUp());
|
||||
Enumeration<InetAddress>ei= networkInterface.getInetAddresses();
|
||||
while (ei.hasMoreElements()) {
|
||||
InetAddress inetAddress = (InetAddress) ei.nextElement();
|
||||
DatagramDistributor dd=new DatagramDistributor(new InetSocketAddress(inetAddress, epoint.getPort()));
|
||||
skts.add(dd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}else {
|
||||
DatagramDistributor dd=new DatagramDistributor(epoint);
|
||||
skts.add(dd);
|
||||
}
|
||||
}
|
||||
private class DatagramDistributor implements Runnable{
|
||||
private Map<SocketAddress,SubDatagramSocket> clients=new ConcurrentHashMap<>();
|
||||
|
||||
private InetSocketAddress epoint;
|
||||
private DatagramSocket datagramSocket;
|
||||
public DatagramDistributor(InetSocketAddress epoint) throws SocketException {
|
||||
this.epoint=epoint;
|
||||
datagramSocket=new DatagramSocket(epoint);
|
||||
ThreadTool.makeVDaemonThreadIfSupport("Datagram Distribute Thread", this).start();
|
||||
}
|
||||
|
||||
public DatagramSocket getDatagramSocket() {
|
||||
return datagramSocket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while(!closed) {
|
||||
byte[]data=dataarraypool.borrow();
|
||||
DatagramPacket dp=new DatagramPacket(data,data.length);
|
||||
datagramSocket.receive(dp);
|
||||
//System.out.println("get:"+dp);
|
||||
SubDatagramSocket sdds=clients.get(dp.getSocketAddress());
|
||||
if(sdds==null) {
|
||||
if(recs.remainingCapacity()>1) {
|
||||
sdds=new SubDatagramSocket(epoint, (InetSocketAddress) dp.getSocketAddress(),this );
|
||||
if(recs.offer(sdds))
|
||||
clients.put(dp.getSocketAddress(), sdds);
|
||||
}
|
||||
|
||||
}
|
||||
if(sdds!=null) {
|
||||
//System.out.println("give:"+dp);
|
||||
sdds.givePacket(dp);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO 自动生成的 catch 块
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeClient(SubDatagramSocket subDatagramSocket) {
|
||||
clients.remove(subDatagramSocket.getRemoteSocketAddress());
|
||||
}
|
||||
|
||||
public void close() {
|
||||
datagramSocket.close();
|
||||
}
|
||||
|
||||
}
|
||||
public DatagramSocket accept()throws IOException{
|
||||
while(true) {
|
||||
if(isClosed())
|
||||
throw new SocketException("DatagramServerSocket closed");
|
||||
if (!isBound())
|
||||
throw new SocketException("DatagramServerSocket is not bound yet");
|
||||
DatagramSocket sds= recs.poll();
|
||||
if(sds!=null) {
|
||||
return sds;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(5);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
private boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
private boolean isBound() {
|
||||
return bound;
|
||||
}
|
||||
public class SubDatagramSocket extends DatagramSocket{
|
||||
private DatagramDistributor parent;
|
||||
private InetSocketAddress local;
|
||||
private InetSocketAddress remote;
|
||||
private boolean closed=false;
|
||||
private int timeout=0;
|
||||
private BlockingQueue<DatagramPacket> recs=new ArrayBlockingQueue(100);
|
||||
private volatile Thread t;
|
||||
private void unwait() {
|
||||
if(t!=null)
|
||||
LockSupport.unpark(t);
|
||||
}
|
||||
|
||||
public SubDatagramSocket(InetSocketAddress local,InetSocketAddress remote,DatagramDistributor datagramDistributor) throws SocketException {
|
||||
super((SocketAddress)null);
|
||||
this.local=local;
|
||||
this.remote=remote;
|
||||
this.parent=datagramDistributor;
|
||||
}
|
||||
|
||||
protected boolean givePacket(DatagramPacket dp) {
|
||||
boolean b=recs.offer(dp);
|
||||
unwait();
|
||||
return b;
|
||||
}
|
||||
public DatagramPacket receive()throws IOException{
|
||||
long start=System.nanoTime();
|
||||
while(true) {
|
||||
if(closed) {
|
||||
throw new SocketException("DatagramSocket closed");
|
||||
}
|
||||
DatagramPacket dp=recs.poll();
|
||||
if(dp!=null) {
|
||||
|
||||
return dp;
|
||||
}
|
||||
if(timeout!=0) {
|
||||
long dms=(System.nanoTime()-start)/1000000;
|
||||
if(dms>timeout)
|
||||
throw new SocketTimeoutException("Receive Time Out");
|
||||
}
|
||||
t=Thread.currentThread();
|
||||
LockSupport.parkNanos(1000000);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void receive(DatagramPacket p) throws IOException {
|
||||
DatagramPacket dp=null;
|
||||
long start=System.nanoTime();
|
||||
while(true) {
|
||||
if(closed) {
|
||||
throw new SocketException("DatagramSocket closed");
|
||||
}
|
||||
dp=recs.poll();
|
||||
if(dp!=null) {
|
||||
p.setLength(dp.getLength());
|
||||
System.arraycopy(dp.getData(), dp.getOffset(), p.getData(), p.getOffset(), dp.getLength());
|
||||
dataarraypool.back(dp.getData());
|
||||
break;
|
||||
}
|
||||
if(timeout!=0) {
|
||||
long dms=(System.nanoTime()-start)/1000000;
|
||||
if(dms>timeout)
|
||||
throw new SocketTimeoutException("Receive Time Out");
|
||||
}
|
||||
t=Thread.currentThread();
|
||||
LockSupport.parkNanos(1000000);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(DatagramPacket p) throws IOException {
|
||||
p.setSocketAddress(remote);
|
||||
parent.getDatagramSocket().send(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getRemoteSocketAddress() {
|
||||
return remote;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress getInetAddress() {
|
||||
return remote.getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPort() {
|
||||
return remote.getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getLocalSocketAddress() {
|
||||
return local;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress getLocalAddress() {
|
||||
return local.getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalPort() {
|
||||
return local.getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSoTimeout(int timeout) throws SocketException {
|
||||
this.timeout=timeout;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getSoTimeout() throws SocketException {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(!closed)
|
||||
parent.removeClient(this);
|
||||
closed=true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
closed=true;
|
||||
for (Iterator<DatagramDistributor> iterator = skts.iterator(); iterator.hasNext();) {
|
||||
DatagramDistributor datagramSocket = (DatagramDistributor) iterator.next();
|
||||
datagramSocket.close();
|
||||
}
|
||||
}
|
||||
|
||||
public SocketAddress getLocalSocketAddress() {
|
||||
return bindpoint;
|
||||
}
|
||||
|
||||
|
||||
public InetAddress getLocalAddress() {
|
||||
if(bindpoint==null)
|
||||
return null;
|
||||
else
|
||||
return bindpoint.getAddress();
|
||||
}
|
||||
|
||||
public int getLocalPort() {
|
||||
if(bindpoint==null)
|
||||
return -1;
|
||||
else
|
||||
return bindpoint.getPort();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.kne.cloud.network;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
public abstract class DatagramServerSocketFactory {
|
||||
public DatagramServerSocket createDatagramServerSocket() throws IOException {
|
||||
return new DatagramServerSocket((SocketAddress)null);
|
||||
}
|
||||
|
||||
public abstract DatagramServerSocket createDatagramServerSocket(int port) throws IOException;
|
||||
|
||||
public abstract DatagramServerSocket createDatagramServerSocket(int port, int backlog) throws IOException;
|
||||
|
||||
public abstract DatagramServerSocket createDatagramServerSocket(int port, int backlog, InetAddress ifAddress) throws IOException;
|
||||
}
|
||||