lol
This commit is contained in:
commit
613bef2496
108 changed files with 8397 additions and 0 deletions
8
.classpath
Normal file
8
.classpath
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||||
|
<classpathentry kind="lib" path="libs/mysql-connector-java-5.0.7-bin.jar"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
|
||||||
|
<classpathentry kind="output" path="bin"/>
|
||||||
|
</classpath>
|
||||||
19
.project
Normal file
19
.project
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>ZUtil</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
<nature>org.eclipse.jem.beaninfo.BeanInfoNature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
3
.settings/org.eclipse.core.resources.prefs
Normal file
3
.settings/org.eclipse.core.resources.prefs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#Wed Feb 06 16:42:34 CET 2008
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding/<project>=ISO-8859-1
|
||||||
BIN
bin/zutil/History.class
Normal file
BIN
bin/zutil/History.class
Normal file
Binary file not shown.
BIN
bin/zutil/MultiPrintStream.class
Normal file
BIN
bin/zutil/MultiPrintStream.class
Normal file
Binary file not shown.
BIN
bin/zutil/db/MySQLConnection.class
Normal file
BIN
bin/zutil/db/MySQLConnection.class
Normal file
Binary file not shown.
BIN
exemple.gif
Normal file
BIN
exemple.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 77 KiB |
171
hs_err_pid1104.log
Normal file
171
hs_err_pid1104.log
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
#
|
||||||
|
# An unexpected error has been detected by Java Runtime Environment:
|
||||||
|
#
|
||||||
|
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x77cfb15f, pid=1104, tid=5336
|
||||||
|
#
|
||||||
|
# Java VM: Java HotSpot(TM) Client VM (1.6.0_03-b05 mixed mode)
|
||||||
|
# Problematic frame:
|
||||||
|
# C [ntdll.dll+0x3b15f]
|
||||||
|
#
|
||||||
|
# If you would like to submit a bug report, please visit:
|
||||||
|
# http://java.sun.com/webapps/bugreport/crash.jsp
|
||||||
|
#
|
||||||
|
|
||||||
|
--------------- T H R E A D ---------------
|
||||||
|
|
||||||
|
Current thread (0x0b570400): JavaThread "Connection Thread" [_thread_in_native, id=5336]
|
||||||
|
|
||||||
|
siginfo: ExceptionCode=0xc0000005, writing address 0x00000014
|
||||||
|
|
||||||
|
Registers:
|
||||||
|
EAX=0x00000000, EBX=0xfffffffc, ECX=0x00000000, EDX=0x00000004
|
||||||
|
ESP=0x0bc3efe8, EBP=0x0bc3f038, ESI=0x0ba590bc, EDI=0x0ba590c0
|
||||||
|
EIP=0x77cfb15f, EFLAGS=0x00010213
|
||||||
|
|
||||||
|
Top of Stack: (sp=0x0bc3efe8)
|
||||||
|
0x0bc3efe8: 0ba590bc 0ba590c0 00000000 001d4290
|
||||||
|
0x0bc3eff8: 00000000 00000000 0bc3f07c 75a64c14
|
||||||
|
0x0bc3f008: 00000424 00000420 00000002 75a63f42
|
||||||
|
0x0bc3f018: cacfe3c5 0bc3f108 0bc3f114 00000000
|
||||||
|
0x0bc3f028: 00000000 00000000 7ffae000 000002f0
|
||||||
|
0x0bc3f038: 0bc3f060 77cfb071 00000000 00000000
|
||||||
|
0x0bc3f048: 00000000 0b946e80 00000000 00000004
|
||||||
|
0x0bc3f058: 00000000 00000001 0bc3f0f0 20b0447e
|
||||||
|
|
||||||
|
Instructions: (pc=0x77cfb15f)
|
||||||
|
0x77cfb14f: ff 33 c0 89 45 0c 89 45 08 8b 06 83 f8 ff 74 04
|
||||||
|
0x77cfb15f: 83 40 14 01 8b 5d f4 8b 7d f0 90 80 3d 82 03 fe
|
||||||
|
|
||||||
|
|
||||||
|
Stack: [0x0bbf0000,0x0bc40000), sp=0x0bc3efe8, free space=315k
|
||||||
|
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
|
||||||
|
C [ntdll.dll+0x3b15f]
|
||||||
|
C [ntdll.dll+0x3b071]
|
||||||
|
C [imon.dll+0x447e]
|
||||||
|
|
||||||
|
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
|
||||||
|
j java.net.SocketInputStream.socketRead0(Ljava/io/FileDescriptor;[BIII)I+0
|
||||||
|
j java.net.SocketInputStream.read([BII)I+84
|
||||||
|
j java.io.BufferedInputStream.fill()V+175
|
||||||
|
J java.io.BufferedInputStream.read()I
|
||||||
|
j java.io.DataInputStream.readByte()B+4
|
||||||
|
j org.eclipse.jem.internal.proxy.vm.remote.ConnectionHandler.run()Ljava/lang/Object;+54
|
||||||
|
j org.eclipse.jem.internal.proxy.vm.remote.ConnectionThread.run()V+4
|
||||||
|
v ~StubRoutines::call_stub
|
||||||
|
|
||||||
|
--------------- P R O C E S S ---------------
|
||||||
|
|
||||||
|
Java Threads: ( => current thread )
|
||||||
|
0x0be61000 JavaThread "AWT-Windows" daemon [_thread_in_native, id=1640]
|
||||||
|
0x0be4ac00 JavaThread "Java2D Disposer" daemon [_thread_blocked, id=3032]
|
||||||
|
=>0x0b570400 JavaThread "Connection Thread" [_thread_in_native, id=5336]
|
||||||
|
0x0148ec00 JavaThread "Server Thread-Project (ZUtil)-Beaninfo" [_thread_blocked, id=5880]
|
||||||
|
0x01448800 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=5052]
|
||||||
|
0x01433c00 JavaThread "CompilerThread0" daemon [_thread_blocked, id=4504]
|
||||||
|
0x01432800 JavaThread "Attach Listener" daemon [_thread_blocked, id=3072]
|
||||||
|
0x01432400 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=704]
|
||||||
|
0x01424800 JavaThread "Finalizer" daemon [_thread_blocked, id=4056]
|
||||||
|
0x01418400 JavaThread "Reference Handler" daemon [_thread_blocked, id=4536]
|
||||||
|
0x01388800 JavaThread "main" [_thread_blocked, id=340]
|
||||||
|
|
||||||
|
Other Threads:
|
||||||
|
0x01414000 VMThread [id=4904]
|
||||||
|
0x0144a800 WatcherThread [id=2452]
|
||||||
|
|
||||||
|
VM state:not at safepoint (normal execution)
|
||||||
|
|
||||||
|
VM Mutex/Monitor currently owned by a thread: None
|
||||||
|
|
||||||
|
Heap
|
||||||
|
def new generation total 960K, used 840K [0x03490000, 0x03590000, 0x03970000)
|
||||||
|
eden space 896K, 86% used [0x03490000, 0x03552328, 0x03570000)
|
||||||
|
from space 64K, 100% used [0x03570000, 0x03580000, 0x03580000)
|
||||||
|
to space 64K, 0% used [0x03580000, 0x03580000, 0x03590000)
|
||||||
|
tenured generation total 4096K, used 973K [0x03970000, 0x03d70000, 0x07490000)
|
||||||
|
the space 4096K, 23% used [0x03970000, 0x03a63430, 0x03a63600, 0x03d70000)
|
||||||
|
compacting perm gen total 12288K, used 5126K [0x07490000, 0x08090000, 0x0b490000)
|
||||||
|
the space 12288K, 41% used [0x07490000, 0x07991a68, 0x07991c00, 0x08090000)
|
||||||
|
No shared spaces configured.
|
||||||
|
|
||||||
|
Dynamic libraries:
|
||||||
|
0x00400000 - 0x00423000 C:\Program Files\Java\jre1.6.0_03\bin\javaw.exe
|
||||||
|
0x77cc0000 - 0x77dde000 C:\Windows\system32\ntdll.dll
|
||||||
|
0x774d0000 - 0x775a8000 C:\Windows\system32\kernel32.dll
|
||||||
|
0x76890000 - 0x7694f000 C:\Windows\system32\ADVAPI32.dll
|
||||||
|
0x77630000 - 0x776f3000 C:\Windows\system32\RPCRT4.dll
|
||||||
|
0x77910000 - 0x779ae000 C:\Windows\system32\USER32.dll
|
||||||
|
0x76710000 - 0x7675b000 C:\Windows\system32\GDI32.dll
|
||||||
|
0x77e00000 - 0x77e1e000 C:\Windows\system32\IMM32.DLL
|
||||||
|
0x77bf0000 - 0x77cb7000 C:\Windows\system32\MSCTF.dll
|
||||||
|
0x77b40000 - 0x77bea000 C:\Windows\system32\msvcrt.dll
|
||||||
|
0x77e20000 - 0x77e29000 C:\Windows\system32\LPK.DLL
|
||||||
|
0x76600000 - 0x7667d000 C:\Windows\system32\USP10.dll
|
||||||
|
0x10000000 - 0x10015000 C:\Windows\system32\APSHook.dll
|
||||||
|
0x76950000 - 0x769a5000 C:\Windows\system32\SHLWAPI.dll
|
||||||
|
0x76400000 - 0x76408000 C:\Windows\system32\VERSION.dll
|
||||||
|
0x76570000 - 0x76577000 C:\Windows\system32\PSAPI.DLL
|
||||||
|
0x76000000 - 0x76194000 C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.6000.16386_none_5d07289e07e1d100\comctl32.dll
|
||||||
|
0x7c340000 - 0x7c396000 C:\Program Files\Java\jre1.6.0_03\bin\msvcr71.dll
|
||||||
|
0x6d7c0000 - 0x6da0a000 C:\Program Files\Java\jre1.6.0_03\bin\client\jvm.dll
|
||||||
|
0x75730000 - 0x75763000 C:\Windows\system32\WINMM.dll
|
||||||
|
0x777c0000 - 0x77904000 C:\Windows\system32\ole32.dll
|
||||||
|
0x76680000 - 0x7670c000 C:\Windows\system32\OLEAUT32.dll
|
||||||
|
0x756f0000 - 0x75728000 C:\Windows\system32\OLEACC.dll
|
||||||
|
0x763a0000 - 0x763cc000 C:\Windows\system32\apphelp.dll
|
||||||
|
0x6d310000 - 0x6d318000 C:\Program Files\Java\jre1.6.0_03\bin\hpi.dll
|
||||||
|
0x6d770000 - 0x6d77c000 C:\Program Files\Java\jre1.6.0_03\bin\verify.dll
|
||||||
|
0x6d3b0000 - 0x6d3cf000 C:\Program Files\Java\jre1.6.0_03\bin\java.dll
|
||||||
|
0x6d7b0000 - 0x6d7bf000 C:\Program Files\Java\jre1.6.0_03\bin\zip.dll
|
||||||
|
0x6d570000 - 0x6d583000 C:\Program Files\Java\jre1.6.0_03\bin\net.dll
|
||||||
|
0x765d0000 - 0x765fd000 C:\Windows\system32\WS2_32.dll
|
||||||
|
0x77df0000 - 0x77df6000 C:\Windows\system32\NSI.dll
|
||||||
|
0x20b00000 - 0x20b4b000 C:\Windows\system32\imon.dll
|
||||||
|
0x75ad0000 - 0x75ad7000 C:\Windows\system32\WSOCK32.dll
|
||||||
|
0x75a60000 - 0x75a9b000 C:\Windows\system32\mswsock.dll
|
||||||
|
0x75ac0000 - 0x75ac6000 C:\Windows\System32\wship6.dll
|
||||||
|
0x75690000 - 0x75696000 C:\Windows\System32\wshtcpip.dll
|
||||||
|
0x754f0000 - 0x754ff000 C:\Windows\system32\NLAapi.dll
|
||||||
|
0x75c90000 - 0x75ca9000 C:\Windows\system32\IPHLPAPI.DLL
|
||||||
|
0x75c50000 - 0x75c85000 C:\Windows\system32\dhcpcsvc.DLL
|
||||||
|
0x75ec0000 - 0x75eeb000 C:\Windows\system32\DNSAPI.dll
|
||||||
|
0x76410000 - 0x76424000 C:\Windows\system32\Secur32.dll
|
||||||
|
0x75c40000 - 0x75c47000 C:\Windows\system32\WINNSI.DLL
|
||||||
|
0x75c20000 - 0x75c40000 C:\Windows\system32\dhcpcsvc6.DLL
|
||||||
|
0x73360000 - 0x73368000 C:\Windows\System32\winrnr.dll
|
||||||
|
0x77480000 - 0x774c9000 C:\Windows\system32\WLDAP32.dll
|
||||||
|
0x73350000 - 0x7335f000 C:\Windows\system32\napinsp.dll
|
||||||
|
0x73330000 - 0x73342000 C:\Windows\system32\pnrpnsp.dll
|
||||||
|
0x73320000 - 0x7332c000 C:\Windows\system32\wshbth.dll
|
||||||
|
0x779b0000 - 0x77b39000 C:\Windows\system32\SETUPAPI.dll
|
||||||
|
0x733f0000 - 0x733f6000 C:\Windows\system32\rasadhlp.dll
|
||||||
|
0x6d000000 - 0x6d1c3000 C:\Program Files\Java\jre1.6.0_03\bin\awt.dll
|
||||||
|
0x73750000 - 0x73791000 C:\Windows\system32\WINSPOOL.DRV
|
||||||
|
0x74350000 - 0x7438f000 C:\Windows\system32\uxtheme.dll
|
||||||
|
0x01180000 - 0x01198000 c:\Program Files\Bioscrypt\VeriSoft\Bin\ItClient.dll
|
||||||
|
0x74980000 - 0x74a06000 C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_5.82.6000.16386_none_87e0cb09378714f1\Comctl32.dll
|
||||||
|
0x73010000 - 0x7301c000 C:\Windows\system32\dwmapi.dll
|
||||||
|
|
||||||
|
VM Arguments:
|
||||||
|
jvm_args: -Dproxyvm.registryKey=11131376 -Dproxyvm.masterPort=54959 -Dproxyvm.bufsize=16000 -Dproxyvm.servername=Project (ZUtil)-Beaninfo -Xverify:none
|
||||||
|
java_command: org.eclipse.jem.internal.proxy.vm.remote.RemoteVMApplication
|
||||||
|
Launcher Type: SUN_STANDARD
|
||||||
|
|
||||||
|
Environment Variables:
|
||||||
|
CLASSPATH=.;C:\Program Files\Java\jre1.6.0_03\lib\ext\QTJava.zip
|
||||||
|
PATH=C:\Program Files\Java\jre1.6.0_03\bin\client;C:\Program Files\Java\jre1.6.0_03\bin;C:\Windows\system32;C:\Windows;C:\Windows\system32\wbem;c:\program files\common files\roxio shared\dllshared\;c:\program files\common files\roxio shared\dllshared\;c:\program files\common files\roxio shared\9.0\dllshared\;c:\program files\bioscrypt\verisoft\bin;C:\Program Files\MATLAB\R2007a\bin;C:\Program Files\MATLAB\R2007a\bin\win32;C:\Program\Dev-Cpp\libexec\gcc\mingw32\3.4.2;C:\Program Files\Smart Projects\IsoBuster;C:\Program Files\Autodesk\Backburner\;C:\Program Files\Common Files\Autodesk Shared\;C:\Program Files\Java\jdk1.6.0_02\bin;C:\Program Files\QuickTime\QTSystem\
|
||||||
|
USERNAME=Ziver
|
||||||
|
OS=Windows_NT
|
||||||
|
PROCESSOR_IDENTIFIER=x86 Family 6 Model 15 Stepping 10, GenuineIntel
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--------------- S Y S T E M ---------------
|
||||||
|
|
||||||
|
OS: Windows Vista Build 6000
|
||||||
|
|
||||||
|
CPU:total 2 (2 cores per cpu, 1 threads per core) family 6 model 15 stepping 10, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3
|
||||||
|
|
||||||
|
Memory: 4k page, physical 2094912k(757952k free), swap 4194303k(1884172k free)
|
||||||
|
|
||||||
|
vm_info: Java HotSpot(TM) Client VM (1.6.0_03-b05) for windows-x86, built on Sep 24 2007 22:24:33 by "java_re" with unknown MS VC++:1310
|
||||||
|
|
||||||
BIN
libs/mysql-connector-java-5.0.7-bin.jar
Normal file
BIN
libs/mysql-connector-java-5.0.7-bin.jar
Normal file
Binary file not shown.
69
src/zutil/Converter.java
Normal file
69
src/zutil/Converter.java
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
package zutil;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
|
||||||
|
public class Converter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an object to an array of bytes.
|
||||||
|
*
|
||||||
|
* @param object the object to convert.
|
||||||
|
* @return the associated byte array.
|
||||||
|
*/
|
||||||
|
public static byte[] toBytes(Object object){
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try{
|
||||||
|
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||||
|
oos.writeObject(object);
|
||||||
|
oos.flush();
|
||||||
|
oos.close();
|
||||||
|
}catch(IOException ioe){
|
||||||
|
System.out.println(ioe.getMessage());
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an array of bytes back to its constituent object. The
|
||||||
|
* input array is assumed to have been created from the original object.
|
||||||
|
*
|
||||||
|
* @param bytes the byte array to convert.
|
||||||
|
* @return the associated object.
|
||||||
|
*/
|
||||||
|
public static Object toObject(byte[] bytes) {
|
||||||
|
Object object = null;
|
||||||
|
try{
|
||||||
|
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||||
|
ObjectInputStream ois= new ObjectInputStream(bais);
|
||||||
|
object = ois.readObject();
|
||||||
|
ois.close();
|
||||||
|
bais.close();
|
||||||
|
}catch(IOException ioe){
|
||||||
|
System.out.println(ioe.getMessage());
|
||||||
|
}catch(ClassNotFoundException cnfe){
|
||||||
|
System.out.println(cnfe.getMessage());
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given interface is implemented in the object
|
||||||
|
* @param object The object to look for the interface
|
||||||
|
* @param interf The interface to look for
|
||||||
|
* @return True if the interface is implemented else false
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static boolean isInstanceOf(Object object, Class interf){
|
||||||
|
Class[] objectInterf = object.getClass().getInterfaces();
|
||||||
|
for(int i=0; i<objectInterf.length ;i++){
|
||||||
|
if(objectInterf[i] == interf){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
184
src/zutil/Encrypter.java
Normal file
184
src/zutil/Encrypter.java
Normal file
|
|
@ -0,0 +1,184 @@
|
||||||
|
package zutil;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.Provider;
|
||||||
|
import java.security.Security;
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import java.security.spec.KeySpec;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.CipherInputStream;
|
||||||
|
import javax.crypto.CipherOutputStream;
|
||||||
|
import javax.crypto.KeyGenerator;
|
||||||
|
import javax.crypto.NoSuchPaddingException;
|
||||||
|
import javax.crypto.SecretKeyFactory;
|
||||||
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
|
import javax.crypto.spec.PBEParameterSpec;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic symmetric encryption example
|
||||||
|
*/
|
||||||
|
public class Encrypter {
|
||||||
|
public static final String BLOWFISH_ALGO = "Blowfish";
|
||||||
|
public static final String DES_ALGO = "DES";
|
||||||
|
public static final String DESEDE_ALGO = "DESede";
|
||||||
|
public static final String TRIPLEDES_ALGO = "TripleDES";
|
||||||
|
public static final String PASSPHRASE_TOWFISH_ALGO = "PBEWithSHAAndTwofish-CBC";
|
||||||
|
public static final String PASSPHRASE_TRIPLEDES_ALGO = "PBEWithMD5AndTripleDES";
|
||||||
|
public static final String PASSPHRASE_DES_ALGO = "PBEWithMD5AndDES";
|
||||||
|
|
||||||
|
// 8-byte Salt
|
||||||
|
public static byte[] salt = {
|
||||||
|
(byte)0xA9, (byte)0x9B, (byte)0xC8, (byte)0x32,
|
||||||
|
(byte)0x56, (byte)0x35, (byte)0xE3, (byte)0x03
|
||||||
|
};
|
||||||
|
// Iteration count
|
||||||
|
public static int iterationCount = 19;
|
||||||
|
|
||||||
|
private Cipher encipher;
|
||||||
|
private Cipher decipher;
|
||||||
|
private Key key;
|
||||||
|
private AlgorithmParameterSpec paramSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a random key
|
||||||
|
* @param algorithm The algorithm to use
|
||||||
|
*/
|
||||||
|
public Encrypter(String algorithm) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException{
|
||||||
|
KeyGenerator keygenerator = KeyGenerator.getInstance(algorithm);
|
||||||
|
|
||||||
|
key = keygenerator.generateKey();
|
||||||
|
encipher = Cipher.getInstance(key.getAlgorithm());
|
||||||
|
decipher = Cipher.getInstance(key.getAlgorithm());
|
||||||
|
encipher.init(Cipher.ENCRYPT_MODE, key);
|
||||||
|
decipher.init(Cipher.DECRYPT_MODE, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses the given key for encryption
|
||||||
|
* @param key The key to use
|
||||||
|
*/
|
||||||
|
public Encrypter(Key key) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException{
|
||||||
|
this.key = key;
|
||||||
|
encipher = Cipher.getInstance(key.getAlgorithm());
|
||||||
|
decipher = Cipher.getInstance(key.getAlgorithm());
|
||||||
|
encipher.init(Cipher.ENCRYPT_MODE, key);
|
||||||
|
decipher.init(Cipher.DECRYPT_MODE, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a encrypter with a passphrase
|
||||||
|
*
|
||||||
|
* @param stringKey The pass
|
||||||
|
* @param algorithm The algoritm to use
|
||||||
|
*/
|
||||||
|
public Encrypter(String stringKey, String algorithm) throws NoSuchAlgorithmException{
|
||||||
|
try {
|
||||||
|
// Install SunJCE provider
|
||||||
|
Provider sunJce = new com.sun.crypto.provider.SunJCE();
|
||||||
|
Security.addProvider(sunJce);
|
||||||
|
|
||||||
|
// Generate the secret key specs.
|
||||||
|
KeySpec keySpec = new PBEKeySpec(stringKey.toCharArray());
|
||||||
|
|
||||||
|
key = SecretKeyFactory.getInstance(algorithm).generateSecret(keySpec);
|
||||||
|
paramSpec = new PBEParameterSpec(salt, iterationCount);
|
||||||
|
|
||||||
|
encipher = Cipher.getInstance(key.getAlgorithm());
|
||||||
|
decipher = Cipher.getInstance(key.getAlgorithm());
|
||||||
|
encipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
|
||||||
|
decipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts the given data
|
||||||
|
*
|
||||||
|
* @param data Data to encrypt
|
||||||
|
* @return The encrypted data
|
||||||
|
*/
|
||||||
|
public byte[] encrypt(byte[] data){
|
||||||
|
try {
|
||||||
|
byte[] encryption = new byte[encipher.getOutputSize(data.length)];
|
||||||
|
int ctLength = encipher.update(data, 0, data.length, encryption, 0);
|
||||||
|
|
||||||
|
ctLength += encipher.doFinal(encryption, ctLength);
|
||||||
|
return encryption;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds encryption to the OutputStream
|
||||||
|
* @param out The OutputStream to enable encryption on
|
||||||
|
* @return A new encrypted OutputStream
|
||||||
|
*/
|
||||||
|
public OutputStream encrypt(OutputStream out) {
|
||||||
|
// Bytes written to out will be encrypted
|
||||||
|
return new CipherOutputStream(out, encipher);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts encrypted data
|
||||||
|
* @param encrypted The encrypted data
|
||||||
|
* @return The decrypted data
|
||||||
|
*/
|
||||||
|
public byte[] decrypt(byte[] encrypted){
|
||||||
|
try {
|
||||||
|
byte[] dataTmp = new byte[encrypted.length];
|
||||||
|
int ptLength = decipher.update(encrypted, 0, encrypted.length, dataTmp, 0);
|
||||||
|
ptLength += decipher.doFinal(dataTmp, ptLength);
|
||||||
|
|
||||||
|
byte[] data = new byte[ptLength];
|
||||||
|
System.arraycopy(dataTmp, 0, data, 0, ptLength);
|
||||||
|
return data;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds decryption to the InputStream
|
||||||
|
* @param in The InputStream to enable decryption on
|
||||||
|
* @return A new decrypted InputStream
|
||||||
|
*/
|
||||||
|
public InputStream decrypt(InputStream in) {
|
||||||
|
// Bytes read from in will be decrypted
|
||||||
|
return new CipherInputStream(in, decipher);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The key for this encrypter
|
||||||
|
*/
|
||||||
|
public Key getKey(){
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The algorithm used by this encrypter
|
||||||
|
*/
|
||||||
|
public String getAlgorithm(){
|
||||||
|
return key.getAlgorithm();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Randomizes the salt for the key
|
||||||
|
*/
|
||||||
|
public static void randomizeSalt(){
|
||||||
|
Random random = new Random();
|
||||||
|
random.nextBytes(salt);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/zutil/FileChangeListener.java
Normal file
19
src/zutil/FileChangeListener.java
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
package zutil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for the FileWatcher class
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
public interface FileChangeListener{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called when there is a change in
|
||||||
|
* a file
|
||||||
|
*
|
||||||
|
* @param file The file that has changed
|
||||||
|
*/
|
||||||
|
public void fileChangedEvent(File file);
|
||||||
|
}
|
||||||
121
src/zutil/FileFinder.java
Normal file
121
src/zutil/FileFinder.java
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
package zutil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File path utilities
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
public class FileFinder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a String with a relative path from the given path
|
||||||
|
*
|
||||||
|
* @param file The file to get a relative path from
|
||||||
|
* @param path The path
|
||||||
|
* @return A String with a relative path
|
||||||
|
*/
|
||||||
|
public static String relativePath(File file, String path){
|
||||||
|
String absolute = file.getAbsolutePath();
|
||||||
|
String tmpPath = path.replaceAll(
|
||||||
|
"[/\\\\]",
|
||||||
|
Matcher.quoteReplacement(File.separator));
|
||||||
|
|
||||||
|
String relative = absolute.substring(
|
||||||
|
absolute.indexOf(tmpPath)+path.length(),
|
||||||
|
absolute.length());
|
||||||
|
return relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the File object for the given file
|
||||||
|
*
|
||||||
|
* @param path The path to the file (no / if not absolute path)
|
||||||
|
* @return A File object for the file
|
||||||
|
* @throws URISyntaxException
|
||||||
|
*/
|
||||||
|
public static File find(String path){
|
||||||
|
try {
|
||||||
|
File file = new File(path);
|
||||||
|
if(file!=null && file.exists()){
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
return new File(findURL(path).toURI());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the URL to the given file
|
||||||
|
*
|
||||||
|
* @param path The path to the file (no / if not absolute path)
|
||||||
|
* @return A URL object for the file
|
||||||
|
* @throws URISyntaxException
|
||||||
|
*/
|
||||||
|
public static URL findURL(String path){
|
||||||
|
return FileFinder.class.getClassLoader().getResource(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a ArrayList with all the files in a folder and sub folders
|
||||||
|
*
|
||||||
|
* @param dir The directory to search in
|
||||||
|
* @return The ArrayList with the files
|
||||||
|
*/
|
||||||
|
public static ArrayList<File> search(File dir){
|
||||||
|
return search(dir, new ArrayList<File>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a ArrayList with all the files in a folder and sub folders
|
||||||
|
*
|
||||||
|
* @param dir The directory to search in
|
||||||
|
* @param fileList The ArrayList to add the files to
|
||||||
|
* @return The ArrayList with the files
|
||||||
|
*/
|
||||||
|
public static ArrayList<File> search(File dir, ArrayList<File> fileList){
|
||||||
|
String[] temp = dir.list();
|
||||||
|
File file;
|
||||||
|
|
||||||
|
for(int i=0; i<temp.length ;i++){
|
||||||
|
file = new File(dir.getPath()+File.separator+temp[i]);
|
||||||
|
if(file.isDirectory()){
|
||||||
|
search(new File(dir.getPath()+File.separator+temp[i]+File.separator),fileList);
|
||||||
|
}
|
||||||
|
else if(file.isFile()){
|
||||||
|
MultiPrintStream.out.println("File Found: "+file);
|
||||||
|
fileList.add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the extension of the file
|
||||||
|
* @param file The file
|
||||||
|
* @return The extension
|
||||||
|
*/
|
||||||
|
public static String fileExtension(File file){
|
||||||
|
return fileExtension(file.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the extension of the file
|
||||||
|
* @param file The file
|
||||||
|
* @return The extension
|
||||||
|
*/
|
||||||
|
public static String fileExtension(String file){
|
||||||
|
if(file.lastIndexOf(".")==-1)
|
||||||
|
return "";
|
||||||
|
return file.substring(file.lastIndexOf(".")+1,file.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
63
src/zutil/FileWatcher.java
Normal file
63
src/zutil/FileWatcher.java
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
package zutil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class calls a given listener
|
||||||
|
* when a file is changed
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class FileWatcher extends TimerTask{
|
||||||
|
private FileChangeListener listener;
|
||||||
|
private long lastChanged;
|
||||||
|
private File file;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a watcher for the given file whit the check
|
||||||
|
* interval of 1 second
|
||||||
|
*
|
||||||
|
* @param file The file to check
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
*/
|
||||||
|
public FileWatcher(File file) throws FileNotFoundException{
|
||||||
|
this(file, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a watcher for the given file whit the given
|
||||||
|
* check interval
|
||||||
|
*
|
||||||
|
* @param file The file
|
||||||
|
* @param intervall The interval
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
*/
|
||||||
|
public FileWatcher(File file, int intervall) throws FileNotFoundException{
|
||||||
|
if(file==null || !file.exists()) throw new FileNotFoundException("File not found: "+file);
|
||||||
|
this.file = file;
|
||||||
|
lastChanged = file.lastModified();
|
||||||
|
|
||||||
|
Timer t = new Timer(true);
|
||||||
|
t.schedule(this, 0, intervall);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setListener(FileChangeListener listener){
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (lastChanged != file.lastModified()) {
|
||||||
|
lastChanged = file.lastModified();
|
||||||
|
if(listener != null){
|
||||||
|
listener.fileChangedEvent(file);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
MultiPrintStream.out.println("File Changed: "+file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/zutil/Hasher.java
Normal file
64
src/zutil/Hasher.java
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
package zutil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import sun.misc.BASE64Encoder;
|
||||||
|
|
||||||
|
public class Hasher {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a hash of a file
|
||||||
|
*
|
||||||
|
* @param file The path to the file
|
||||||
|
* @param hashType The hash type
|
||||||
|
* @return A String with the hash
|
||||||
|
* @throws NoSuchAlgorithmException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static String hash(File file, String hashType) throws NoSuchAlgorithmException, IOException {
|
||||||
|
MessageDigest digest = MessageDigest.getInstance(hashType);//"MD5"
|
||||||
|
InputStream is = new FileInputStream(file);
|
||||||
|
String output = "";
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int read = 0;
|
||||||
|
try {
|
||||||
|
while( (read = is.read(buffer)) > 0) {
|
||||||
|
digest.update(buffer, 0, read);
|
||||||
|
}
|
||||||
|
byte[] md5sum = digest.digest();
|
||||||
|
BigInteger bigInt = new BigInteger(1, md5sum);
|
||||||
|
output = bigInt.toString(16);
|
||||||
|
}
|
||||||
|
catch(IOException e) {
|
||||||
|
throw new RuntimeException("Unable to process file for MD5", e);
|
||||||
|
}
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
MultiPrintStream.out.println("File Hash: "+output);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hash of the given object
|
||||||
|
*
|
||||||
|
* @param object The object to hash
|
||||||
|
* @param hashType The hash method
|
||||||
|
* @return String containing the hash
|
||||||
|
* @throws NoSuchAlgorithmException
|
||||||
|
*/
|
||||||
|
public static String hash(Serializable object, String hashType) throws NoSuchAlgorithmException {
|
||||||
|
MessageDigest md = null;
|
||||||
|
md = MessageDigest.getInstance(hashType); //MD5 || SHA
|
||||||
|
md.update(Converter.toBytes(object));
|
||||||
|
|
||||||
|
byte raw[] = md.digest();
|
||||||
|
return (new BASE64Encoder()).encode(raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/zutil/History.java
Normal file
59
src/zutil/History.java
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
package zutil;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
public class History<T> {
|
||||||
|
public int history_length = 10;
|
||||||
|
private LinkedList<T> history;
|
||||||
|
private int historyIndex = 0;
|
||||||
|
|
||||||
|
public History(int histlength){
|
||||||
|
history_length = histlength;
|
||||||
|
history = new LinkedList<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToHistory(T url){
|
||||||
|
while(historyIndex < history.size()-1){
|
||||||
|
history.removeLast();
|
||||||
|
}
|
||||||
|
history.addLast(url);
|
||||||
|
if(history_length < history.size()){
|
||||||
|
history.removeFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
historyIndex = history.size()-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getBackHistory(){
|
||||||
|
if(historyIndex > 0){
|
||||||
|
historyIndex -= 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
historyIndex = 0;
|
||||||
|
}
|
||||||
|
return history.get(historyIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getForwHistory(){
|
||||||
|
if(forwHistoryExist()){
|
||||||
|
historyIndex += 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
historyIndex = history.size()-1;
|
||||||
|
}
|
||||||
|
return history.get(historyIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getCurrentHistory(){
|
||||||
|
return history.get(historyIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean forwHistoryExist(){
|
||||||
|
if(historyIndex < history.size()-1){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
309
src/zutil/MultiPrintStream.java
Normal file
309
src/zutil/MultiPrintStream.java
Normal file
|
|
@ -0,0 +1,309 @@
|
||||||
|
package zutil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ziver
|
||||||
|
* this class can print strings to multiple PrintStreams
|
||||||
|
*/
|
||||||
|
public class MultiPrintStream extends PrintStream {
|
||||||
|
//the print streams that will print
|
||||||
|
private ArrayList<PrintStream> streams;
|
||||||
|
// the stream should print time stamp
|
||||||
|
private boolean timeStamp = false;
|
||||||
|
//The timestamp style
|
||||||
|
private String timeStampString = "yyyy-MM-dd HH:mm:ss:SSS# ";
|
||||||
|
//a instance of this class
|
||||||
|
public static MultiPrintStream out = new MultiPrintStream();
|
||||||
|
|
||||||
|
public MultiPrintStream(){
|
||||||
|
super(new PrintStream(System.out));
|
||||||
|
streams = new ArrayList<PrintStream>();
|
||||||
|
streams.add(new PrintStream(System.out));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this constructor makes a simple PrintStream that prints to the console and to a file
|
||||||
|
* @param file the file name to output to
|
||||||
|
*/
|
||||||
|
public MultiPrintStream(String file){
|
||||||
|
super(new PrintStream(System.out));
|
||||||
|
try {
|
||||||
|
streams = new ArrayList<PrintStream>();
|
||||||
|
streams.add(new PrintStream(System.out));
|
||||||
|
streams.add(new PrintStream(new File(file)));
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
System.out.println("Error when declaring PrintStream!!");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this constructor takes a array of PrintStreams to be used
|
||||||
|
* @param streams a array of the streams that will be used
|
||||||
|
*/
|
||||||
|
public MultiPrintStream(PrintStream[] streams){
|
||||||
|
super(streams[0]);
|
||||||
|
this.streams = new ArrayList<PrintStream>();
|
||||||
|
for(int i=0; i<streams.length ;i++){
|
||||||
|
this.streams.add(streams[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this constructor takes a array of PrintStreams to be used
|
||||||
|
* @param streams a array of the streams that will be used
|
||||||
|
*/
|
||||||
|
public static void makeInstance(MultiPrintStream instanceStream){
|
||||||
|
out = instanceStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a printstream to the list pf streams
|
||||||
|
* @param p The Printstream to add
|
||||||
|
*/
|
||||||
|
public void addPrintStream(PrintStream p){
|
||||||
|
streams.add(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a printstream from the list
|
||||||
|
* @param p The PrintStream to remove
|
||||||
|
*/
|
||||||
|
public void removePrintStream(PrintStream p){
|
||||||
|
streams.remove(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a printstream from the list
|
||||||
|
* @param p The index of the PrintStream to remove
|
||||||
|
*/
|
||||||
|
public void removePrintStream(int p){
|
||||||
|
streams.remove(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prints whit a new line to all the PrintStreams
|
||||||
|
*/
|
||||||
|
public void println(String s){
|
||||||
|
if(!s.equals(""))s = getTime() + s;
|
||||||
|
for(int i=0; i<streams.size() ;i++)
|
||||||
|
streams.get(i).println(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prints to all the PrintStreams
|
||||||
|
*/
|
||||||
|
public void print(String s){
|
||||||
|
for(int i=0; i<streams.size() ;i++)
|
||||||
|
streams.get(i).print(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void println(){ println("");}
|
||||||
|
public void println(boolean x){ println(""+x);}
|
||||||
|
public void println(char x){ println(""+x);}
|
||||||
|
public void println(char[] x){ println(new String(x));}
|
||||||
|
public void println(double x){ println(""+x);}
|
||||||
|
public void println(float x){ println(""+x);}
|
||||||
|
public void println(int x){ println(""+x);}
|
||||||
|
public void println(long x){ println(""+x);}
|
||||||
|
public void println(Object x){ println(""+x);}
|
||||||
|
|
||||||
|
public void print(boolean x){ print(""+x);}
|
||||||
|
public void print(char x){ print(""+x);}
|
||||||
|
public void print(char[] x){ print(new String(x));}
|
||||||
|
public void print(double x){ print(""+x);}
|
||||||
|
public void print(float x){ print(""+x);}
|
||||||
|
public void print(int x){ print(""+x);}
|
||||||
|
public void print(long x){ print(""+x);}
|
||||||
|
public void print(Object x){ print(""+x);}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the streams should print timestamp in front
|
||||||
|
* of the msgs
|
||||||
|
* @param enable True to activate
|
||||||
|
*/
|
||||||
|
public void printTimeStamp(boolean enable){
|
||||||
|
timeStamp = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DateFormat to print in the time stamp
|
||||||
|
* @param ts String to send to SimpleDateFormat
|
||||||
|
*/
|
||||||
|
public void setTimeStamp(String ts){
|
||||||
|
timeStampString = ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTime(){
|
||||||
|
if(timeStamp)
|
||||||
|
return "" + (new SimpleDateFormat(timeStampString)).format(new java.util.Date());
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkError(){
|
||||||
|
for(int i=0; i<streams.size() ;i++)
|
||||||
|
if(streams.get(i).checkError())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* closes all the PrintStreams
|
||||||
|
*/
|
||||||
|
public void close(){
|
||||||
|
for(int i=0; i<streams.size() ;i++)
|
||||||
|
streams.get(i).close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps the content of:
|
||||||
|
* - Array content
|
||||||
|
* - Map content (HashMap etc.)
|
||||||
|
* - List content (ArrayList, LinkedList etc.)
|
||||||
|
* - InputStream content (Prints out until the end of the stream)
|
||||||
|
* - Reader content (Prints out until the end of the reader)
|
||||||
|
* - Instance variables of a Object
|
||||||
|
*
|
||||||
|
* @param o The Object to dump
|
||||||
|
* @return A String with all the printed data
|
||||||
|
*/
|
||||||
|
public String dump( Object o ){
|
||||||
|
return dump( o , true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps the content of:
|
||||||
|
* <br>- Array content
|
||||||
|
* <br>- Map content (HashMap etc.)
|
||||||
|
* <br>- List content (ArrayList, LinkedList etc.)
|
||||||
|
* <br>- InputStream content (Prints out until the end of the stream)
|
||||||
|
* <br>- Reader content (Prints out until the end of the reader)
|
||||||
|
* <br>- Instance variables of a Object
|
||||||
|
*
|
||||||
|
* @param o The Object to dump
|
||||||
|
* @param print If the method should print the data or just return it
|
||||||
|
* @return A String with all the printed data
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private String dump( Object o , boolean print) {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
Class oClass = o.getClass();
|
||||||
|
buffer.append( oClass.getName() );
|
||||||
|
// Prints out Arrays
|
||||||
|
if ( oClass.isArray() ) {
|
||||||
|
buffer.append( "[" );
|
||||||
|
for ( int i=0; i<Array.getLength(o) ;i++ ) {
|
||||||
|
if ( i > 0 )
|
||||||
|
buffer.append( ", " );
|
||||||
|
Object value = Array.get(o,i);
|
||||||
|
buffer.append( (dumbCapable(value) ? dump(value,false) : value) );
|
||||||
|
}
|
||||||
|
buffer.append( "]" );
|
||||||
|
}
|
||||||
|
// Prints out a list
|
||||||
|
else if(o instanceof Collection){
|
||||||
|
Iterator it = ((Collection)o).iterator();
|
||||||
|
buffer.append( "{" );
|
||||||
|
while(it.hasNext()){
|
||||||
|
Object value = it.next();
|
||||||
|
buffer.append( (dumbCapable(value) ? dump(value,false) : value) );
|
||||||
|
if(it.hasNext())
|
||||||
|
buffer.append( ", " );
|
||||||
|
}
|
||||||
|
buffer.append( "}" );
|
||||||
|
}
|
||||||
|
// Prints out a Map
|
||||||
|
else if(o instanceof Map){
|
||||||
|
Iterator it = ((Map)o).keySet().iterator();
|
||||||
|
buffer.append( "{" );
|
||||||
|
while(it.hasNext()){
|
||||||
|
Object key = it.next();
|
||||||
|
Object value = ((Map)o).get(key);
|
||||||
|
buffer.append( key );
|
||||||
|
buffer.append( "=>" );
|
||||||
|
buffer.append( (dumbCapable(value) ? dump(value,false) : value) );
|
||||||
|
if(it.hasNext())
|
||||||
|
buffer.append( ", " );
|
||||||
|
}
|
||||||
|
buffer.append( "}" );
|
||||||
|
}
|
||||||
|
// Prints out data from InputStream
|
||||||
|
else if(o instanceof InputStream){
|
||||||
|
buffer.append( " =>{ \n" );
|
||||||
|
try {
|
||||||
|
InputStream in = (InputStream)o;
|
||||||
|
int tmp;
|
||||||
|
while((tmp = in.read()) != -1){
|
||||||
|
buffer.append( (char)tmp );
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace(this);
|
||||||
|
}
|
||||||
|
buffer.append( "\n}" );
|
||||||
|
}
|
||||||
|
// Prints out data from InputStream
|
||||||
|
else if(o instanceof Reader){
|
||||||
|
buffer.append( " =>{ \n" );
|
||||||
|
try {
|
||||||
|
Reader in = (Reader)o;
|
||||||
|
int tmp;
|
||||||
|
while((tmp = in.read()) != -1){
|
||||||
|
buffer.append( (char)tmp );
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace(this);
|
||||||
|
}
|
||||||
|
buffer.append( "\n}" );
|
||||||
|
}
|
||||||
|
// Prints out Object properties
|
||||||
|
else{
|
||||||
|
buffer.append( "{" );
|
||||||
|
while ( oClass != null ) {
|
||||||
|
Field[] fields = oClass.getDeclaredFields();
|
||||||
|
for ( int i=0; i<fields.length; i++ ) {
|
||||||
|
if ( buffer.length() > 1 )
|
||||||
|
buffer.append( ", " );
|
||||||
|
fields[i].setAccessible( true );
|
||||||
|
buffer.append( fields[i].getName() );
|
||||||
|
buffer.append( "=" );
|
||||||
|
try {
|
||||||
|
Object value = fields[i].get(o);
|
||||||
|
if (value != null) {
|
||||||
|
buffer.append( (dumbCapable(value) ? dump(value,false) : value) );
|
||||||
|
}
|
||||||
|
} catch ( IllegalAccessException e ) {}
|
||||||
|
}
|
||||||
|
oClass = oClass.getSuperclass();
|
||||||
|
}
|
||||||
|
buffer.append( "}" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if(print) out.println(buffer.toString());
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean dumbCapable(Object o){
|
||||||
|
if(o.getClass().isArray()) return true;
|
||||||
|
else if(o instanceof Collection)return true;
|
||||||
|
else if(o instanceof Map)return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/zutil/OneApp.java
Normal file
24
src/zutil/OneApp.java
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
package zutil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface is used to look if another instance of the
|
||||||
|
* application is running
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface OneApp {
|
||||||
|
/**
|
||||||
|
* Checks if the application is already running
|
||||||
|
*
|
||||||
|
* @return True if the file is locked else false
|
||||||
|
*/
|
||||||
|
public boolean check();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks the application so that another one can not run
|
||||||
|
*
|
||||||
|
* @return False if there are a error else true
|
||||||
|
*/
|
||||||
|
public boolean lockApp();
|
||||||
|
}
|
||||||
99
src/zutil/OneAppFile.java
Normal file
99
src/zutil/OneAppFile.java
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
package zutil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.channels.FileLock;
|
||||||
|
import java.nio.channels.OverlappingFileLockException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class checks if the application is already running
|
||||||
|
* by Locking a file
|
||||||
|
*
|
||||||
|
* @author Ziver Koc
|
||||||
|
*/
|
||||||
|
public class OneAppFile implements OneApp{
|
||||||
|
private File file;
|
||||||
|
private FileChannel channel;
|
||||||
|
private FileLock lock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a OneApp class
|
||||||
|
*
|
||||||
|
* @param filename The name of the file to be locked
|
||||||
|
*/
|
||||||
|
public OneAppFile(String filename){
|
||||||
|
this.file = new File(System.getProperty("user.home"), filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the file have already bean locked
|
||||||
|
*
|
||||||
|
* @return True if the file is locked else false
|
||||||
|
*/
|
||||||
|
public boolean check() {
|
||||||
|
boolean tmp = lockApp();
|
||||||
|
closeLock();
|
||||||
|
return !tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks the file
|
||||||
|
*
|
||||||
|
* @return False if there are a error else true
|
||||||
|
*/
|
||||||
|
public boolean lockApp() {
|
||||||
|
try {
|
||||||
|
channel = new RandomAccessFile(file, "rw").getChannel();
|
||||||
|
|
||||||
|
try {
|
||||||
|
lock = channel.tryLock();
|
||||||
|
}
|
||||||
|
catch (OverlappingFileLockException e) {
|
||||||
|
// already locked
|
||||||
|
closeLock();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lock == null) {
|
||||||
|
closeLock();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||||
|
// destroy the lock when the JVM is closing
|
||||||
|
public void run() {
|
||||||
|
closeLock();
|
||||||
|
deleteFile();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
closeLock();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeLock() {
|
||||||
|
try {
|
||||||
|
lock.release();
|
||||||
|
channel.close();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteFile() {
|
||||||
|
try {
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
72
src/zutil/OneAppNetwork.java
Normal file
72
src/zutil/OneAppNetwork.java
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
package zutil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class checks if the app is alredy running
|
||||||
|
* by Locking a port
|
||||||
|
*
|
||||||
|
* @author Ziver Koc
|
||||||
|
*/
|
||||||
|
public class OneAppNetwork extends Thread implements OneApp{
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a One App objekt
|
||||||
|
*
|
||||||
|
* @param port The port to lock
|
||||||
|
*/
|
||||||
|
public OneAppNetwork(int port){
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the port lock
|
||||||
|
*
|
||||||
|
* @return Always true
|
||||||
|
*/
|
||||||
|
public boolean lockApp(){
|
||||||
|
this.start();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* he port lock thread
|
||||||
|
* should not be cald outside the class
|
||||||
|
*/
|
||||||
|
public void run() {
|
||||||
|
ServerSocket serverSocket = null;
|
||||||
|
Socket clientSocket = null;
|
||||||
|
try {
|
||||||
|
// Create the server socket
|
||||||
|
serverSocket = new ServerSocket(port, 1);
|
||||||
|
while (true) {
|
||||||
|
// Wait for a connection
|
||||||
|
clientSocket = serverSocket.accept();
|
||||||
|
clientSocket.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ioe) {
|
||||||
|
MultiPrintStream.out.println("Error in JustOneServer: " + ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the port is locked
|
||||||
|
*
|
||||||
|
* @return True if port is locked else false
|
||||||
|
*/
|
||||||
|
public boolean check() {
|
||||||
|
try {
|
||||||
|
Socket clientSocket = new Socket("localhost", port);
|
||||||
|
MultiPrintStream.out.println("Already running!!!");
|
||||||
|
clientSocket.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/zutil/ProgressListener.java
Normal file
18
src/zutil/ProgressListener.java
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
package zutil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface is used in some classes to handle the progress
|
||||||
|
* of some action
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ProgressListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called when the progress is updated
|
||||||
|
* @param source The source object of the progress
|
||||||
|
* @param percent The progress of the object (0-100)
|
||||||
|
*/
|
||||||
|
public void progressUpdate(Object source, Object info, double percent);
|
||||||
|
}
|
||||||
30
src/zutil/StringUtil.java
Normal file
30
src/zutil/StringUtil.java
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
package zutil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a class whit utility methods.
|
||||||
|
*
|
||||||
|
* @author Ziver *
|
||||||
|
*/
|
||||||
|
public class StringUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Present a size (in bytes) as a human-readable value
|
||||||
|
*
|
||||||
|
* @param size size (in bytes)
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static String formatBytesToString(long bytes){
|
||||||
|
String[] sizes = new String[]{"YB", "ZB", "EB", "PB", "TB", "GB", "MB", "kB", "B"};
|
||||||
|
int total = sizes.length-1;
|
||||||
|
double value = bytes;
|
||||||
|
|
||||||
|
for(; value > 1024 ;total--) {
|
||||||
|
value /= 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = (double)( (int)(value*100) )/100;
|
||||||
|
return value+" "+sizes[total];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
68
src/zutil/algo/QuickSelect.java
Normal file
68
src/zutil/algo/QuickSelect.java
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
package zutil.algo;
|
||||||
|
|
||||||
|
import zutil.algo.sort.sortable.SortableDataList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This algorithm is a modified QuickSort
|
||||||
|
* to find the k smallest or biggest value
|
||||||
|
* http://en.wikipedia.org/wiki/Selection_algorithm
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public class QuickSelect {
|
||||||
|
|
||||||
|
public static Object find(SortableDataList list, int k){
|
||||||
|
return find(list, k, 0, list.size()-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
function select(list, k, left, right)
|
||||||
|
select a pivot value list[pivotIndex]
|
||||||
|
pivotNewIndex := partition(list, left, right, pivotIndex)
|
||||||
|
if k = pivotNewIndex
|
||||||
|
return list[k]
|
||||||
|
else if k < pivotNewIndex
|
||||||
|
return select(list, k, left, pivotNewIndex-1)
|
||||||
|
else
|
||||||
|
return select(list, k, pivotNewIndex+1, right)
|
||||||
|
*/
|
||||||
|
public static Object find(SortableDataList list, int k, int left, int right){
|
||||||
|
// select a pivot
|
||||||
|
int pivot = right/2;
|
||||||
|
int newPivot = partition(list, left, right, pivot);
|
||||||
|
if(k == newPivot)
|
||||||
|
return list.getIndex(k);
|
||||||
|
else if(k < newPivot)
|
||||||
|
return find(list, k, left, newPivot-1);
|
||||||
|
else
|
||||||
|
return find(list, k, newPivot+1, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
function partition(list, left, right, pivotIndex)
|
||||||
|
pivotValue := list[pivotIndex]
|
||||||
|
swap list[pivotIndex] and list[right] // Move pivot to end
|
||||||
|
storeIndex := left
|
||||||
|
for i from left to right-1
|
||||||
|
if list[i] < pivotValue
|
||||||
|
swap list[storeIndex] and list[i]
|
||||||
|
storeIndex := storeIndex + 1
|
||||||
|
swap list[right] and list[storeIndex] // Move pivot to its final place
|
||||||
|
return storeIndex
|
||||||
|
*/
|
||||||
|
private static int partition(SortableDataList list, int left, int right, int pivot){
|
||||||
|
Object pivotValue = list.getIndex(pivot);
|
||||||
|
list.swap(pivot, right);
|
||||||
|
int storeIndex = left;
|
||||||
|
for(int i=left; i<right ;i++){
|
||||||
|
if(list.compare(i, pivotValue) < 0){
|
||||||
|
list.swap(storeIndex, i);
|
||||||
|
storeIndex = storeIndex+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list.swap(right, storeIndex);
|
||||||
|
return storeIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
39
src/zutil/algo/path/DijkstraPathFinder.java
Normal file
39
src/zutil/algo/path/DijkstraPathFinder.java
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
package zutil.algo.path;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
public class DijkstraPathFinder {
|
||||||
|
|
||||||
|
public static LinkedList<PathNode> find(PathNode start, PathNode stop){
|
||||||
|
// TODO
|
||||||
|
/*
|
||||||
|
1
|
||||||
|
|
||||||
|
5 dist[source] := 0 // Distance from source to source
|
||||||
|
6 Q := copy(Graph) // All nodes in the graph are unoptimized - thus are in Q
|
||||||
|
7 while Q is not empty: // The main loop
|
||||||
|
8 u := extract_min(Q) // Remove and return best vertex from nodes in two given nodes
|
||||||
|
// we would use a path finding algorithm on the new graph, such as depth-first search.
|
||||||
|
9 for each neighbor v of u: // where v has not yet been considered
|
||||||
|
10 alt = dist[u] + length(u, v)
|
||||||
|
11 if alt < dist[v] // Relax (u,v)
|
||||||
|
12 dist[v] := alt
|
||||||
|
13 previous[v] := u
|
||||||
|
14 return previous[]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LinkedList<PathNode> path = new LinkedList<PathNode>();
|
||||||
|
PathNode current = stop;
|
||||||
|
while(true){
|
||||||
|
path.addFirst(current);
|
||||||
|
current = current.getSourceNeighbor();
|
||||||
|
if(current.equals(start)){
|
||||||
|
path.addFirst(start);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
117
src/zutil/algo/path/DynamicProgramming.java
Normal file
117
src/zutil/algo/path/DynamicProgramming.java
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
package zutil.algo.path;
|
||||||
|
|
||||||
|
public class DynamicProgramming {
|
||||||
|
public static char[][] words = new char[][]{
|
||||||
|
"bibba".toCharArray(),
|
||||||
|
"bitas".toCharArray(),
|
||||||
|
"brott".toCharArray(),
|
||||||
|
"blöja".toCharArray(),
|
||||||
|
"boson".toCharArray()
|
||||||
|
};
|
||||||
|
|
||||||
|
public static void main(String[] args){
|
||||||
|
new DynamicProgramming().search();
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
|
||||||
|
int search(words[][][])
|
||||||
|
matrix[][][] = 0
|
||||||
|
shortest = -1
|
||||||
|
|
||||||
|
for w=0->length(words)
|
||||||
|
for y=0->length(words)
|
||||||
|
for x=0->length(words)
|
||||||
|
// första raden i matrisen
|
||||||
|
if y == 0
|
||||||
|
// finns första bokstaven i rätt position i första ordet?
|
||||||
|
if words[0][x] != words[w][0]
|
||||||
|
matrix[w][y][x] = -1
|
||||||
|
else
|
||||||
|
matrix[w][y][x] = 0
|
||||||
|
else
|
||||||
|
// om föregående är negativ sätt nuvarande till negativ
|
||||||
|
if matrix[w][y-1][x] < 0
|
||||||
|
matrix[w][y-1][x] = -1
|
||||||
|
// här så händer det riktiga i algoritmen
|
||||||
|
else
|
||||||
|
tmp = minstaForskjutning(words[y], words[w][y], x)
|
||||||
|
if tmp >= 0
|
||||||
|
matrix[w][y][x] = matrix[w][y-1][x] + tmp
|
||||||
|
else
|
||||||
|
matrix[w][y][x] = -1
|
||||||
|
// kolla om det är sista raden i matrisen
|
||||||
|
if y == length(matrix)
|
||||||
|
if (tmp < shortest || shortest < 0) && tmp >= 0
|
||||||
|
shortest = tmp;
|
||||||
|
|
||||||
|
return shortest
|
||||||
|
|
||||||
|
int minstaForskjutning(word[], find, index){
|
||||||
|
minsta = -1
|
||||||
|
for i=0->length(word)
|
||||||
|
if word[i] == cfind && (abs(index-i) < minsta || minsta < 0)
|
||||||
|
minsta = abs(index-i)
|
||||||
|
|
||||||
|
return minsta
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
public int search(){
|
||||||
|
int[][][] matrix = new int[words.length][words.length][words.length];
|
||||||
|
int shortest = -1;
|
||||||
|
|
||||||
|
for(int w=0; w<words.length ;w++){ //lodräta ordet
|
||||||
|
System.out.print("\n\n"+new String(words[w])+"\n ");
|
||||||
|
for(int y=0; y<words.length ;y++){ // vågräta ordet
|
||||||
|
System.out.print("\n"+ new String(words[y])+": ");
|
||||||
|
for(int x=0; x<words.length ;x++){ // psition i y
|
||||||
|
// första vågräta ordet
|
||||||
|
if(y == 0){
|
||||||
|
if(words[0][x] != words[w][0]){
|
||||||
|
matrix[w][y][x] = -1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
matrix[w][y][x] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//resten av de vågräta orden
|
||||||
|
else{
|
||||||
|
if(matrix[w][y-1][x] < 0){
|
||||||
|
matrix[w][y][x] = -1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
int tmp = minstaForskjutning(words[y], words[w][y], x);
|
||||||
|
if(tmp >= 0){
|
||||||
|
matrix[w][y][x] = matrix[w][y-1][x] + tmp;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
matrix[w][y][x] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(y == words.length-1){
|
||||||
|
int tmp = matrix[w][y][x];
|
||||||
|
if((tmp<shortest || shortest<0)
|
||||||
|
&& tmp>= 0){
|
||||||
|
shortest = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.print(" "+matrix[w][y][x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("\n\nKortaste förflyttningen: "+shortest);
|
||||||
|
return shortest;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int minstaForskjutning(char[] word, char cfind, int index){
|
||||||
|
int minsta = -1;
|
||||||
|
for(int i=0; i<word.length ;i++){
|
||||||
|
if(word[i] == cfind && (Math.abs(index-i)<minsta || minsta<0)){
|
||||||
|
minsta = Math.abs(index-i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return minsta;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/zutil/algo/path/PathNode.java
Normal file
17
src/zutil/algo/path/PathNode.java
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
package zutil.algo.path;
|
||||||
|
|
||||||
|
|
||||||
|
public interface PathNode {
|
||||||
|
|
||||||
|
public void setVisited(boolean b);
|
||||||
|
|
||||||
|
public boolean visited();
|
||||||
|
|
||||||
|
public Iterable<PathNode> getNeighbors();
|
||||||
|
|
||||||
|
public int getNeighborCost(PathNode neighbor);
|
||||||
|
|
||||||
|
public void setSourceNeighbor(PathNode neighbor);
|
||||||
|
|
||||||
|
public PathNode getSourceNeighbor();
|
||||||
|
}
|
||||||
38
src/zutil/algo/path/PathNodeDefault.java
Normal file
38
src/zutil/algo/path/PathNodeDefault.java
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
package zutil.algo.path;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class PathNodeDefault implements PathNode{
|
||||||
|
private HashMap<PathNode,Integer> neighbors;
|
||||||
|
private PathNode neighbor;
|
||||||
|
private boolean visited;
|
||||||
|
|
||||||
|
public PathNodeDefault(){
|
||||||
|
neighbors = new HashMap<PathNode,Integer>();
|
||||||
|
visited = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVisited(boolean b){
|
||||||
|
visited = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNeighborCost(PathNode neighbor) {
|
||||||
|
return neighbors.get(neighbor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterable<PathNode> getNeighbors() {
|
||||||
|
return neighbors.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean visited() {
|
||||||
|
return visited;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSourceNeighbor(PathNode n) {
|
||||||
|
neighbor = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PathNode getSourceNeighbor() {
|
||||||
|
return neighbor;
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/zutil/algo/path/SimplePathFinder.java
Normal file
95
src/zutil/algo/path/SimplePathFinder.java
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
package zutil.algo.path;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class for simple path finding algorithms
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
public class SimplePathFinder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first path to the destination
|
||||||
|
*
|
||||||
|
* @param start Start Node
|
||||||
|
* @param stop Stop Node
|
||||||
|
* @return A list with the path
|
||||||
|
*/
|
||||||
|
public LinkedList<PathNode> BreadthFirstSearch(PathNode start, PathNode stop){
|
||||||
|
Queue<PathNode> queue = new LinkedList<PathNode>();
|
||||||
|
|
||||||
|
queue.add(start);
|
||||||
|
start.setVisited(true);
|
||||||
|
|
||||||
|
PathNode tmp;
|
||||||
|
while(!queue.isEmpty()){
|
||||||
|
tmp = queue.poll();
|
||||||
|
|
||||||
|
for(PathNode next : tmp.getNeighbors()){
|
||||||
|
if(!next.visited() && tmp.getNeighborCost(next) > 0){
|
||||||
|
queue.add(next);
|
||||||
|
next.setVisited(true);
|
||||||
|
next.setSourceNeighbor(tmp);
|
||||||
|
|
||||||
|
if(next.equals(stop)){
|
||||||
|
LinkedList<PathNode> path = new LinkedList<PathNode>();
|
||||||
|
for(PathNode current=stop; !current.equals(start) ;current = current.getSourceNeighbor()){
|
||||||
|
path.addFirst(current);
|
||||||
|
}
|
||||||
|
path.addFirst(start);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LinkedList<PathNode>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first path to the destination
|
||||||
|
*
|
||||||
|
* @param start Start Node
|
||||||
|
* @param stop Stop Node
|
||||||
|
* @return A list with the path
|
||||||
|
*/
|
||||||
|
public LinkedList<PathNode> DepthFirstSearch(PathNode start, PathNode stop){
|
||||||
|
LinkedList<PathNode> path = new LinkedList<PathNode>();
|
||||||
|
PathNode current = DepthFirstSearchInternal(start, stop);
|
||||||
|
while(current != null){
|
||||||
|
path.addFirst(current);
|
||||||
|
current = current.getSourceNeighbor();
|
||||||
|
if(current.equals(start)){
|
||||||
|
path.addFirst(start);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DepthFirstSearch algorithm
|
||||||
|
* @param node The node to search from
|
||||||
|
* @return The stop PathNode if a path was found else null
|
||||||
|
*/
|
||||||
|
private PathNode DepthFirstSearchInternal(PathNode node, PathNode stop){
|
||||||
|
node.setVisited(true);
|
||||||
|
if(node.equals(stop)){
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(PathNode next : node.getNeighbors()){
|
||||||
|
if(!next.visited() && node.getNeighborCost(next) > 0){
|
||||||
|
next.setSourceNeighbor(node);
|
||||||
|
PathNode tmp = DepthFirstSearchInternal(next, stop);
|
||||||
|
if(tmp != null){
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
252
src/zutil/algo/sort/ExternalSort.java
Normal file
252
src/zutil/algo/sort/ExternalSort.java
Normal file
|
|
@ -0,0 +1,252 @@
|
||||||
|
package zutil.algo.sort;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort very big files that doesn't fit in ram
|
||||||
|
* Inspiration:
|
||||||
|
* http://www.codeodor.com/index.cfm/2007/5/14/Re-Sorting-really-BIG-files---the-Java-source-code/1208
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
public class ExternalSort {
|
||||||
|
public static int CHUNK_SIZE = 100000;
|
||||||
|
|
||||||
|
private BufferedReader in;
|
||||||
|
private File sortedFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ExternalSort object that sort a big file
|
||||||
|
* with minimal use of ram
|
||||||
|
*
|
||||||
|
* @param orgFile File to sort
|
||||||
|
* @param sortedFile The sorted file
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
*/
|
||||||
|
public ExternalSort(File orgFile, File sortedFile) throws FileNotFoundException{
|
||||||
|
in = new BufferedReader(new FileReader(orgFile));
|
||||||
|
this.sortedFile = sortedFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ExternalSort object that sort a big file
|
||||||
|
* with minimal use of ram
|
||||||
|
*
|
||||||
|
* @param orgFile File to sort
|
||||||
|
* @param sortedFile The sorted file
|
||||||
|
* @param chunk The chunk size
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
*/
|
||||||
|
public ExternalSort(File orgFile, File sortedFile, int chunk) throws FileNotFoundException{
|
||||||
|
in = new BufferedReader(new FileReader(orgFile));
|
||||||
|
this.sortedFile = sortedFile;
|
||||||
|
CHUNK_SIZE = chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts the given file
|
||||||
|
*
|
||||||
|
* @throws IOException Some kind of error
|
||||||
|
*/
|
||||||
|
public void sort() throws IOException{
|
||||||
|
// sorting the chunks
|
||||||
|
LinkedList<File> chunkFiles = sortChunks();
|
||||||
|
|
||||||
|
//merging the chunks
|
||||||
|
mergeFiles(chunkFiles);
|
||||||
|
|
||||||
|
//removing the chunks
|
||||||
|
removeFiles(chunkFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges all the files to one
|
||||||
|
* @param files
|
||||||
|
*/
|
||||||
|
private void mergeFiles(LinkedList<File> files){
|
||||||
|
try {
|
||||||
|
BufferedReader[] chunkReader = new BufferedReader[files.size()];
|
||||||
|
String[] rows = new String[files.size()];
|
||||||
|
BufferedWriter out = new BufferedWriter(new FileWriter(sortedFile));
|
||||||
|
|
||||||
|
boolean someFileStillHasRows = false;
|
||||||
|
|
||||||
|
for (int i=0; i<files.size(); i++){
|
||||||
|
chunkReader[i] = new BufferedReader(new FileReader(files.get(i)));
|
||||||
|
|
||||||
|
// get the first row
|
||||||
|
String line = chunkReader[i].readLine();
|
||||||
|
if (line != null){
|
||||||
|
rows[i] = line;
|
||||||
|
someFileStillHasRows = true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
rows[i] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
String row;
|
||||||
|
while (someFileStillHasRows){
|
||||||
|
String min;
|
||||||
|
int minIndex = 0;
|
||||||
|
|
||||||
|
row = rows[0];
|
||||||
|
if (row!=null) {
|
||||||
|
min = row;
|
||||||
|
minIndex = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
min = null;
|
||||||
|
minIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check which one is minimum
|
||||||
|
for(int i=1; i<rows.length ;i++){
|
||||||
|
row = rows[i];
|
||||||
|
if (min!=null) {
|
||||||
|
|
||||||
|
if(row!=null && row.compareTo(min) < 0){
|
||||||
|
minIndex = i;
|
||||||
|
min = row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(row!=null){
|
||||||
|
min = row;
|
||||||
|
minIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minIndex < 0) {
|
||||||
|
someFileStillHasRows = false;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// write to the sorted file
|
||||||
|
out.append(rows[minIndex]);
|
||||||
|
out.newLine();
|
||||||
|
|
||||||
|
// get another row from the file that had the min
|
||||||
|
String line = chunkReader[minIndex].readLine();
|
||||||
|
if (line != null){
|
||||||
|
rows[minIndex] = line;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
rows[minIndex] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if one still has rows
|
||||||
|
someFileStillHasRows = false;
|
||||||
|
for(int i=0; i<rows.length ; i++){
|
||||||
|
if(rows[i] != null){
|
||||||
|
if (minIndex < 0){
|
||||||
|
throw(new IOException("Error sorting!!!"));
|
||||||
|
}
|
||||||
|
someFileStillHasRows = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the actual files one more time
|
||||||
|
if (!someFileStillHasRows){
|
||||||
|
//write the last one not covered above
|
||||||
|
for(int i=0; i<rows.length ; i++){
|
||||||
|
if (rows[i] == null){
|
||||||
|
String line = chunkReader[i].readLine();
|
||||||
|
if (line != null){
|
||||||
|
someFileStillHasRows=true;
|
||||||
|
rows[i] = line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// close all the files
|
||||||
|
out.close();
|
||||||
|
for(int i=0; i<chunkReader.length ; i++){
|
||||||
|
chunkReader[i].close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex){
|
||||||
|
ex.printStackTrace();
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts the chunk files and returns a LinkedList
|
||||||
|
* with all the files
|
||||||
|
* @return A linkedList with the files
|
||||||
|
* @throws IOException Some kind of error
|
||||||
|
*/
|
||||||
|
private LinkedList<File> sortChunks() throws IOException{
|
||||||
|
LinkedList<File> chunkFiles = new LinkedList<File>();
|
||||||
|
LinkedList<String> chunk = new LinkedList<String>();
|
||||||
|
do{
|
||||||
|
chunk = readChunk(in);
|
||||||
|
|
||||||
|
//QuickSort.sort(new SortableLinkedList(chunk));
|
||||||
|
Collections.sort(chunk);
|
||||||
|
|
||||||
|
File file = new File("extsort"+chunkFiles.size()+".txt");
|
||||||
|
chunkFiles.add(file);
|
||||||
|
writeChunk(chunk,file);
|
||||||
|
}while(!chunk.isEmpty());
|
||||||
|
|
||||||
|
return chunkFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads in a chunk of rows into a LinkedList
|
||||||
|
*
|
||||||
|
* @param list The list to populate
|
||||||
|
* @param in The BufferedReader to read from
|
||||||
|
* @return The LinkeList with the chunk
|
||||||
|
* @throws IOException Some kind of error
|
||||||
|
*/
|
||||||
|
private LinkedList<String> readChunk(BufferedReader in) throws IOException{
|
||||||
|
LinkedList<String> list = new LinkedList<String>();
|
||||||
|
String tmp;
|
||||||
|
for(int i=0; i<CHUNK_SIZE ;i++){
|
||||||
|
tmp = in.readLine();
|
||||||
|
if(tmp == null) break;
|
||||||
|
list.add(tmp);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writs a chunk of strings to a file
|
||||||
|
*
|
||||||
|
* @param list The list to write down
|
||||||
|
* @param file The file to write to
|
||||||
|
* @throws IOException Some kind of error
|
||||||
|
*/
|
||||||
|
private void writeChunk(LinkedList<String> list, File file) throws IOException{
|
||||||
|
BufferedWriter out = new BufferedWriter(new FileWriter(file));
|
||||||
|
Iterator<String> it = list.iterator();
|
||||||
|
while(it.hasNext()){
|
||||||
|
out.write(it.next());
|
||||||
|
out.newLine();
|
||||||
|
}
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeFiles(LinkedList<File> list){
|
||||||
|
Iterator<File> it = list.iterator();
|
||||||
|
while(it.hasNext()){
|
||||||
|
it.next().delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
106
src/zutil/algo/sort/QuickSort.java
Normal file
106
src/zutil/algo/sort/QuickSort.java
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
package zutil.algo.sort;
|
||||||
|
|
||||||
|
import zutil.algo.sort.sortable.SortableComparableArray;
|
||||||
|
import zutil.algo.sort.sortable.SortableDataList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements QuickSort to sort a array
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
public class QuickSort{
|
||||||
|
public static final int RANDOM_PIVOT = 0;
|
||||||
|
public static final int MEDIAN_PIVOT = 1;
|
||||||
|
public static final int HALF_PIVOT = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort the elements in ascending order using quicksort.
|
||||||
|
*
|
||||||
|
* @param A A list to sort.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static void sort(SortableDataList list){
|
||||||
|
sort(list, 0, list.size()-1, 2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort the elements in ascending order using quicksort.
|
||||||
|
*
|
||||||
|
* @param A A list to sort.
|
||||||
|
* @param type type of pivot
|
||||||
|
* @param insert to use insertion sort when needed
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static void sort(SortableDataList list, int type, boolean insert){
|
||||||
|
sort(list, 0, list.size()-1, type, insert);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort the elements in ascending order using qicksort.
|
||||||
|
* after the 10 th re write and a bad mood i found this
|
||||||
|
* site that gave me much help:
|
||||||
|
* http://www.inf.fh-flensburg.de/lang/algorithmen/
|
||||||
|
* sortieren/quick/quicken.htm
|
||||||
|
*
|
||||||
|
* @param A A list to sort.
|
||||||
|
* @param start The index to start from
|
||||||
|
* @param stop The index to stop
|
||||||
|
* @param type The type of pivot to use
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static void sort(SortableDataList list, int start, int stop, int type, boolean insertionSort){
|
||||||
|
if(stop-start <= 15 && insertionSort){
|
||||||
|
SimpleSort.insertionSort( list, start, stop);
|
||||||
|
}
|
||||||
|
int pivotIndex = pivot(list,start,stop,type);
|
||||||
|
Object pivot = list.getIndex(pivotIndex);
|
||||||
|
int left=start, right=stop;
|
||||||
|
|
||||||
|
do{
|
||||||
|
while(list.compare(left, pivot) < 0){
|
||||||
|
left++;
|
||||||
|
}
|
||||||
|
while(list.compare(right, pivot) > 0){
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(left <= right){
|
||||||
|
list.swap(left, right);
|
||||||
|
left++;
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
}while(left <= right);
|
||||||
|
|
||||||
|
if(start < right){
|
||||||
|
sort(list, start, right, type, insertionSort);
|
||||||
|
}
|
||||||
|
if(left < stop){
|
||||||
|
sort(list, left, stop, type, insertionSort);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static int pivot(SortableDataList list, int start, int stop,int type){
|
||||||
|
switch(type){
|
||||||
|
case 0:
|
||||||
|
return start+(int)(Math.random()*(stop-start));
|
||||||
|
case 1:
|
||||||
|
Comparable[] i = new Comparable[]{
|
||||||
|
(Comparable)list.getIndex(0),
|
||||||
|
(Comparable)list.getIndex(list.size()/2),
|
||||||
|
(Comparable)list.getIndex(list.size()-1)};
|
||||||
|
SimpleSort.insertionSort(new SortableComparableArray(i),0,i.length);
|
||||||
|
if(i[i.length/2].compareTo(list.getIndex(start)) == 0)
|
||||||
|
return start;
|
||||||
|
else if(i[i.length/2].compareTo(list.getIndex(stop)) == 0)
|
||||||
|
return stop;
|
||||||
|
else
|
||||||
|
return start+(stop-start)/2;
|
||||||
|
case 2:
|
||||||
|
return (start+stop)/2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/zutil/algo/sort/Randomizer.java
Normal file
25
src/zutil/algo/sort/Randomizer.java
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package zutil.algo.sort;
|
||||||
|
|
||||||
|
import zutil.algo.sort.sortable.SortableDataList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class randomizes the index of all the elements in
|
||||||
|
* the Sortable object
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
public class Randomizer {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Randomizes the index of all the elements
|
||||||
|
* @param list The list
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static void sort(SortableDataList list){
|
||||||
|
int size = list.size();
|
||||||
|
for(int i=0; i<size ;i++){
|
||||||
|
list.swap(i, (int)(Math.random()*size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/zutil/algo/sort/SimpleSort.java
Normal file
67
src/zutil/algo/sort/SimpleSort.java
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
package zutil.algo.sort;
|
||||||
|
|
||||||
|
import zutil.algo.sort.sortable.SortableDataList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A collection of sorting algorithms for arrays of integers.
|
||||||
|
*
|
||||||
|
* @author Ziver Koc
|
||||||
|
* @version 2006-10-31
|
||||||
|
*/
|
||||||
|
public class SimpleSort{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort the elements in ascending order using selection sort.
|
||||||
|
* This algorithm has time complexity Theta(n*n), where n is
|
||||||
|
* the length of the array.
|
||||||
|
*
|
||||||
|
* @param list A list to sort.
|
||||||
|
* @return The same array sorted in ascending order.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static SortableDataList selectionSort(SortableDataList list){
|
||||||
|
int n = list.size();
|
||||||
|
for (int i = 0; i < n - 1; i++) {
|
||||||
|
// find index m of min element in v[i..n-1]
|
||||||
|
int m = i;
|
||||||
|
for (int j = i + 1; j < n; j++) {
|
||||||
|
if (list.compare(j, m) < 0)
|
||||||
|
m = j;
|
||||||
|
}
|
||||||
|
// swap v[i] and v[m]
|
||||||
|
list.swap(i, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort the elements in ascending order using insertionsort.
|
||||||
|
*
|
||||||
|
* @param A A list to sort.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static SortableDataList insertionSort(SortableDataList list){
|
||||||
|
return insertionSort(list, 0, list.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort the elements in ascending order using insertionsort.
|
||||||
|
*
|
||||||
|
* @param A An array of integers.
|
||||||
|
* @param start The index to start from
|
||||||
|
* @param stop The index to stop
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static SortableDataList insertionSort(SortableDataList list, int start, int stop){
|
||||||
|
for(int i=start; i<stop ;i++){
|
||||||
|
for(int j=i; j>start ;j--){
|
||||||
|
if(list.compare(j, j-1) < 0){
|
||||||
|
list.swap(j, j-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
42
src/zutil/algo/sort/sortable/SortableArrayList.java
Normal file
42
src/zutil/algo/sort/sortable/SortableArrayList.java
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
package zutil.algo.sort.sortable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class SortableArrayList<T> implements SortableDataList<T>{
|
||||||
|
private ArrayList<T> list;
|
||||||
|
|
||||||
|
public SortableArrayList(ArrayList<T> list){
|
||||||
|
this.list = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getIndex(int i) {
|
||||||
|
return list.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return list.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void swap(int a, int b) {
|
||||||
|
T temp = list.get(a);
|
||||||
|
list.set(a, list.get(b));
|
||||||
|
list.set(b, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public int compare(int a, int b) {
|
||||||
|
Comparable aa = (Comparable)list.get(a);
|
||||||
|
Comparable bb = (Comparable)list.get(b);
|
||||||
|
return aa.compareTo(bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public int compare(int a, T b) {
|
||||||
|
Comparable aa = (Comparable)list.get(a);
|
||||||
|
Comparable bb = (Comparable)b;
|
||||||
|
return aa.compareTo(bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
47
src/zutil/algo/sort/sortable/SortableComparableArray.java
Normal file
47
src/zutil/algo/sort/sortable/SortableComparableArray.java
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package zutil.algo.sort.sortable;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public class SortableComparableArray implements SortableDataList<Comparable>{
|
||||||
|
private Comparable[] list;
|
||||||
|
|
||||||
|
public SortableComparableArray(Comparable[] list){
|
||||||
|
this.list = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Comparable getIndex(int i) {
|
||||||
|
return list[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return list.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void swap(int a, int b) {
|
||||||
|
Comparable temp = list[a];
|
||||||
|
list[a] = list[b];
|
||||||
|
list[b] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compare(int a, int b) {
|
||||||
|
if(list[a].compareTo(list[b]) < 0){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if(list[a].compareTo(list[b]) > 0){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compare(int a, Comparable b) {
|
||||||
|
if(list[a].compareTo(b) < 0){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if(list[a].compareTo(b) > 0){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
50
src/zutil/algo/sort/sortable/SortableDataList.java
Normal file
50
src/zutil/algo/sort/sortable/SortableDataList.java
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
package zutil.algo.sort.sortable;
|
||||||
|
|
||||||
|
public interface SortableDataList<T>{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a specific index i the list
|
||||||
|
* @param i The index
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public T getIndex(int i);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of the list
|
||||||
|
*
|
||||||
|
* @return The size of the list
|
||||||
|
*/
|
||||||
|
public int size();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swaps the given indexes
|
||||||
|
* @param a First index
|
||||||
|
* @param b Second index
|
||||||
|
*/
|
||||||
|
public void swap(int a, int b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares to indexes and returns:
|
||||||
|
* <0 if a<b ,
|
||||||
|
* >0 if a>b ,
|
||||||
|
* =0 if a=b
|
||||||
|
*
|
||||||
|
* @param a Firs index to compare
|
||||||
|
* @param b Second index to compare
|
||||||
|
* @return Look at the info
|
||||||
|
*/
|
||||||
|
public int compare(int a, int b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares to indexes and returns:
|
||||||
|
* <0 if a<b ,
|
||||||
|
* >0 if a>b ,
|
||||||
|
* =0 if a=b
|
||||||
|
*
|
||||||
|
* @param a Firs index to compare
|
||||||
|
* @param b Second Object to compare
|
||||||
|
* @return Look at the info
|
||||||
|
*/
|
||||||
|
public int compare(int a, T b);
|
||||||
|
|
||||||
|
}
|
||||||
46
src/zutil/algo/sort/sortable/SortableIntArray.java
Normal file
46
src/zutil/algo/sort/sortable/SortableIntArray.java
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
package zutil.algo.sort.sortable;
|
||||||
|
|
||||||
|
public class SortableIntArray implements SortableDataList<Integer>{
|
||||||
|
private int[] list;
|
||||||
|
|
||||||
|
public SortableIntArray(int[] list){
|
||||||
|
this.list = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getIndex(int i) {
|
||||||
|
return list[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return list.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void swap(int a, int b) {
|
||||||
|
int temp = list[a];
|
||||||
|
list[a] = list[b];
|
||||||
|
list[b] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compare(int a, int b) {
|
||||||
|
if(list[a] < list[b]){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if(list[a] > list[b]){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compare(int a, Integer b) {
|
||||||
|
if(list[a] < b){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if(list[a] > b){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
42
src/zutil/algo/sort/sortable/SortableLinkedList.java
Normal file
42
src/zutil/algo/sort/sortable/SortableLinkedList.java
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
package zutil.algo.sort.sortable;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
public class SortableLinkedList<T> implements SortableDataList<T>{
|
||||||
|
private LinkedList<T> list;
|
||||||
|
|
||||||
|
public SortableLinkedList(LinkedList<T> list){
|
||||||
|
this.list = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getIndex(int i) {
|
||||||
|
return list.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return list.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void swap(int a, int b) {
|
||||||
|
T temp = list.get(a);
|
||||||
|
list.set(a, list.get(b));
|
||||||
|
list.set(b, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public int compare(int a, int b) {
|
||||||
|
Comparable aa = (Comparable)list.get(a);
|
||||||
|
Comparable bb = (Comparable)list.get(b);
|
||||||
|
return aa.compareTo(bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public int compare(int a, T b) {
|
||||||
|
Comparable aa = (Comparable)list.get(a);
|
||||||
|
Comparable bb = (Comparable)b;
|
||||||
|
return aa.compareTo(bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
BIN
src/zutil/data/JavaConsole.png
Normal file
BIN
src/zutil/data/JavaConsole.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
76
src/zutil/db/MySQLConnection.java
Normal file
76
src/zutil/db/MySQLConnection.java
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
package zutil.db;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
|
public class MySQLConnection {
|
||||||
|
Connection conn = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects to a MySQL server
|
||||||
|
* @param url The URL of the MySQL server
|
||||||
|
* @param db The database to connect to
|
||||||
|
* @param user The user name
|
||||||
|
* @param password The password
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
* @throws IllegalAccessException
|
||||||
|
* @throws InstantiationException
|
||||||
|
*/
|
||||||
|
public MySQLConnection(String url,String db,String user, String password) throws SQLException, InstantiationException, IllegalAccessException, ClassNotFoundException{
|
||||||
|
Class.forName ("com.mysql.jdbc.Driver").newInstance();
|
||||||
|
conn = DriverManager.getConnection ("jdbc:mysql://"+url+"/"+db, user, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a query and returns the result
|
||||||
|
* NOTE: Don't forget to close the ResultSet and the Statement or it can lead to memory leak tex: rows.getStatement().close();
|
||||||
|
* @param sql The query to execute
|
||||||
|
* @return The data that the DB returned
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
public synchronized ResultSet returnQuery(String sql) throws SQLException{
|
||||||
|
Statement s = conn.createStatement ();
|
||||||
|
s.executeQuery (sql);
|
||||||
|
return s.getResultSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a query in the MySQL server and returns effected rows
|
||||||
|
* @param sql The query to execute
|
||||||
|
* @return Number of rows effected
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
public synchronized int updateQuery(String sql) throws SQLException{
|
||||||
|
Statement s = conn.createStatement ();
|
||||||
|
int ret = s.executeUpdate(sql);
|
||||||
|
s.close();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a Prepared Statement
|
||||||
|
* NOTE: Don't forget to close the PreparedStatement or it can lead to memory leak
|
||||||
|
* @param sql The SQL to run
|
||||||
|
* @return The PreparedStatement
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
public synchronized PreparedStatement prepareStatement(String sql) throws SQLException{
|
||||||
|
return conn.prepareStatement(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnects from the database
|
||||||
|
* @throws SQLException
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public synchronized void close() throws SQLException{
|
||||||
|
if (conn != null){
|
||||||
|
conn.close ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
181
src/zutil/db/MySQLQueue.java
Normal file
181
src/zutil/db/MySQLQueue.java
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
package zutil.db;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
import zutil.Converter;
|
||||||
|
import zutil.MultiPrintStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class creates a queue that stors the
|
||||||
|
* data in a mysql table.
|
||||||
|
* The table should look like this:
|
||||||
|
* CREATE TABLE `queue` (
|
||||||
|
* `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
|
||||||
|
* `data` BINARY NOT NULL
|
||||||
|
* );
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MySQLQueue<E> implements Queue<E>{
|
||||||
|
|
||||||
|
private MySQLConnection db;
|
||||||
|
private String table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiats the queue.
|
||||||
|
* WARNING!! this will erase all rows i the table
|
||||||
|
* @param db The connection to the db
|
||||||
|
* @param table The name of the table
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
public MySQLQueue(MySQLConnection db, String table){
|
||||||
|
this.db = db;
|
||||||
|
this.table = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean add(Object arg0){
|
||||||
|
try {
|
||||||
|
PreparedStatement sql = db.prepareStatement("INSERT INTO "+table+" (data) VALUES(?)");
|
||||||
|
sql.setObject(1, arg0);
|
||||||
|
sql.executeUpdate();
|
||||||
|
sql.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace(MultiPrintStream.out);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public E element() {
|
||||||
|
return peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean offer(Object arg0) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public synchronized E peek() {
|
||||||
|
try {
|
||||||
|
ResultSet rs = db.returnQuery("SELECT * FROM "+table+" LIMIT 1");
|
||||||
|
if (rs.next()) {
|
||||||
|
return (E) Converter.toObject(rs.getBytes("data"));
|
||||||
|
}
|
||||||
|
rs.getStatement().close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace(MultiPrintStream.out);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public synchronized E poll() {
|
||||||
|
try {
|
||||||
|
ResultSet rs = db.returnQuery("SELECT * FROM "+table+" LIMIT 1");
|
||||||
|
if (rs.next()) {
|
||||||
|
db.updateQuery("DELETE FROM "+table+" WHERE id="+rs.getInt("id")+" LIMIT 1");
|
||||||
|
return (E) Converter.toObject(rs.getBytes("data"));
|
||||||
|
}
|
||||||
|
rs.getStatement().close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace(MultiPrintStream.out);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public E remove() {
|
||||||
|
return poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addAll(Collection arg0) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
try {
|
||||||
|
db.updateQuery("TRUNCATE TABLE `"+table+"`");
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace(MultiPrintStream.out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(Object arg0) {
|
||||||
|
try {
|
||||||
|
ResultSet rs = db.returnQuery("SELECT data FROM "+table+" WHERE data='"+Converter.toBytes(arg0)+"' LIMIT 1");
|
||||||
|
if (rs.next()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
rs.getStatement().close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace(MultiPrintStream.out);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsAll(Collection arg0) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return (peek() != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator iterator() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean remove(Object arg0) {
|
||||||
|
try {
|
||||||
|
ResultSet rs = db.returnQuery("DELETE FROM "+table+" WHERE data='"+Converter.toBytes(arg0)+"' LIMIT 1");
|
||||||
|
rs.getStatement().close();
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace(MultiPrintStream.out);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean removeAll(Collection arg0) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean retainAll(Collection arg0) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
try {
|
||||||
|
ResultSet rs = db.returnQuery("SELECT count(*) FROM "+table);
|
||||||
|
if (rs.next()) {
|
||||||
|
return rs.getInt(1);
|
||||||
|
}
|
||||||
|
rs.getStatement().close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace(MultiPrintStream.out);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public E[] toArray() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public E[] toArray(Object[] arg0) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
210
src/zutil/image/ImageFilterProcessor.java
Normal file
210
src/zutil/image/ImageFilterProcessor.java
Normal file
|
|
@ -0,0 +1,210 @@
|
||||||
|
package zutil.image;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
import zutil.ProgressListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a abstract class for all the effects
|
||||||
|
*
|
||||||
|
* Inspiration:
|
||||||
|
* http://www.dickbaldwin.com/tocadv.htm
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
public abstract class ImageFilterProcessor {
|
||||||
|
private BufferedImage img;
|
||||||
|
private ProgressListener progress;
|
||||||
|
|
||||||
|
public ImageFilterProcessor(BufferedImage img){
|
||||||
|
this.img = img;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the listener
|
||||||
|
* @param listener The listener, null to disable the progress
|
||||||
|
*/
|
||||||
|
public void setProgressListener(ProgressListener listener){
|
||||||
|
this.progress = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the progress in percent
|
||||||
|
*/
|
||||||
|
protected void setProgress(double percent){
|
||||||
|
if(progress != null) progress.progressUpdate(this, null, percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a effect to a given image
|
||||||
|
*
|
||||||
|
* @param effect The effect to use
|
||||||
|
* @param img The image to process
|
||||||
|
* @return The processed image
|
||||||
|
*/
|
||||||
|
public static ImageFilterProcessor getProcessor(String effect, BufferedImage img) throws InstantiationException, IllegalAccessException, ClassNotFoundException, InterruptedException{
|
||||||
|
ImageFilterProcessor processor = (ImageFilterProcessor)Class.forName(effect).newInstance();
|
||||||
|
processor.img = img;
|
||||||
|
return processor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the chosen effect to the image
|
||||||
|
*
|
||||||
|
* @return The Image with the effect
|
||||||
|
* @throws InterruptedException
|
||||||
|
*/
|
||||||
|
public BufferedImage process() throws InterruptedException{
|
||||||
|
int cols = img.getWidth();
|
||||||
|
int rows = img.getHeight();
|
||||||
|
|
||||||
|
if(cols < 0 || rows < 0){
|
||||||
|
throw new InterruptedException("Image not Loaded!!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// converts the img to raw data
|
||||||
|
int[][][] data = convertToArray(img, cols, rows);
|
||||||
|
//processes the image
|
||||||
|
data = process(data, cols, rows);
|
||||||
|
//converts back the image
|
||||||
|
return convertToImage(data, data[0].length, data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Integer array whit the pixel data of the image
|
||||||
|
* int[row][col][4]
|
||||||
|
* 0 -> Alpha data
|
||||||
|
* Red data
|
||||||
|
* Green data
|
||||||
|
* 4 -> Blue data
|
||||||
|
*
|
||||||
|
* @param img The image to convert
|
||||||
|
* @param cols Columns of the image
|
||||||
|
* @param rows Rows of the image
|
||||||
|
* @return A Integer array
|
||||||
|
* @throws InterruptedException
|
||||||
|
*/
|
||||||
|
public static int[][][] convertToArray(BufferedImage img, int cols, int rows) throws InterruptedException{
|
||||||
|
int[][][] data = new int[rows][cols][4];
|
||||||
|
// Reads in the image to a one dim array
|
||||||
|
int[] pixels = img.getRGB(0, 0, cols, rows, null, 0, cols);
|
||||||
|
|
||||||
|
// Read the pixel data and put it in the data array
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
// reading a row
|
||||||
|
int[] aRow = new int[cols];
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
int element = y * cols + x;
|
||||||
|
aRow[x] = pixels[element];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reading in the color data
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
//Alpha data
|
||||||
|
data[y][x][0] = (aRow[x] >> 24) & 0xFF;
|
||||||
|
//Red data
|
||||||
|
data[y][x][1] = (aRow[x] >> 16) & 0xFF;
|
||||||
|
//Green data
|
||||||
|
data[y][x][2] = (aRow[x] >> 8) & 0xFF;
|
||||||
|
//Blue data
|
||||||
|
data[y][x][3] = (aRow[x])& 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a pixel data array to a java Image object
|
||||||
|
*
|
||||||
|
* @param pixels The pixel data array
|
||||||
|
* @param cols Columns of the image
|
||||||
|
* @param rows Rows of the image
|
||||||
|
* @return A Image
|
||||||
|
*/
|
||||||
|
public static BufferedImage convertToImage(int[][][] pixels, int cols, int rows){
|
||||||
|
int[] data = new int[cols * rows * 4];
|
||||||
|
|
||||||
|
//Move the data into the 1D array. Note the
|
||||||
|
// use of the bitwise OR operator and the
|
||||||
|
// bitwise left-shift operators to put the
|
||||||
|
// four 8-bit bytes into each int.
|
||||||
|
int index = 0;
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
for(int x=0; x< cols ;x++){
|
||||||
|
data[index] = ((pixels[y][x][0] << 24) & 0xFF000000)
|
||||||
|
| ((pixels[y][x][1] << 16) & 0x00FF0000)
|
||||||
|
| ((pixels[y][x][2] << 8) & 0x0000FF00)
|
||||||
|
| ((pixels[y][x][3]) & 0x000000FF);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferedImage img = new BufferedImage(cols, rows, BufferedImage.TYPE_4BYTE_ABGR);
|
||||||
|
img.setRGB(0, 0, cols, rows, data, 0, cols);
|
||||||
|
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the given array to a new one that it returns
|
||||||
|
* @param data The data to duplicate
|
||||||
|
* @param cols The amount of columns
|
||||||
|
* @param rows The amount of rows
|
||||||
|
* @return The array copy
|
||||||
|
*/
|
||||||
|
public static int[][][] copyArray(int[][][] data,int cols,int rows){
|
||||||
|
int[][][] copy = new int[rows][cols][4];
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
copy[y][x][0] = data[y][x][0];
|
||||||
|
copy[y][x][1] = data[y][x][1];
|
||||||
|
copy[y][x][2] = data[y][x][2];
|
||||||
|
copy[y][x][3] = data[y][x][3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method clips the values of the pixel so that they
|
||||||
|
* are in the range 0-255
|
||||||
|
* @param data The image data
|
||||||
|
* @param cols The amount of columns
|
||||||
|
* @param rows The amount of rows
|
||||||
|
*/
|
||||||
|
public static void clip(int[][][] data, int cols, int rows){
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
data[y][x][1] = clip(data[y][x][1]);
|
||||||
|
data[y][x][1] = clip(data[y][x][2]);
|
||||||
|
data[y][x][1] = clip(data[y][x][3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method clips the values of a color so that it
|
||||||
|
* is in the range 0-255
|
||||||
|
* @param color
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static int clip(int color){
|
||||||
|
if(color < 0)
|
||||||
|
return 0;
|
||||||
|
else if(color > 255)
|
||||||
|
return 255;
|
||||||
|
else
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The underlying effect is run here
|
||||||
|
* @param data The raw image to apply the effect to
|
||||||
|
* @param cols Columns of the image
|
||||||
|
* @param rows Rows of the image
|
||||||
|
*/
|
||||||
|
public abstract int[][][] process(final int[][][] data, int cols, int rows);
|
||||||
|
}
|
||||||
170
src/zutil/image/ImageUtil.java
Normal file
170
src/zutil/image/ImageUtil.java
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
package zutil.image;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some util methods for image processing
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ImageUtil {
|
||||||
|
/**
|
||||||
|
* Returns the peek value in the image
|
||||||
|
*
|
||||||
|
* @param data The image data
|
||||||
|
* @param cols The number of columns
|
||||||
|
* @param rows The number of rows
|
||||||
|
* @return The peak value of the image
|
||||||
|
*/
|
||||||
|
public static int peakValue(int[][][] data, int cols, int rows) {
|
||||||
|
int peak = 0;
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
if(data[y][x][1] > peak) peak = data[y][x][1];
|
||||||
|
if(data[y][x][2] > peak) peak = data[y][x][2];
|
||||||
|
if(data[y][x][3] > peak) peak = data[y][x][3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return peak;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes the image data by the given scale
|
||||||
|
*
|
||||||
|
* @param data The image data
|
||||||
|
* @param cols The number of columns
|
||||||
|
* @param rows The number of rows
|
||||||
|
* @param scale The scale to normalize the image by
|
||||||
|
*/
|
||||||
|
public static void normalize(int[][][] data, int cols, int rows, double scale) {
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
data[y][x][1] = (int)(data[y][x][1] * scale);
|
||||||
|
data[y][x][2] = (int)(data[y][x][2] * scale);
|
||||||
|
data[y][x][3] = (int)(data[y][x][3] * scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the rms value of the image
|
||||||
|
* (The RMS value is a measure of the width of the color distribution.)
|
||||||
|
*
|
||||||
|
* @param data The image data
|
||||||
|
* @param cols The number of columns
|
||||||
|
* @param rows The number of rows
|
||||||
|
* @return The rms value for the image
|
||||||
|
*/
|
||||||
|
public static int rms(int[][][] data, int cols, int rows){
|
||||||
|
int pixelCount = 0;
|
||||||
|
long accum = 0;
|
||||||
|
for(int y=0; y <rows ;y++){
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
accum += data[y][x][1] * data[y][x][1];
|
||||||
|
accum += data[y][x][2] * data[y][x][2];
|
||||||
|
accum += data[y][x][3] * data[y][x][3];
|
||||||
|
pixelCount += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int meanSquare = (int)(accum/pixelCount);
|
||||||
|
int rms = (int)(Math.sqrt(meanSquare));
|
||||||
|
return rms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiplies the given image data by the given value
|
||||||
|
*
|
||||||
|
* @param data The image data
|
||||||
|
* @param cols The number of columns
|
||||||
|
* @param rows The number of rows
|
||||||
|
* @param scale The number to scale the image by
|
||||||
|
*/
|
||||||
|
public static void scale(int[][][] data, int cols, int rows, double scale){
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
data[y][x][1] *= scale;
|
||||||
|
data[y][x][2] *= scale;
|
||||||
|
data[y][x][3] *= scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mean value of the given image data
|
||||||
|
*
|
||||||
|
* @param data The image data
|
||||||
|
* @param cols The column count
|
||||||
|
* @param rows The row count
|
||||||
|
* @return The mean value of the image
|
||||||
|
*/
|
||||||
|
public static int meanValue(int[][][] data,int cols, int rows){
|
||||||
|
int pixelCount = 0;
|
||||||
|
long accum = 0;
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
accum += data[y][x][1];
|
||||||
|
accum += data[y][x][2];
|
||||||
|
accum += data[y][x][3];
|
||||||
|
pixelCount += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// calculate the mean value
|
||||||
|
return (int)(accum/pixelCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the mean value to the image data
|
||||||
|
*
|
||||||
|
* @param data The image data
|
||||||
|
* @param cols The number of columns
|
||||||
|
* @param rows The number of rows
|
||||||
|
* @param mean The mean value
|
||||||
|
*/
|
||||||
|
public static void addMeanValue(int[][][] data,int cols, int rows, int mean){
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
data[y][x][1] += mean;
|
||||||
|
data[y][x][2] += mean;
|
||||||
|
data[y][x][3] += mean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies all the pixel data from the image to the new array
|
||||||
|
*
|
||||||
|
* @param data The data to copy
|
||||||
|
* @param xStart X start position on the source
|
||||||
|
* @param yStart Y start position on the source
|
||||||
|
* @param width The amount of pixels to copy
|
||||||
|
* @param hight The amount of pixels to copy
|
||||||
|
* @return A copy of the data array
|
||||||
|
*/
|
||||||
|
public static int[][][] crop(int[][][] data, int xStart, int yStart, int width, int hight){
|
||||||
|
return crop(data, xStart, yStart, null, 0, 0, width, hight);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies all the pixel data from the image to the new array
|
||||||
|
*
|
||||||
|
* @param data The data to copy
|
||||||
|
* @param xData X start position in the source
|
||||||
|
* @param yData Y start position in the source
|
||||||
|
* @param crop The destination
|
||||||
|
* @param xCrop X start position in the destination
|
||||||
|
* @param yCrop Y start position in the destination
|
||||||
|
* @param width The amount of pixels to copy
|
||||||
|
* @param hight The amount of pixels to copy
|
||||||
|
* @return A copy of the data array
|
||||||
|
*/
|
||||||
|
public static int[][][] crop(int[][][] data, int xData, int yData, int[][][] crop, int xCrop, int yCrop, int width, int hight){
|
||||||
|
if(crop==null) crop = new int[width][hight][4];
|
||||||
|
for(int y=0; y<width ;y++){
|
||||||
|
for(int x=0; x<hight ;x++){
|
||||||
|
crop[y+yData][x+xData][0] = data[y+yCrop][x+xCrop][0];
|
||||||
|
crop[y+yData][x+xData][1] = data[y+yCrop][x+xCrop][1];
|
||||||
|
crop[y+yData][x+xData][2] = data[y+yCrop][x+xCrop][2];
|
||||||
|
crop[y+yData][x+xData][3] = data[y+yCrop][x+xCrop][3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crop;
|
||||||
|
}
|
||||||
|
}
|
||||||
88
src/zutil/image/filters/BlurFilter.java
Normal file
88
src/zutil/image/filters/BlurFilter.java
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
package zutil.image.filters;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
import zutil.image.ImageFilterProcessor;
|
||||||
|
import zutil.image.ImageUtil;
|
||||||
|
import zutil.math.ZMath;
|
||||||
|
|
||||||
|
public class BlurFilter extends ImageFilterProcessor{
|
||||||
|
private int blurValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a blur effect on the image
|
||||||
|
* @param img The image to blur
|
||||||
|
*/
|
||||||
|
public BlurFilter(BufferedImage img){
|
||||||
|
this(img, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a blur effect on the image
|
||||||
|
* @param img The image to blur
|
||||||
|
* @param blur The amount to blur
|
||||||
|
*/
|
||||||
|
public BlurFilter(BufferedImage img, int blur){
|
||||||
|
super(img);
|
||||||
|
blurValue = blur;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[][][] process(final int[][][] data, int cols, int rows) {
|
||||||
|
int inputPeak = ImageUtil.peakValue(data, cols, rows);
|
||||||
|
|
||||||
|
int[][][] output = new int[rows][cols][4];
|
||||||
|
//Perform the convolution one or more times
|
||||||
|
// in succession
|
||||||
|
for(int i=0; i<blurValue ;i++){
|
||||||
|
//Iterate on each pixel as a registration
|
||||||
|
// point.
|
||||||
|
for(int y=1; y<rows-2 ;y++){
|
||||||
|
setProgress(ZMath.percent(0, (blurValue-1)*(rows-3), i*(rows-3)+y));
|
||||||
|
for(int x=0+1; x<cols-2 ;x++){
|
||||||
|
int redSum =
|
||||||
|
data[y - 1][x - 1][1] +
|
||||||
|
data[y - 1][x - 0][1] +
|
||||||
|
data[y - 1][x + 1][1] +
|
||||||
|
data[y - 0][x - 1][1] +
|
||||||
|
data[y - 0][x - 0][1] +
|
||||||
|
data[y - 0][x + 1][1] +
|
||||||
|
data[y + 1][x - 1][1] +
|
||||||
|
data[y + 1][x - 0][1] +
|
||||||
|
data[y + 1][x + 1][1];
|
||||||
|
int greenSum =
|
||||||
|
data[y - 1][x - 1][2] +
|
||||||
|
data[y - 1][x - 0][2] +
|
||||||
|
data[y - 1][x + 1][2] +
|
||||||
|
data[y - 0][x - 1][2] +
|
||||||
|
data[y - 0][x - 0][2] +
|
||||||
|
data[y - 0][x + 1][2] +
|
||||||
|
data[y + 1][x - 1][2] +
|
||||||
|
data[y + 1][x - 0][2] +
|
||||||
|
data[y + 1][x + 1][2];
|
||||||
|
int blueSum =
|
||||||
|
data[y - 1][x - 1][3] +
|
||||||
|
data[y - 1][x - 0][3] +
|
||||||
|
data[y - 1][x + 1][3] +
|
||||||
|
data[y - 0][x - 1][3] +
|
||||||
|
data[y - 0][x - 0][3] +
|
||||||
|
data[y - 0][x + 1][3] +
|
||||||
|
data[y + 1][x - 1][3] +
|
||||||
|
data[y + 1][x - 0][3] +
|
||||||
|
data[y + 1][x + 1][3];
|
||||||
|
|
||||||
|
output[y][x][0] = data[y][x][0];
|
||||||
|
output[y][x][1] = redSum;
|
||||||
|
output[y][x][2] = greenSum;
|
||||||
|
output[y][x][3] = blueSum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getting the new peak value and normalizing the image
|
||||||
|
int outputPeak = ImageUtil.peakValue(output, cols, rows);
|
||||||
|
ImageUtil.normalize(output, cols, rows, ((double)inputPeak)/outputPeak );
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
90
src/zutil/image/filters/ColorIntensityFilter.java
Normal file
90
src/zutil/image/filters/ColorIntensityFilter.java
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
package zutil.image.filters;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
import zutil.image.ImageFilterProcessor;
|
||||||
|
import zutil.math.ZMath;
|
||||||
|
|
||||||
|
public class ColorIntensityFilter extends ImageFilterProcessor{
|
||||||
|
private boolean invert;
|
||||||
|
private int redScale;
|
||||||
|
private int greenScale;
|
||||||
|
private int blueScale;
|
||||||
|
|
||||||
|
public ColorIntensityFilter(BufferedImage img){
|
||||||
|
this(img, 50, 50, 50, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ColorIntensityEffect object with the given values
|
||||||
|
* @param img The image data
|
||||||
|
* @param inv If the image color should be inverted
|
||||||
|
*/
|
||||||
|
public ColorIntensityFilter(BufferedImage img, boolean inv){
|
||||||
|
this(img, 100, 100, 100, inv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ColorIntensityEffect object with the given values
|
||||||
|
* @param img The image data
|
||||||
|
* @param red The scale of red (0-100)
|
||||||
|
* @param green The scale of green (0-100)
|
||||||
|
* @param blue The scale of blue (0-100)
|
||||||
|
*/
|
||||||
|
public ColorIntensityFilter(BufferedImage img, int red, int green, int blue){
|
||||||
|
this(img, red, green, blue, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ColorIntensityEffect object with the given values
|
||||||
|
* @param img The image data
|
||||||
|
* @param red The scale of red (0-100)
|
||||||
|
* @param green The scale of green (0-100)
|
||||||
|
* @param blue The scale of blue (0-100)
|
||||||
|
* @param inv If the image color should be inverted
|
||||||
|
*/
|
||||||
|
public ColorIntensityFilter(BufferedImage img, int red, int green, int blue, boolean inv){
|
||||||
|
super(img);
|
||||||
|
invert = false;
|
||||||
|
redScale = red;
|
||||||
|
greenScale = green;
|
||||||
|
blueScale = blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[][][] process(final int[][][] data, int cols, int rows) {
|
||||||
|
// making sure the scales are right
|
||||||
|
if(redScale > 100) redScale = 100;
|
||||||
|
else if(redScale < 0) redScale = 0;
|
||||||
|
|
||||||
|
if(greenScale > 100) greenScale = 100;
|
||||||
|
else if(greenScale < 0) greenScale = 0;
|
||||||
|
|
||||||
|
if(blueScale > 100) blueScale = 100;
|
||||||
|
else if(blueScale < 0) blueScale = 0;
|
||||||
|
|
||||||
|
int[][][] output = new int[rows][cols][4];
|
||||||
|
|
||||||
|
// Applying the color intensity to the image
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
setProgress(ZMath.percent(0, rows-1, y));
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
if(!invert){
|
||||||
|
// inversion
|
||||||
|
output[y][x][0] = data[y][x][0];
|
||||||
|
output[y][x][1] = 255 - data[y][x][1] * redScale/100;
|
||||||
|
output[y][x][2] = 255 - data[y][x][2] * greenScale/100;
|
||||||
|
output[y][x][3] = 255 - data[y][x][3] * blueScale/100;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
output[y][x][0] = data[y][x][0];
|
||||||
|
output[y][x][1] = data[y][x][1] * redScale/100;
|
||||||
|
output[y][x][2] = data[y][x][2] * greenScale/100;
|
||||||
|
output[y][x][3] = data[y][x][3] * blueScale/100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
47
src/zutil/image/filters/ContrastBrightnessFilter.java
Normal file
47
src/zutil/image/filters/ContrastBrightnessFilter.java
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package zutil.image.filters;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
import zutil.image.ImageFilterProcessor;
|
||||||
|
import zutil.image.ImageUtil;
|
||||||
|
|
||||||
|
public class ContrastBrightnessFilter extends ImageFilterProcessor{
|
||||||
|
private double contrast;
|
||||||
|
private double brightness;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ContrastBrightnessEffect object with the given values
|
||||||
|
* @param img The image to apply the effect to
|
||||||
|
*/
|
||||||
|
public ContrastBrightnessFilter(BufferedImage img){
|
||||||
|
this(img, 3, 1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ContrastBrightnessEffect object with the given values
|
||||||
|
* @param img The image to apply the effect to
|
||||||
|
* @param con The contrast to apply
|
||||||
|
* @param brig The brightness to apply
|
||||||
|
*/
|
||||||
|
public ContrastBrightnessFilter(BufferedImage img, double con, double brig){
|
||||||
|
super(img);
|
||||||
|
contrast = con;
|
||||||
|
brightness = brig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[][][] process(final int[][][] data, int cols, int rows) {
|
||||||
|
int mean = ImageUtil.meanValue(data, cols, rows);
|
||||||
|
|
||||||
|
int[][][] output = copyArray(data, cols, rows);
|
||||||
|
|
||||||
|
ImageUtil.addMeanValue(output, cols, rows, mean*(-1));
|
||||||
|
ImageUtil.scale(output, cols, rows, contrast);
|
||||||
|
ImageUtil.addMeanValue(output, cols, rows, (int)(brightness*mean));
|
||||||
|
|
||||||
|
clip(output , cols, rows);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
87
src/zutil/image/filters/DitheringFilter.java
Normal file
87
src/zutil/image/filters/DitheringFilter.java
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
package zutil.image.filters;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
import zutil.image.ImageFilterProcessor;
|
||||||
|
import zutil.math.ZMath;
|
||||||
|
|
||||||
|
|
||||||
|
public class DitheringFilter extends ImageFilterProcessor{
|
||||||
|
// default palette is black and white
|
||||||
|
private int[][] palette = {
|
||||||
|
{255,0,0,0},
|
||||||
|
{255,255,255,255}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up a default DitheringEffect
|
||||||
|
*/
|
||||||
|
public DitheringFilter(BufferedImage img){
|
||||||
|
super(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Dithering Effect object
|
||||||
|
* @param img The image to apply the effect on
|
||||||
|
* @param palette The palette to use on the image
|
||||||
|
* int[colorCount][4]
|
||||||
|
* 0 -> Alpha data
|
||||||
|
* Red data
|
||||||
|
* Green data
|
||||||
|
* 4 -> Blue data
|
||||||
|
*/
|
||||||
|
public DitheringFilter(BufferedImage img, int[][] palette){
|
||||||
|
super(img);
|
||||||
|
this.palette = palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[][][] process(final int[][][] data, int cols, int rows) {
|
||||||
|
int error, index;
|
||||||
|
int[] currentPixel;
|
||||||
|
|
||||||
|
int[][][] output = copyArray(data, cols, rows);
|
||||||
|
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
setProgress(ZMath.percent(0, rows-1, y));
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
currentPixel = output[y][x];
|
||||||
|
index = findNearestColor(currentPixel, palette);
|
||||||
|
output[y][x] = palette[index];
|
||||||
|
|
||||||
|
for (int i = 1; i < 4; i++) {
|
||||||
|
error = currentPixel[i] - palette[index][i];
|
||||||
|
if (x + 1 < cols) {
|
||||||
|
output[y+0][x+1][i] = clip( output[y+0][x+1][i] + (error*7)/16 );
|
||||||
|
}
|
||||||
|
if (y + 1 < rows) {
|
||||||
|
if (x - 1 > 0)
|
||||||
|
output[y+1][x-1][i] = clip( output[y+1][x-1][i] + (error*3)/16 );
|
||||||
|
output[y+1][x+0][i] = clip( output[y+1][x+0][i] + (error*5)/16 );
|
||||||
|
if (x + 1 < cols)
|
||||||
|
output[y+1][x+1][i] = clip( output[y+1][x+1][i] + (error*1)/16 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int findNearestColor(int[] color, int[][] palette) {
|
||||||
|
int minDistanceSquared = 255*255 + 255*255 + 255*255 + 1;
|
||||||
|
int bestIndex = 0;
|
||||||
|
for (byte i = 0; i < palette.length; i++) {
|
||||||
|
int Rdiff = color[1] - palette[i][0];
|
||||||
|
int Gdiff = color[2] - palette[i][1];
|
||||||
|
int Bdiff = color[3] - palette[i][2];
|
||||||
|
int distanceSquared = Rdiff*Rdiff + Gdiff*Gdiff + Bdiff*Bdiff;
|
||||||
|
if (distanceSquared < minDistanceSquared) {
|
||||||
|
minDistanceSquared = distanceSquared;
|
||||||
|
bestIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
171
src/zutil/image/filters/FaceDetectionFilter.java
Normal file
171
src/zutil/image/filters/FaceDetectionFilter.java
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
package zutil.image.filters;
|
||||||
|
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
import zutil.image.ImageFilterProcessor;
|
||||||
|
import zutil.math.ZMath;
|
||||||
|
|
||||||
|
public class FaceDetectionFilter extends ImageFilterProcessor{
|
||||||
|
|
||||||
|
public FaceDetectionFilter(BufferedImage img) {
|
||||||
|
super(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[][][] process(int[][][] data, int cols, int rows) {
|
||||||
|
int[][][] IRgBy = convertARGBToIRgBy(data, cols, rows);
|
||||||
|
|
||||||
|
MedianFilter median = new MedianFilter(null, 4*getSCALE(cols,rows), new boolean[]{false,false,true,true});
|
||||||
|
IRgBy = median.process(IRgBy, cols, rows);
|
||||||
|
setProgress(ZMath.percent(0, 4, 1));
|
||||||
|
|
||||||
|
//********* Texture Map ********
|
||||||
|
median = new MedianFilter(null, 8*getSCALE(cols,rows), new boolean[]{false,true,false,false});
|
||||||
|
int[][][] textureMap = median.process(IRgBy, cols, rows);
|
||||||
|
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
textureMap[y][x][1] = Math.abs(IRgBy[y][x][1]-textureMap[y][x][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
median = new MedianFilter(null, 12*getSCALE(cols,rows), new boolean[]{false,true,false,false});
|
||||||
|
textureMap = median.process(textureMap, cols, rows);
|
||||||
|
setProgress(ZMath.percent(0, 4, 2));
|
||||||
|
|
||||||
|
//*********** Hue & Saturation *********
|
||||||
|
int[][] skinMap = new int[rows][cols];
|
||||||
|
int[][] hueMap = new int[rows][cols];
|
||||||
|
int[][] saturationMap = new int[rows][cols];
|
||||||
|
|
||||||
|
int hue, saturation;
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
// hue = (atan^2(Rg,By))
|
||||||
|
hue = (int)( Math.atan2(IRgBy[y][x][2], IRgBy[y][x][3]) * 360/2*Math.PI);
|
||||||
|
// saturation = sqrt(Rg^2+By^2)
|
||||||
|
saturation = (int) Math.sqrt(IRgBy[y][x][2]*IRgBy[y][x][2] + IRgBy[y][x][3]*IRgBy[y][x][3]);
|
||||||
|
|
||||||
|
hueMap[y][x] = hue;
|
||||||
|
saturationMap[y][x] = saturation;
|
||||||
|
|
||||||
|
// (1) texture<4.5, 120<160, 10<60
|
||||||
|
// (2) texture<4.5, 150<180, 20<80
|
||||||
|
if((textureMap[y][x][1] < 4.5 && (hue >= 120 && hue <= 160) && (saturation >= 10 && saturation <= 60)) ||
|
||||||
|
(textureMap[y][x][1] < 4.5 && (hue >= 150 && hue <= 180) && (saturation >= 20 && saturation <= 80)) ){
|
||||||
|
skinMap[y][x] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setProgress(ZMath.percent(0, 4, 3));
|
||||||
|
|
||||||
|
//************** SkinMap dilation ********************
|
||||||
|
skinMap = dilation(skinMap , cols, rows);
|
||||||
|
|
||||||
|
|
||||||
|
//*****************************************************
|
||||||
|
setProgress(100);
|
||||||
|
//return convertArrayToARGBchannel(hueMap, cols, rows, -150, 150, 1);
|
||||||
|
//return convertArrayToARGBchannel(saturationMap, cols, rows, 0, 70, 1);
|
||||||
|
return convertArrayToARGBchannel(skinMap, cols, rows, 0, 1, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[][] dilation(int[][] data, int cols, int rows){
|
||||||
|
int[][] output = new int[rows][cols];
|
||||||
|
int radX = 8;
|
||||||
|
int radY = 8;
|
||||||
|
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
if(data[y][x] == 1){
|
||||||
|
|
||||||
|
for(int dy=y-radY; dy<y+radY ;dy++){
|
||||||
|
for(int dx=x-radX; dx<x+radX ;dx++){
|
||||||
|
if(dy >= 0 && dy < rows && dx >= 0 && dx < cols)
|
||||||
|
output[dy][dx] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given data array to a color image
|
||||||
|
*
|
||||||
|
* @param data The 2d data
|
||||||
|
* @param cols The size of the image data
|
||||||
|
* @param rows The size of the image data
|
||||||
|
* @param min The minimum value in the data
|
||||||
|
* @param max The maximum value in the data
|
||||||
|
* @param channel The color channel to apply the data to
|
||||||
|
* @return A ARGB array
|
||||||
|
*/
|
||||||
|
public int[][][] convertArrayToARGBchannel(int[][] data, int cols, int rows,int min, int max, int channel){
|
||||||
|
int[][][] output = new int[rows][cols][4];
|
||||||
|
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
output[y][x][0] = 255;
|
||||||
|
output[y][x][channel] = (int) ZMath.percent(min, max, data[y][x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts RGB color to log-opponent (IRgBy) with the formula:
|
||||||
|
* I= [L(R)+L(B)+L(G)]/3
|
||||||
|
* Rg = L(R)-L(G)
|
||||||
|
* By = L(B)-[L(G)+L(R)]/2
|
||||||
|
*
|
||||||
|
* @param data The RGB data
|
||||||
|
* @param cols The number of columns
|
||||||
|
* @param rows The number of rows
|
||||||
|
* @return IRgBy data
|
||||||
|
*/
|
||||||
|
public int[][][] convertARGBToIRgBy(int[][][] data, int cols, int rows){
|
||||||
|
int[][][] output = new int[rows][cols][4];
|
||||||
|
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
output[y][x][0] = data[y][x][0];
|
||||||
|
// I= [L(R)+L(B)+L(G)]/3
|
||||||
|
output[y][x][1] = (
|
||||||
|
IRgByFunction(data[y][x][1]) +
|
||||||
|
IRgByFunction(data[y][x][2]) +
|
||||||
|
IRgByFunction(data[y][x][3])
|
||||||
|
) / 3;
|
||||||
|
// Rg = L(R)-L(G)
|
||||||
|
output[y][x][2] = IRgByFunction(output[y][x][1]) - IRgByFunction(data[y][x][2]);
|
||||||
|
// By = L(B)-[L(G)+L(R)]/2
|
||||||
|
output[y][x][3] = IRgByFunction(output[y][x][3]) -
|
||||||
|
(IRgByFunction(output[y][x][2]) - IRgByFunction(output[y][x][1])) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
// Helper function to convertToIRgBy()
|
||||||
|
private int IRgByFunction(int value){
|
||||||
|
return (int)(105*Math.log10(value+1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int getSCALE(int cols, int rows){
|
||||||
|
return (cols+rows)/320;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public Rectangle getFaceRectangle(){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
169
src/zutil/image/filters/MedianFilter.java
Normal file
169
src/zutil/image/filters/MedianFilter.java
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
package zutil.image.filters;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
import zutil.algo.sort.sortable.SortableDataList;
|
||||||
|
import zutil.image.ImageFilterProcessor;
|
||||||
|
import zutil.math.ZMath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The MedianFilter is used for noise reduction and things
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
public class MedianFilter extends ImageFilterProcessor{
|
||||||
|
private int windowSize;
|
||||||
|
private boolean[] channels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup a default MedianFilter
|
||||||
|
*
|
||||||
|
* @param img The image to process
|
||||||
|
*/
|
||||||
|
public MedianFilter(BufferedImage img) {
|
||||||
|
this(img, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup a default MedianFilter
|
||||||
|
*
|
||||||
|
* @param img The image to process
|
||||||
|
* @param pixels The size of the window
|
||||||
|
*/
|
||||||
|
public MedianFilter(BufferedImage img, int pixels) {
|
||||||
|
this(img, pixels, new boolean[]{true,true,true,true});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup a default MedianFilter
|
||||||
|
*
|
||||||
|
* @param img The image to process
|
||||||
|
* @param pixels The size of the window
|
||||||
|
* @param channels Is a 4 element array for witch channels to use the filter on
|
||||||
|
*/
|
||||||
|
public MedianFilter(BufferedImage img, int pixels, boolean[] channels) {
|
||||||
|
super(img);
|
||||||
|
this.windowSize = pixels;
|
||||||
|
this.channels = channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
edgex := (window width / 2) rounded down
|
||||||
|
edgey := (window height / 2) rounded down
|
||||||
|
for x from edgex to image width - edgex:
|
||||||
|
for y from edgey to image height - edgey:
|
||||||
|
colorArray[window width][window height];
|
||||||
|
for fx from 0 to window width:
|
||||||
|
for fy from 0 to window height:
|
||||||
|
colorArray[fx][fy] := pixelvalue[x + fx - edgex][y + fy - edgey]
|
||||||
|
Sort colorArray[][];
|
||||||
|
pixelValue[x][y] := colorArray[window width / 2][window height / 2];
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int[][][] process(int[][][] data, int cols, int rows) {
|
||||||
|
int[][][] output = new int[rows][cols][4];
|
||||||
|
|
||||||
|
int edgeX = windowSize / 2;
|
||||||
|
int edgeY = windowSize / 2;
|
||||||
|
|
||||||
|
int[][] tmpArray = new int[4][256*2];
|
||||||
|
int pixelCount = 0;
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
setProgress(ZMath.percent(0, rows-1, y));
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
|
||||||
|
pixelCount = 0;
|
||||||
|
for(int fy=0; fy<windowSize ;fy++){
|
||||||
|
for(int fx=0; fx<windowSize ;fx++){
|
||||||
|
if(y+fy-edgeY >= 0 && y+fy-edgeY < rows && x+fx-edgeX >= 0 && x+fx-edgeX < cols){
|
||||||
|
//colorArray[fx][fy] := pixelvalue[x + fx - edgex][y + fy - edgey]
|
||||||
|
if(channels[0]) tmpArray[0][ getMedianIndex( data[y + fy - edgeY][x + fx - edgeX][0] ) ]++;
|
||||||
|
if(channels[1]) tmpArray[1][ getMedianIndex( data[y + fy - edgeY][x + fx - edgeX][1] ) ]++;
|
||||||
|
if(channels[2]) tmpArray[2][ getMedianIndex( data[y + fy - edgeY][x + fx - edgeX][2] ) ]++;
|
||||||
|
if(channels[3]) tmpArray[3][ getMedianIndex( data[y + fy - edgeY][x + fx - edgeX][3] ) ]++;
|
||||||
|
pixelCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(channels[0])output[y][x][0] = findMedian(tmpArray[0], pixelCount/2);
|
||||||
|
else output[y][x][0] = data[y][x][0];
|
||||||
|
if(channels[1])output[y][x][1] = findMedian(tmpArray[1], pixelCount/2);
|
||||||
|
else output[y][x][1] = data[y][x][1];
|
||||||
|
if(channels[2])output[y][x][2] = findMedian(tmpArray[2], pixelCount/2);
|
||||||
|
else output[y][x][2] = data[y][x][2];
|
||||||
|
if(channels[3])output[y][x][3] = findMedian(tmpArray[3], pixelCount/2);
|
||||||
|
else output[y][x][3] = data[y][x][3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getMedianIndex(int i){
|
||||||
|
if(i < 0) return Math.abs(i);
|
||||||
|
else return i+256;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int findMedian(int[] median, int medianCount){
|
||||||
|
int sum = 0;
|
||||||
|
int ret = 0;
|
||||||
|
for(int i=0; i<median.length ;i++){
|
||||||
|
sum += median[i];
|
||||||
|
median[i] = 0;
|
||||||
|
if(sum >= medianCount && ret == 0){
|
||||||
|
ret = i-256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class SortableARGB implements SortableDataList<Integer>{
|
||||||
|
private int[][][] data;
|
||||||
|
private int cols;
|
||||||
|
private int rows;
|
||||||
|
private int channel;
|
||||||
|
|
||||||
|
public SortableARGB(int[][][] data, int cols, int rows, int channel){
|
||||||
|
this.data = data;
|
||||||
|
this.cols = cols;
|
||||||
|
this.rows = rows;
|
||||||
|
this.channel = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compare(int a, int b) {
|
||||||
|
return compare(a, data[ getY(b) ][ getX(b) ][ channel ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compare(int a, Integer b) {
|
||||||
|
return ((Integer)data[ getY(a) ][ getX(a) ][ channel ]).compareTo(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getIndex(int i) {
|
||||||
|
return data[ getY(i) ][ getX(i) ][ channel ];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return cols * rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void swap(int a, int b) {
|
||||||
|
int tmp = data[ getY(a) ][ getX(a) ][ channel ];
|
||||||
|
data[ getY(a) ][ getX(a) ][ channel ] = data[ getY(b) ][ getX(b) ][ channel ];
|
||||||
|
data[ getY(b) ][ getX(b) ][ channel ] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int getX(int a){
|
||||||
|
return a % cols;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getY(int a){
|
||||||
|
return a / cols;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
63
src/zutil/image/filters/ResizeImage.java
Normal file
63
src/zutil/image/filters/ResizeImage.java
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
package zutil.image.filters;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
import zutil.image.ImageFilterProcessor;
|
||||||
|
import zutil.math.ZMath;
|
||||||
|
|
||||||
|
public class ResizeImage extends ImageFilterProcessor{
|
||||||
|
private int width;
|
||||||
|
private int hight;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create a ResizeImage object and fix the hight with the aspect
|
||||||
|
* of the width
|
||||||
|
*
|
||||||
|
* @param img The image to resize
|
||||||
|
* @param w The new width
|
||||||
|
*/
|
||||||
|
public ResizeImage(BufferedImage img, int w){
|
||||||
|
this(img, w, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will create a ResizeImage object
|
||||||
|
*
|
||||||
|
* @param img The image to resize
|
||||||
|
* @param w The new width if -1 then it will be scaled whit aspect of the hight
|
||||||
|
* @param h The new hight if -1 then it will be scaled whit aspect of the width
|
||||||
|
*/
|
||||||
|
public ResizeImage(BufferedImage img, int w, int h){
|
||||||
|
super(img);
|
||||||
|
width = w;
|
||||||
|
hight = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[][][] process(final int[][][] data, int cols, int rows) {
|
||||||
|
if(width < 1){
|
||||||
|
hight = (int)(((double)width/cols)*rows);
|
||||||
|
}
|
||||||
|
else if(hight < 1){
|
||||||
|
width = (int)(((double)hight/rows)*cols);
|
||||||
|
}
|
||||||
|
|
||||||
|
int[][][] tmp = new int[hight][width][4];
|
||||||
|
double xScale = ((double)cols/width);
|
||||||
|
double yScale = ((double)rows/hight);
|
||||||
|
|
||||||
|
for(int y=0; y<width ;y++){
|
||||||
|
setProgress(ZMath.percent(0, width-1, y));
|
||||||
|
for(int x=0; x<hight ;x++){
|
||||||
|
tmp[y][x][0] = data[(int)(y*yScale)][(int)(x*xScale)][0];
|
||||||
|
tmp[y][x][1] = data[(int)(y*yScale)][(int)(x*xScale)][1];
|
||||||
|
tmp[y][x][2] = data[(int)(y*yScale)][(int)(x*xScale)][2];
|
||||||
|
tmp[y][x][3] = data[(int)(y*yScale)][(int)(x*xScale)][3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
73
src/zutil/image/filters/SpotLightFilter.java
Normal file
73
src/zutil/image/filters/SpotLightFilter.java
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
package zutil.image.filters;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
import zutil.image.ImageFilterProcessor;
|
||||||
|
import zutil.math.ZMath;
|
||||||
|
|
||||||
|
public class SpotLightFilter extends ImageFilterProcessor{
|
||||||
|
private int radius;
|
||||||
|
private int xPos;
|
||||||
|
private int yPos;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up a default spotlight effect in
|
||||||
|
* the middle of the image
|
||||||
|
*/
|
||||||
|
public SpotLightFilter(BufferedImage img){
|
||||||
|
this(img, 100, -1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up a custom spotlight
|
||||||
|
* @param r The radius of the spotlight in pixels
|
||||||
|
*/
|
||||||
|
public SpotLightFilter(BufferedImage img, int r){
|
||||||
|
this(img, r, -1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up a custom spotlight
|
||||||
|
* @param r The radius of the spotlight in pixels
|
||||||
|
* @param x The x position of the spotlight, if -1 then it will be centered
|
||||||
|
* @param y The y position of the spotlight, if -1 then it will be centered
|
||||||
|
*/
|
||||||
|
public SpotLightFilter(BufferedImage img, int r, int x, int y){
|
||||||
|
super(img);
|
||||||
|
radius = r;
|
||||||
|
xPos = x;
|
||||||
|
yPos = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[][][] process(final int[][][] data, int cols, int rows) {
|
||||||
|
if(xPos < 0) xPos = cols/2;
|
||||||
|
if(yPos < 0) yPos = rows/2;
|
||||||
|
|
||||||
|
int[][][] output = new int[rows][cols][4];
|
||||||
|
double scale, dx, dy, distance;
|
||||||
|
for(int y=0; y<rows ;y++){
|
||||||
|
setProgress(ZMath.percent(0, rows-1, y));
|
||||||
|
for(int x=0; x<cols ;x++){
|
||||||
|
dx = x-xPos;
|
||||||
|
dy = y-yPos;
|
||||||
|
|
||||||
|
distance = Math.sqrt(dx*dx+dy*dy);
|
||||||
|
|
||||||
|
if(distance > radius){
|
||||||
|
scale = 0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
scale = 1-(distance/radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
output[y][x][0] = data[y][x][0];
|
||||||
|
output[y][x][1] = clip((int)(scale * data[y][x][1]));
|
||||||
|
output[y][x][2] = clip((int)(scale * data[y][x][2]));
|
||||||
|
output[y][x][3] = clip((int)(scale * data[y][x][3]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
110
src/zutil/math/Tick.java
Normal file
110
src/zutil/math/Tick.java
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
package zutil.math;
|
||||||
|
|
||||||
|
public class Tick {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TEST
|
||||||
|
*/
|
||||||
|
public static void main(String[] args){
|
||||||
|
String temp = "a";
|
||||||
|
while(true){
|
||||||
|
temp = tick(temp,3);
|
||||||
|
System.out.println(temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ticks a given string(increments the string with one)
|
||||||
|
*
|
||||||
|
* @param ts The string to tick
|
||||||
|
* @param maxChar The maximum number of characters in the string
|
||||||
|
* @return The ticked string
|
||||||
|
*/
|
||||||
|
public static String tick(String ts, int maxChar){
|
||||||
|
StringBuffer ret = new StringBuffer(ts.trim());
|
||||||
|
int index = ret.length()-1;
|
||||||
|
|
||||||
|
if(ret.length() < maxChar){
|
||||||
|
ret.append('a');
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
while(index >= 0){
|
||||||
|
char c = increment(ret.charAt(index));
|
||||||
|
if(c != 0){
|
||||||
|
if(index == 0 && ret.length() < maxChar) ret.append('a');
|
||||||
|
if(index == 0) ret = new StringBuffer(""+c);
|
||||||
|
else ret.setCharAt(index,c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//ret.setCharAt(index,'a');
|
||||||
|
ret.deleteCharAt(index);
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the char with one after the swedish alfabet
|
||||||
|
*
|
||||||
|
* @param c The char to increment
|
||||||
|
* @return The incremented char in lowercase 0 if it reached the end
|
||||||
|
*/
|
||||||
|
public static char increment(char c){
|
||||||
|
switch(Character.toLowerCase(c)){
|
||||||
|
case 'z': return 'å';
|
||||||
|
case 'å': return 'ä';
|
||||||
|
case 'ä': return 'ö';
|
||||||
|
}
|
||||||
|
c = (char)(Character.toLowerCase(c) + 1);
|
||||||
|
if(isAlfa(c)){
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the char is a valid character in
|
||||||
|
* the Swedish alfabet
|
||||||
|
*
|
||||||
|
* @param c The char to check
|
||||||
|
* @return True if the char is a valid letter
|
||||||
|
*/
|
||||||
|
public static boolean isAlfa(char c){
|
||||||
|
switch(Character.toLowerCase(c)){
|
||||||
|
case 'a':
|
||||||
|
case 'b':
|
||||||
|
case 'c':
|
||||||
|
case 'd':
|
||||||
|
case 'e':
|
||||||
|
case 'f':
|
||||||
|
case 'g':
|
||||||
|
case 'h':
|
||||||
|
case 'i':
|
||||||
|
case 'j':
|
||||||
|
case 'k':
|
||||||
|
case 'l':
|
||||||
|
case 'm':
|
||||||
|
case 'n':
|
||||||
|
case 'o':
|
||||||
|
case 'p':
|
||||||
|
case 'q':
|
||||||
|
case 'r':
|
||||||
|
case 's':
|
||||||
|
case 't':
|
||||||
|
case 'u':
|
||||||
|
case 'v':
|
||||||
|
case 'w':
|
||||||
|
case 'x':
|
||||||
|
case 'y':
|
||||||
|
case 'z':
|
||||||
|
case 'å':
|
||||||
|
case 'ä':
|
||||||
|
case 'ö': return true;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/zutil/math/ZMath.java
Normal file
16
src/zutil/math/ZMath.java
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
package zutil.math;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Very Simple math functions
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
public class ZMath {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the percentige the value has
|
||||||
|
*/
|
||||||
|
public static double percent(int min, int max, int value){
|
||||||
|
return ((double)(value-min)/(max-min))*100;
|
||||||
|
}
|
||||||
|
}
|
||||||
257
src/zutil/math/parser/MathParser.java
Normal file
257
src/zutil/math/parser/MathParser.java
Normal file
|
|
@ -0,0 +1,257 @@
|
||||||
|
package zutil.math.parser;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class parses a string with math
|
||||||
|
* and solves it
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
public class MathParser {
|
||||||
|
|
||||||
|
public static MathNode parse(String functionString){
|
||||||
|
StringBuffer functionStringBuffer = new StringBuffer(functionString+(char)0);
|
||||||
|
MathNode node = new MathNode();
|
||||||
|
|
||||||
|
parse(functionStringBuffer, new StringBuffer(), null, node);
|
||||||
|
|
||||||
|
System.out.println("----------------------------------------------------------------------");
|
||||||
|
System.out.println(node+" = "+node.exec());
|
||||||
|
System.out.println("----------------------------------------------------------------------");
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parse(StringBuffer functionString, StringBuffer temp, MathOperation previus, MathNode rootNode){
|
||||||
|
if(functionString.length() <= 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char c = functionString.charAt(0);
|
||||||
|
functionString.deleteCharAt(0);
|
||||||
|
System.out.println("char: "+c);
|
||||||
|
MathOperation current = null;
|
||||||
|
|
||||||
|
if(!Character.isWhitespace(c)){
|
||||||
|
if(isNumber(c)){
|
||||||
|
temp.append(c);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
Math container = new MathNumber();
|
||||||
|
if(temp.length() > 0){
|
||||||
|
System.out.println("("+Double.parseDouble(temp.toString())+")");
|
||||||
|
((MathNumber)container).num = Double.parseDouble(temp.toString());
|
||||||
|
temp.delete(0, temp.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rootNode.math == null){
|
||||||
|
System.out.println("Initializing rootNode");
|
||||||
|
previus = getOperation(c);
|
||||||
|
System.out.println("operation: "+previus.getClass().getName());
|
||||||
|
previus.math1 = container;
|
||||||
|
rootNode.math = previus;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(c == '('){
|
||||||
|
MathNode parantes = new MathNode();
|
||||||
|
MathOperation previusParantes = previus;
|
||||||
|
parse(functionString, temp, previus, parantes);
|
||||||
|
previusParantes.math2 = parantes;
|
||||||
|
System.out.println(parantes);
|
||||||
|
container = parantes;
|
||||||
|
|
||||||
|
// get the next operation
|
||||||
|
c = functionString.charAt(0);
|
||||||
|
functionString.deleteCharAt(0);
|
||||||
|
System.out.println("char: "+c);
|
||||||
|
}
|
||||||
|
|
||||||
|
current = getOperation(c);
|
||||||
|
System.out.println("operation: "+current.getClass().getName());
|
||||||
|
current.math1 = container;
|
||||||
|
previus.math2 = current;
|
||||||
|
|
||||||
|
if(c == ')'){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(current != null) parse(functionString, temp, current, rootNode);
|
||||||
|
else parse(functionString, temp, previus, rootNode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isNumber(char c){
|
||||||
|
if(Character.isDigit(c)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MathOperation getOperation(char c){
|
||||||
|
switch(c){
|
||||||
|
case '+': return new MathAddition();
|
||||||
|
case '-': return new MathSubtraction();
|
||||||
|
case '*': return new MathMultiplication();
|
||||||
|
case '/': return new MathDivision();
|
||||||
|
case '%': return new MathModulus();
|
||||||
|
case '^': return new MathPow();
|
||||||
|
case ')':
|
||||||
|
case (char)0: return new EmptyMath();
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args){
|
||||||
|
try {
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
|
||||||
|
while(true){
|
||||||
|
System.out.print(">>Math: ");
|
||||||
|
parse(in.readLine());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Math{
|
||||||
|
public abstract double exec();
|
||||||
|
|
||||||
|
public abstract String toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
class MathNode extends Math{
|
||||||
|
Math math;
|
||||||
|
|
||||||
|
public double exec() {
|
||||||
|
return math.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "( "+math.toString()+" )";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MathNumber extends Math{
|
||||||
|
double num;
|
||||||
|
|
||||||
|
public double exec() {
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return ""+num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class MathOperation extends Math{
|
||||||
|
Math math1;
|
||||||
|
Math math2;
|
||||||
|
int priority;
|
||||||
|
|
||||||
|
public abstract double exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
class MathAddition extends MathOperation{
|
||||||
|
public MathAddition(){
|
||||||
|
priority = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double exec() {
|
||||||
|
return math1.exec() + math2.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return math1.toString()+" + "+math2.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MathSubtraction extends MathOperation{
|
||||||
|
public MathSubtraction(){
|
||||||
|
priority = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double exec() {
|
||||||
|
return math1.exec() - math2.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return math1.toString()+" - "+math2.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MathMultiplication extends MathOperation{
|
||||||
|
public MathMultiplication(){
|
||||||
|
priority = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double exec() {
|
||||||
|
return math1.exec() * math2.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return math1.toString()+" * "+math2.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MathDivision extends MathOperation{
|
||||||
|
public MathDivision(){
|
||||||
|
priority = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double exec() {
|
||||||
|
return math1.exec() / math2.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return math1.toString()+" / "+math2.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MathModulus extends MathOperation{
|
||||||
|
public MathModulus(){
|
||||||
|
priority = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double exec() {
|
||||||
|
return math1.exec() % math2.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return math1.toString()+" % "+math2.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MathPow extends MathOperation{
|
||||||
|
public MathPow(){
|
||||||
|
priority = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double exec() {
|
||||||
|
double ret = 1;
|
||||||
|
double tmp1 = math1.exec();
|
||||||
|
double tmp2 = math2.exec();
|
||||||
|
for(int i=0; i<tmp2 ;i++){
|
||||||
|
ret *= tmp1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return math1.toString()+"^"+math2.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EmptyMath extends MathOperation{
|
||||||
|
public double exec() {
|
||||||
|
return math1.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return math1.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
487
src/zutil/network/FTPClient.java
Normal file
487
src/zutil/network/FTPClient.java
Normal file
|
|
@ -0,0 +1,487 @@
|
||||||
|
package zutil.network;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import javax.security.auth.login.AccountException;
|
||||||
|
|
||||||
|
import zutil.MultiPrintStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple FTP client class
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
* http://en.wikipedia.org/wiki/List_of_FTP_commands
|
||||||
|
* http://en.wikipedia.org/wiki/List_of_FTP_server_return_codes
|
||||||
|
* http://www.ietf.org/rfc/rfc959.txt
|
||||||
|
*
|
||||||
|
* TODO: file info, rename, Active mode
|
||||||
|
*/
|
||||||
|
public class FTPClient extends Thread{
|
||||||
|
public static final int FTP_ACTIVE = 0;
|
||||||
|
public static final int FTP_PASSIVE = 1;
|
||||||
|
public static final int FTP_PORT = 21;
|
||||||
|
public static final int FTP_DATA_PORT = 20;
|
||||||
|
public static final int FTP_NOOP_INT = 120;
|
||||||
|
|
||||||
|
//************** FTP Return Codes ******************
|
||||||
|
public static final int FTPC_USER_OK = 331;
|
||||||
|
public static final int FTPC_NEED_PASS = 331;
|
||||||
|
public static final int FTPC_LOGIN_NO = 530;
|
||||||
|
public static final int FTPC_LOGIN_OK = 230;
|
||||||
|
|
||||||
|
public static final int FTPC_ENTERING_PASSIVE = 227;
|
||||||
|
public static final int FTPC_FILE_ACTION_OK = 250;
|
||||||
|
public static final int FTPC_PATH_CREATED = 257;
|
||||||
|
//***************************************************
|
||||||
|
|
||||||
|
private BufferedReader in;
|
||||||
|
private PrintStream out;
|
||||||
|
private Socket socket;
|
||||||
|
private long last_sent;
|
||||||
|
|
||||||
|
public static void main(String[] args){
|
||||||
|
try {
|
||||||
|
FTPClient client = new FTPClient("koc.se", 21, "kth", "****", FTP_PASSIVE);
|
||||||
|
client.createDir("./ziver/lol");
|
||||||
|
client.removeDir("./ziver/lol");
|
||||||
|
|
||||||
|
MultiPrintStream.out.dump(client.getFileList("./ziver"));
|
||||||
|
client.sendFile("./ziver/test.txt", "lol");
|
||||||
|
MultiPrintStream.out.dump(client.getFileList("./ziver"));
|
||||||
|
|
||||||
|
MultiPrintStream.out.dump(client.getFile("./ziver/test.txt"));
|
||||||
|
client.readCommand(true);
|
||||||
|
|
||||||
|
MultiPrintStream.out.println(client.getFileInfo("./ziver/test.txt"));
|
||||||
|
|
||||||
|
MultiPrintStream.out.dump(client.getFileList("./ziver"));
|
||||||
|
client.removeFile("./ziver/test.txt");
|
||||||
|
MultiPrintStream.out.dump(client.getFileList("./ziver"));
|
||||||
|
|
||||||
|
client.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a FTP connection and logs in
|
||||||
|
*
|
||||||
|
* @param url The address to server
|
||||||
|
* @param port Port number
|
||||||
|
* @param user User name
|
||||||
|
* @param pass Password
|
||||||
|
* @param connection_type Pasive or Active
|
||||||
|
*/
|
||||||
|
public FTPClient(String url, int port, String user, String pass, int connection_type) throws UnknownHostException, IOException, AccountException{
|
||||||
|
socket = new Socket(url, port);
|
||||||
|
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
out = new PrintStream(socket.getOutputStream());
|
||||||
|
|
||||||
|
readCommand(true);
|
||||||
|
sendCommand("USER "+user);
|
||||||
|
sendNoReplyCommand("PASS "+pass, false);
|
||||||
|
System.out.println("PASS ***");
|
||||||
|
String tmp = readMultipleCommands(true);
|
||||||
|
if(parseReturnCode(tmp) == FTPC_LOGIN_NO){
|
||||||
|
close();
|
||||||
|
throw new AccountException(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
//**************************************************************************************
|
||||||
|
//**************************************************************************************
|
||||||
|
//********************************* Command channel ************************************
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the given line to the server and returns a status integer
|
||||||
|
*
|
||||||
|
* @param cmd The command to send
|
||||||
|
* @return The return code from the server
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public synchronized int sendCommand(String cmd) throws IOException{
|
||||||
|
return parseReturnCode(sendCommand(cmd, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the given line to the server and returns the last line
|
||||||
|
*
|
||||||
|
* @param cmd The command to send
|
||||||
|
* @param print To print out the received lines
|
||||||
|
* @return Last String line from the server
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private synchronized String sendCommand(String cmd, boolean print) throws IOException{
|
||||||
|
sendNoReplyCommand(cmd, print);
|
||||||
|
return readCommand(print);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a given command and don't cares about the reply
|
||||||
|
*
|
||||||
|
* @param cmd The command
|
||||||
|
* @param print If it should print to System.out
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private synchronized void sendNoReplyCommand(String cmd, boolean print) throws IOException{
|
||||||
|
out.println(cmd);
|
||||||
|
last_sent = System.currentTimeMillis();
|
||||||
|
if(print)System.out.println(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads on line from the command channel
|
||||||
|
*
|
||||||
|
* @param print If the method should print the input line
|
||||||
|
* @return The input line
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private synchronized String readCommand(boolean print) throws IOException{
|
||||||
|
String tmp = in.readLine();
|
||||||
|
if(print)System.out.println(tmp);
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads from the command channel until there are nothing
|
||||||
|
* left to read and returns the last line
|
||||||
|
* Multiple
|
||||||
|
* @param print To print out the received lines
|
||||||
|
* @return The last received line
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private synchronized String readMultipleCommands(boolean print) throws IOException{
|
||||||
|
String tmp = in.readLine();
|
||||||
|
if(print)System.out.println(tmp);
|
||||||
|
try{ Thread.sleep(500); }catch(Exception e){}
|
||||||
|
while(in.ready()){
|
||||||
|
tmp = in.readLine();
|
||||||
|
if(print)System.out.println(tmp);
|
||||||
|
try{ Thread.sleep(500); }catch(Exception e){}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the return line from the server and returns the status code
|
||||||
|
*
|
||||||
|
* @param msg The message from the server
|
||||||
|
* @return The status code
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private synchronized int parseReturnCode(String msg){
|
||||||
|
return Integer.parseInt(msg.substring(0, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
//**************************************************************************************
|
||||||
|
//**************************************************************************************
|
||||||
|
//****************************** File system actions ************************************
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a LinkedList with the names of all the files in the directory
|
||||||
|
*
|
||||||
|
* @param path Path to the files to be listed
|
||||||
|
* @return LinkedList whit filenames
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public LinkedList<String> getFileList(String path) throws IOException{
|
||||||
|
LinkedList<String> list = new LinkedList<String>();
|
||||||
|
|
||||||
|
BufferedReader data_in = getDataInputStream();
|
||||||
|
sendCommand("NLST "+path, true);
|
||||||
|
|
||||||
|
String tmp = "";
|
||||||
|
while((tmp = data_in.readLine()) != null){
|
||||||
|
list.add(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
data_in.close();
|
||||||
|
readCommand(true);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns information about the file or directory
|
||||||
|
* (This is system specific information)
|
||||||
|
*
|
||||||
|
* TODO:
|
||||||
|
* @deprecated DOSENT WORK!!!!
|
||||||
|
* @param path The path and filename of a file or a directory
|
||||||
|
* @return A String with information
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public String getFileInfo(String path) throws IOException{
|
||||||
|
StringBuffer info = new StringBuffer("");
|
||||||
|
|
||||||
|
BufferedReader data_in = getDataInputStream();
|
||||||
|
sendCommand("LIST "+path, true);
|
||||||
|
|
||||||
|
String tmp = "";
|
||||||
|
while((tmp = data_in.readLine()) != null){
|
||||||
|
info.append(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
data_in.close();
|
||||||
|
readCommand(true);
|
||||||
|
return info.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a file at the server with the given data
|
||||||
|
*
|
||||||
|
* @param path The path and filename
|
||||||
|
* @param data The data to put in the file
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void sendFile(String path, String data) throws IOException{
|
||||||
|
PrintStream data_out = getDataOutputStream();
|
||||||
|
sendCommand("STOR "+path, true);
|
||||||
|
data_out.println(data);
|
||||||
|
data_out.close();
|
||||||
|
readCommand(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a directory at the server
|
||||||
|
*
|
||||||
|
* @param path The path to the directory
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public boolean createDir(String path) throws IOException{
|
||||||
|
if(sendCommand("MKD "+path) == FTPC_PATH_CREATED)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a BufferedReader with the file data
|
||||||
|
* WARNING: you must run readCommand(true); after you close the stream
|
||||||
|
*
|
||||||
|
* @param path The path and filename
|
||||||
|
* @return Stream with the file
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private BufferedReader getFile(String path) throws IOException{
|
||||||
|
BufferedReader ret = getDataInputStream();
|
||||||
|
sendCommand("RETR "+path, true);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloads a file from the FTP server to a local file
|
||||||
|
*
|
||||||
|
* @param source The source file on the server
|
||||||
|
* @param destination The local file to save to
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void getFile(String source, String destination) throws IOException{
|
||||||
|
BufferedReader file_in = getFile(source);
|
||||||
|
PrintStream file_out = new PrintStream(new File(destination));
|
||||||
|
|
||||||
|
String tmp = "";
|
||||||
|
while((tmp = file_in.readLine()) != null){
|
||||||
|
file_out.println(tmp);
|
||||||
|
}
|
||||||
|
readCommand(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a file from the FTP server
|
||||||
|
*
|
||||||
|
* @param path The path and filename of the file to be deleted
|
||||||
|
* @return True if the command was successful or false otherwise
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public boolean removeFile(String path) throws IOException{
|
||||||
|
if(sendCommand("DELE "+path) == FTPC_FILE_ACTION_OK)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a directory from the FTP server
|
||||||
|
*
|
||||||
|
* @param path The path of the directory to be deleted
|
||||||
|
* @return True if the command was successful or false otherwise
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public boolean removeDir(String path) throws IOException{
|
||||||
|
if(sendCommand("RMD "+path) == FTPC_FILE_ACTION_OK)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//**************************************************************************************
|
||||||
|
//**************************************************************************************
|
||||||
|
//******************************** Data Connection *************************************
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a connection to the server. It automatically handles
|
||||||
|
* passive or active mode
|
||||||
|
*
|
||||||
|
* @return The PrintStream for the channel
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public synchronized PrintStream getDataOutputStream() throws IOException{
|
||||||
|
int port = getDataConnectionPortType();
|
||||||
|
if(port < 0){ // Active Mode
|
||||||
|
port *= -1;
|
||||||
|
return getActiveDataOutputStream(port);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
System.out.println("port: "+port);
|
||||||
|
return getPassiveDataOutputStream(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a connection to the server. It automatically handles
|
||||||
|
* passive or active mode
|
||||||
|
*
|
||||||
|
* @return The BufferedReader for the channel
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public synchronized BufferedReader getDataInputStream() throws IOException{
|
||||||
|
int port = getDataConnectionPortType();
|
||||||
|
if(port < 0){ // Active Mode
|
||||||
|
port *= -1;
|
||||||
|
return getActiveDataInputStream(port);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return getPassiveDataInputStream(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method chooses the appropriate data connection type
|
||||||
|
* to the server (Passive or Active) and returns the port number
|
||||||
|
*
|
||||||
|
* @return A port number. If port > 0 = Passive AND port < 0 Active
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private int getDataConnectionPortType() throws IOException{
|
||||||
|
return setPassiveMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects to the data port on the server and returns the InputStream
|
||||||
|
*
|
||||||
|
* @param port The port to connect to
|
||||||
|
* @return The InputStream for the data channel
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private BufferedReader getPassiveDataInputStream(int port) throws IOException{
|
||||||
|
Socket data_socket = new Socket(socket.getInetAddress().getHostAddress(), port);
|
||||||
|
BufferedReader data_in = new BufferedReader(new InputStreamReader(data_socket.getInputStream()));
|
||||||
|
|
||||||
|
return data_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects to the data port on the server and returns the OutputStream
|
||||||
|
*
|
||||||
|
* @param port The port to connect to
|
||||||
|
* @return The OutputStream for the data channel
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private PrintStream getPassiveDataOutputStream(int port) throws IOException{
|
||||||
|
Socket data_socket = new Socket(socket.getInetAddress().getHostAddress(), port);
|
||||||
|
PrintStream data_out = new PrintStream(data_socket.getOutputStream());
|
||||||
|
|
||||||
|
return data_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listens on a local port for a connection from the server
|
||||||
|
* and returns with the InputStream of the connection from the server
|
||||||
|
*
|
||||||
|
* @param port The port to listen to
|
||||||
|
* @return The InputStream for the data channel
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private BufferedReader getActiveDataInputStream(int port) throws IOException{
|
||||||
|
// TODO:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listens on a local port for a connection from the server
|
||||||
|
* and returns with the OutputStream of the connection from the server
|
||||||
|
*
|
||||||
|
* @param port The port to listen to
|
||||||
|
* @return The OutputStream for the data channel
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private PrintStream getActiveDataOutputStream(int port) throws IOException{
|
||||||
|
// TODO:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets Passive mode at the server and returns the port number
|
||||||
|
* for the data channel
|
||||||
|
*
|
||||||
|
* @return Port number for data channel
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private int setPassiveMode() throws IOException{
|
||||||
|
String tmp = sendCommand("PASV", true);
|
||||||
|
if(parseReturnCode(tmp) != FTPC_ENTERING_PASSIVE){
|
||||||
|
throw new IOException(tmp);
|
||||||
|
}
|
||||||
|
tmp = tmp.substring(tmp.indexOf('(')+1, tmp.indexOf(')'));
|
||||||
|
String[] tmpArray = tmp.split("[,]");
|
||||||
|
|
||||||
|
if(tmpArray.length <= 1)
|
||||||
|
return Integer.parseInt(tmpArray[0]);
|
||||||
|
else
|
||||||
|
return Integer.parseInt(tmpArray[4])*256 + Integer.parseInt(tmpArray[5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//**************************************************************************************
|
||||||
|
//**************************************************************************************
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To keep the connection alive
|
||||||
|
*/
|
||||||
|
public void run(){
|
||||||
|
try {
|
||||||
|
while(true){
|
||||||
|
if(last_sent > System.currentTimeMillis() + FTP_NOOP_INT*1000){
|
||||||
|
sendCommand("NOOP");
|
||||||
|
}
|
||||||
|
try{ Thread.sleep(5000); }catch(Exception e){}
|
||||||
|
}
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the FTP connection
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public void close() throws IOException{
|
||||||
|
sendCommand("QUIT", true);
|
||||||
|
in.close();
|
||||||
|
out.close();
|
||||||
|
socket.close();
|
||||||
|
this.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
73
src/zutil/network/ServerFind.java
Normal file
73
src/zutil/network/ServerFind.java
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
package zutil.network;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.MulticastSocket;
|
||||||
|
|
||||||
|
import zutil.MultiPrintStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class broadcast its address in the LAN so that
|
||||||
|
* the ServerFindClient can get the server IP
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ServerFind extends Thread {
|
||||||
|
public String broadcastAddress = "230.0.0.1";
|
||||||
|
|
||||||
|
private InetAddress group;
|
||||||
|
private MulticastSocket Msocket;
|
||||||
|
|
||||||
|
private boolean avsluta;
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ServerFind Thread an the specified port
|
||||||
|
*
|
||||||
|
* @param port The port to run the ServerFind Server on
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public ServerFind (int port) throws IOException {
|
||||||
|
this.port = port;
|
||||||
|
avsluta = false;
|
||||||
|
group = InetAddress.getByName(broadcastAddress);
|
||||||
|
Msocket = new MulticastSocket(port);
|
||||||
|
Msocket.joinGroup(group);
|
||||||
|
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run (){
|
||||||
|
byte[] buf = new byte[256];
|
||||||
|
DatagramPacket packet;
|
||||||
|
DatagramSocket lan_socket = null;
|
||||||
|
|
||||||
|
while (!avsluta){
|
||||||
|
try {
|
||||||
|
packet = new DatagramPacket(buf, buf.length);
|
||||||
|
Msocket.receive(packet);
|
||||||
|
|
||||||
|
lan_socket = new DatagramSocket(port , packet.getAddress());
|
||||||
|
packet = new DatagramPacket(buf, buf.length, group, port);
|
||||||
|
lan_socket.send(packet);
|
||||||
|
lan_socket.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
MultiPrintStream.out.println("Error Establishing ServerFind Connection!!!\n" + e);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the broadcast socket
|
||||||
|
*/
|
||||||
|
public void close(){
|
||||||
|
avsluta = true;
|
||||||
|
Msocket.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
50
src/zutil/network/ServerFindClient.java
Normal file
50
src/zutil/network/ServerFindClient.java
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
package zutil.network;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.MulticastSocket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is the client for ServerFind that receives the server IP
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ServerFindClient{
|
||||||
|
public String broadcastAddress = "230.0.0.1";
|
||||||
|
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ServerFind Client
|
||||||
|
*
|
||||||
|
* @param port The port to contact the server on
|
||||||
|
*/
|
||||||
|
public ServerFindClient(int port){
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests IP from server
|
||||||
|
*
|
||||||
|
* @return The address of the server
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public InetAddress find() throws IOException{
|
||||||
|
InetAddress group = InetAddress.getByName(broadcastAddress);
|
||||||
|
DatagramSocket lan_socket = new DatagramSocket();
|
||||||
|
MulticastSocket Msocket = new MulticastSocket(port);
|
||||||
|
Msocket.joinGroup(group);
|
||||||
|
|
||||||
|
byte[] buf = new byte[256];
|
||||||
|
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, port);
|
||||||
|
lan_socket.send(packet);
|
||||||
|
|
||||||
|
packet = new DatagramPacket(buf, buf.length);
|
||||||
|
Msocket.receive(packet);
|
||||||
|
|
||||||
|
return packet.getAddress();
|
||||||
|
}
|
||||||
|
}
|
||||||
134
src/zutil/network/UpdateClient.java
Normal file
134
src/zutil/network/UpdateClient.java
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
package zutil.network;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import zutil.FileFinder;
|
||||||
|
import zutil.MultiPrintStream;
|
||||||
|
import zutil.ProgressListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class connects to a update server and updates a path
|
||||||
|
* with the servers
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class UpdateClient{
|
||||||
|
private ArrayList<FileHash> clientFileList;
|
||||||
|
private Socket socket;
|
||||||
|
private String path;
|
||||||
|
private ProgressListener progress;
|
||||||
|
private int speed;
|
||||||
|
private long totalReceived;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a UpdateClient
|
||||||
|
*
|
||||||
|
* @param address Address to the UpdateServer
|
||||||
|
* @param port The port on the server
|
||||||
|
* @param path Path to the files to update
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public UpdateClient(String address, int port, String path) throws Exception{
|
||||||
|
clientFileList = UpdateServer.getFileList(path);
|
||||||
|
socket = new Socket(address, port);
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProgressListener(ProgressListener p){
|
||||||
|
progress = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the files
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public void update() throws Exception{
|
||||||
|
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
|
||||||
|
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
|
||||||
|
|
||||||
|
// send client file list
|
||||||
|
out.writeObject(clientFileList);
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
// receive file updates
|
||||||
|
FileHash fileInfo = (FileHash)in.readObject();
|
||||||
|
File tmpPath = FileFinder.find(path);
|
||||||
|
while(!fileInfo.path.isEmpty()){
|
||||||
|
MultiPrintStream.out.println("Updating: "+path+fileInfo.path);
|
||||||
|
// reading new file data
|
||||||
|
File file = new File(tmpPath.getAbsolutePath()+fileInfo.path);
|
||||||
|
File tmpFile = File.createTempFile(file.getName(), ".tmp", tmpPath);
|
||||||
|
tmpFile.getParentFile().mkdirs();
|
||||||
|
tmpFile.deleteOnExit();
|
||||||
|
|
||||||
|
FileOutputStream fileOut = new FileOutputStream(tmpFile);
|
||||||
|
byte[] buffer = new byte[socket.getReceiveBufferSize()];
|
||||||
|
|
||||||
|
int bytesReceived = 0;
|
||||||
|
totalReceived = 0;
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
long timeTotalRecived = 0;
|
||||||
|
|
||||||
|
while((bytesReceived = in.read(buffer)) > 0) {
|
||||||
|
fileOut.write(buffer, 0, bytesReceived);
|
||||||
|
|
||||||
|
if(time+1000 < System.currentTimeMillis()){
|
||||||
|
time = System.currentTimeMillis();
|
||||||
|
speed = (int)(totalReceived - timeTotalRecived);
|
||||||
|
timeTotalRecived = totalReceived;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalReceived += bytesReceived;
|
||||||
|
if(progress != null) progress.progressUpdate(this, fileInfo, (double)totalReceived/fileInfo.size*100);
|
||||||
|
}
|
||||||
|
fileOut.close();
|
||||||
|
speed = 0;
|
||||||
|
|
||||||
|
// delete old file and replace whit new
|
||||||
|
file.delete();
|
||||||
|
if(!tmpFile.renameTo(file)){
|
||||||
|
throw new Exception("Cannot update file: "+file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
// read new message
|
||||||
|
fileInfo = (FileHash)in.readObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiPrintStream.out.println("Update Done!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the speed of the transfer
|
||||||
|
*
|
||||||
|
* @return The speed in bytes/s
|
||||||
|
*/
|
||||||
|
public int speed(){
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total amount of data received for the
|
||||||
|
* current file
|
||||||
|
*
|
||||||
|
* @return The speed in bytes/s
|
||||||
|
*/
|
||||||
|
public long totalReceived(){
|
||||||
|
return totalReceived;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the connection
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void close() throws IOException{
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
165
src/zutil/network/UpdateServer.java
Normal file
165
src/zutil/network/UpdateServer.java
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
package zutil.network;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import zutil.FileFinder;
|
||||||
|
import zutil.Hasher;
|
||||||
|
import zutil.MultiPrintStream;
|
||||||
|
|
||||||
|
public class UpdateServer extends Thread{
|
||||||
|
private ArrayList<FileHash> fileList;
|
||||||
|
private ServerSocket server;
|
||||||
|
private boolean close;
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a UpdateServer Thread
|
||||||
|
*
|
||||||
|
* @param path The path to sync the clients with
|
||||||
|
* @throws IOException
|
||||||
|
* @throws URISyntaxException
|
||||||
|
* @throws NoSuchAlgorithmException
|
||||||
|
*/
|
||||||
|
public UpdateServer(int port, String path) throws Exception{
|
||||||
|
fileList = getFileList(path);
|
||||||
|
server = new ServerSocket(port);
|
||||||
|
close = false;
|
||||||
|
this.path = path;
|
||||||
|
|
||||||
|
this.start();
|
||||||
|
MultiPrintStream.out.println("Update Server Online!!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run(){
|
||||||
|
while (!close){
|
||||||
|
try {
|
||||||
|
new UpdateServerThread(server.accept()).start();
|
||||||
|
MultiPrintStream.out.println("Update Server: Client Connected!!!");
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles all the connecting clients
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
class UpdateServerThread extends Thread{
|
||||||
|
private ObjectOutputStream out;
|
||||||
|
private ObjectInputStream in;
|
||||||
|
private Socket client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a UpdateServerThread
|
||||||
|
* @param client The socket to the client
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public UpdateServerThread(Socket c) throws IOException {
|
||||||
|
client = c;
|
||||||
|
out = new ObjectOutputStream(client.getOutputStream());
|
||||||
|
in = new ObjectInputStream(client.getInputStream());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void run(){
|
||||||
|
try {
|
||||||
|
// receive the clients filelist
|
||||||
|
ArrayList<FileHash> clientFileList = (ArrayList<FileHash>)in.readObject();
|
||||||
|
File tmpPath = FileFinder.find(path);
|
||||||
|
|
||||||
|
for(FileHash file : fileList){
|
||||||
|
if(!clientFileList.contains(file)){
|
||||||
|
// send new file to client
|
||||||
|
out.writeObject(file);
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
// send file data
|
||||||
|
FileInputStream input = new FileInputStream(tmpPath.getAbsolutePath()+file.path);
|
||||||
|
byte[] nextBytes = new byte[client.getSendBufferSize()];
|
||||||
|
int bytesRead = 0;
|
||||||
|
while((bytesRead = input.read(nextBytes)) > 0){
|
||||||
|
out.write(nextBytes,0,bytesRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send update done message
|
||||||
|
out.writeObject(new FileHash("","",0));
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
out.close();
|
||||||
|
in.close();
|
||||||
|
client.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
MultiPrintStream.out.println("Update Server: Client Error!!! "+e.getMessage());
|
||||||
|
} finally {
|
||||||
|
MultiPrintStream.out.println("Update Server: Client Update Done!!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a ArrayList with all the files in the specified folder and there
|
||||||
|
* MD5 hashes
|
||||||
|
*
|
||||||
|
* @param path The path to search
|
||||||
|
* @return A ArrayList with all the files in the path
|
||||||
|
* @throws URISyntaxException
|
||||||
|
* @throws NoSuchAlgorithmException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static ArrayList<FileHash> getFileList(String path) throws Exception{
|
||||||
|
ArrayList<FileHash> fileHash = new ArrayList<FileHash>();
|
||||||
|
|
||||||
|
ArrayList<File> files = FileFinder.search(FileFinder.find(path));
|
||||||
|
for(File file : files){
|
||||||
|
fileHash.add(new FileHash(
|
||||||
|
FileFinder.relativePath(file, path),
|
||||||
|
Hasher.hash(file, "MD5"),
|
||||||
|
file.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileHash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to store the files
|
||||||
|
* and there hashes
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
class FileHash implements Serializable{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public String path;
|
||||||
|
public String hash;
|
||||||
|
public long size;
|
||||||
|
|
||||||
|
public FileHash(String p, String h, long s){
|
||||||
|
path = p;
|
||||||
|
hash = h;
|
||||||
|
size = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object comp){
|
||||||
|
FileHash tmp = (FileHash)comp;
|
||||||
|
return path.equals(tmp.path) && hash.equals(tmp.hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString(){
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
232
src/zutil/network/Zupdater.java
Normal file
232
src/zutil/network/Zupdater.java
Normal file
|
|
@ -0,0 +1,232 @@
|
||||||
|
/*
|
||||||
|
* Zupdater.java
|
||||||
|
*
|
||||||
|
* Created on den 27 juli 2008, 23:32
|
||||||
|
*/
|
||||||
|
|
||||||
|
package zutil.network;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
|
||||||
|
import zutil.ProgressListener;
|
||||||
|
import zutil.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
public class Zupdater extends javax.swing.JFrame implements ProgressListener{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** Creates new form Zupdater */
|
||||||
|
public Zupdater() {
|
||||||
|
super("Zupdater");
|
||||||
|
initComponents();
|
||||||
|
centerScreen();
|
||||||
|
setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void centerScreen(){
|
||||||
|
Dimension screen = getToolkit().getScreenSize();
|
||||||
|
this.setBounds(
|
||||||
|
(screen.width-getWidth())/2,
|
||||||
|
(screen.height-getHeight())/2,
|
||||||
|
getWidth(),
|
||||||
|
getHeight() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void progressUpdate(Object source, Object info, double percent) {
|
||||||
|
if(info instanceof FileHash){
|
||||||
|
FileHash fileHash = (FileHash) info;
|
||||||
|
fileLabel.setText(fileHash.toString());
|
||||||
|
fileProgressBar.setValue((int)percent);
|
||||||
|
percentLabel.setText((int)percent+"%");
|
||||||
|
|
||||||
|
speedLabel.setText(StringUtil.formatBytesToString(((UpdateClient)source).speed())+"/s");
|
||||||
|
transferedLabel.setText(StringUtil.formatBytesToString(((UpdateClient)source).totalReceived())+
|
||||||
|
" / "+StringUtil.formatBytesToString(fileHash.size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This method is called from within the constructor to
|
||||||
|
* initialize the form.
|
||||||
|
* WARNING: Do NOT modify this code. The content of this method is
|
||||||
|
* always regenerated by the Form Editor.
|
||||||
|
*/
|
||||||
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">
|
||||||
|
private void initComponents() {
|
||||||
|
|
||||||
|
jSeparator1 = new javax.swing.JSeparator();
|
||||||
|
cancelButton = new javax.swing.JButton();
|
||||||
|
jPanel1 = new javax.swing.JPanel();
|
||||||
|
jLabel1 = new javax.swing.JLabel();
|
||||||
|
totalProgressBar = new javax.swing.JProgressBar();
|
||||||
|
jLabel2 = new javax.swing.JLabel();
|
||||||
|
fileProgressBar = new javax.swing.JProgressBar();
|
||||||
|
fileLabel = new javax.swing.JLabel();
|
||||||
|
totalProgressLabel = new javax.swing.JLabel();
|
||||||
|
speedLabel = new javax.swing.JLabel();
|
||||||
|
percentLabel = new javax.swing.JLabel();
|
||||||
|
transferedLabel = new javax.swing.JLabel();
|
||||||
|
etaLabel = new javax.swing.JLabel();
|
||||||
|
jLabel3 = new javax.swing.JLabel();
|
||||||
|
|
||||||
|
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
|
||||||
|
|
||||||
|
cancelButton.setText("Cancel");
|
||||||
|
cancelButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Update"));
|
||||||
|
|
||||||
|
jLabel1.setFont(new java.awt.Font("Tahoma", 1, 11));
|
||||||
|
jLabel1.setText("Total Progress:");
|
||||||
|
|
||||||
|
totalProgressBar.setIndeterminate(true);
|
||||||
|
|
||||||
|
jLabel2.setFont(new java.awt.Font("Tahoma", 1, 11));
|
||||||
|
jLabel2.setText("File: ");
|
||||||
|
|
||||||
|
fileLabel.setFont(new java.awt.Font("Tahoma", 0, 11));
|
||||||
|
fileLabel.setText("file");
|
||||||
|
|
||||||
|
totalProgressLabel.setFont(new java.awt.Font("Tahoma", 0, 11));
|
||||||
|
totalProgressLabel.setText("totalProgress");
|
||||||
|
|
||||||
|
speedLabel.setFont(new java.awt.Font("Tahoma", 1, 11));
|
||||||
|
speedLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
|
||||||
|
speedLabel.setText("speed");
|
||||||
|
|
||||||
|
percentLabel.setFont(new java.awt.Font("Tahoma", 1, 11));
|
||||||
|
percentLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||||
|
percentLabel.setText("0%");
|
||||||
|
|
||||||
|
transferedLabel.setFont(new java.awt.Font("Tahoma", 2, 11));
|
||||||
|
transferedLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
|
||||||
|
transferedLabel.setText("transfer");
|
||||||
|
|
||||||
|
etaLabel.setFont(new java.awt.Font("Tahoma", 0, 11));
|
||||||
|
etaLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
|
||||||
|
etaLabel.setText("eta");
|
||||||
|
|
||||||
|
jLabel3.setFont(new java.awt.Font("Tahoma", 1, 11));
|
||||||
|
jLabel3.setText("ETA:");
|
||||||
|
|
||||||
|
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
|
||||||
|
jPanel1.setLayout(jPanel1Layout);
|
||||||
|
jPanel1Layout.setHorizontalGroup(
|
||||||
|
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
|
.addComponent(jLabel1)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(totalProgressLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 464, Short.MAX_VALUE))
|
||||||
|
.addComponent(totalProgressBar, javax.swing.GroupLayout.DEFAULT_SIZE, 555, Short.MAX_VALUE)
|
||||||
|
.addComponent(fileProgressBar, javax.swing.GroupLayout.DEFAULT_SIZE, 555, Short.MAX_VALUE)
|
||||||
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(jLabel2)
|
||||||
|
.addComponent(jLabel3))
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
|
.addComponent(etaLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 175, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(percentLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(transferedLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 207, Short.MAX_VALUE))
|
||||||
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
|
.addComponent(fileLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 399, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(speedLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 119, Short.MAX_VALUE)))))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
jPanel1Layout.setVerticalGroup(
|
||||||
|
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
|
.addComponent(jLabel1)
|
||||||
|
.addComponent(totalProgressLabel))
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(totalProgressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
|
.addComponent(jLabel2)
|
||||||
|
.addComponent(fileLabel)
|
||||||
|
.addComponent(speedLabel))
|
||||||
|
.addGap(6, 6, 6)
|
||||||
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
|
.addComponent(jLabel3)
|
||||||
|
.addComponent(etaLabel)
|
||||||
|
.addComponent(transferedLabel)
|
||||||
|
.addComponent(percentLabel))
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(fileProgressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||||
|
);
|
||||||
|
|
||||||
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||||
|
getContentPane().setLayout(layout);
|
||||||
|
layout.setHorizontalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(jSeparator1, javax.swing.GroupLayout.DEFAULT_SIZE, 587, Short.MAX_VALUE)
|
||||||
|
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addComponent(cancelButton, javax.swing.GroupLayout.Alignment.TRAILING))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
layout.setVerticalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(cancelButton)
|
||||||
|
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||||
|
);
|
||||||
|
|
||||||
|
pack();
|
||||||
|
}// </editor-fold>
|
||||||
|
|
||||||
|
public void cancel(){
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param args the command line arguments
|
||||||
|
*/
|
||||||
|
public static void main(String args[]) {
|
||||||
|
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
new Zupdater().setVisible(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variables declaration - do not modify
|
||||||
|
private javax.swing.JButton cancelButton;
|
||||||
|
private javax.swing.JLabel etaLabel;
|
||||||
|
private javax.swing.JLabel fileLabel;
|
||||||
|
private javax.swing.JProgressBar fileProgressBar;
|
||||||
|
private javax.swing.JLabel jLabel1;
|
||||||
|
private javax.swing.JLabel jLabel2;
|
||||||
|
private javax.swing.JLabel jLabel3;
|
||||||
|
private javax.swing.JPanel jPanel1;
|
||||||
|
private javax.swing.JSeparator jSeparator1;
|
||||||
|
private javax.swing.JLabel percentLabel;
|
||||||
|
private javax.swing.JLabel speedLabel;
|
||||||
|
private javax.swing.JProgressBar totalProgressBar;
|
||||||
|
private javax.swing.JLabel totalProgressLabel;
|
||||||
|
private javax.swing.JLabel transferedLabel;
|
||||||
|
// End of variables declaration
|
||||||
|
|
||||||
|
}
|
||||||
28
src/zutil/network/http/HttpPage.java
Normal file
28
src/zutil/network/http/HttpPage.java
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package zutil.network.http;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a interface for a ordinary page for the HttpServer
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface HttpPage{
|
||||||
|
/**
|
||||||
|
* This method has to be implemented for every page.
|
||||||
|
* This method is called when a client wants a response
|
||||||
|
* from this specific page.
|
||||||
|
*
|
||||||
|
* @param out The PrintStream to the client
|
||||||
|
* @param client_info Information about the client
|
||||||
|
* @param session Session values for the client
|
||||||
|
* @param cookie Cookie information from the client
|
||||||
|
* @param request POST and GET requests from the client
|
||||||
|
*/
|
||||||
|
public abstract void respond(HttpPrintStream out,
|
||||||
|
HashMap<String,String> client_info,
|
||||||
|
HashMap<String,String> session,
|
||||||
|
HashMap<String,String> cookie,
|
||||||
|
HashMap<String,String> request);
|
||||||
|
}
|
||||||
135
src/zutil/network/http/HttpPrintStream.java
Normal file
135
src/zutil/network/http/HttpPrintStream.java
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
package zutil.network.http;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This PrintStream is written for HTTP use
|
||||||
|
* It has buffer capabilities and cookie management.
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HttpPrintStream extends PrintStream{
|
||||||
|
private HashMap<String, String> cookie;
|
||||||
|
private StringBuffer buffer;
|
||||||
|
private boolean buffer_enabled;
|
||||||
|
|
||||||
|
public HttpPrintStream(OutputStream out) {
|
||||||
|
super(out);
|
||||||
|
|
||||||
|
cookie = new HashMap<String, String>();
|
||||||
|
buffer = new StringBuffer();
|
||||||
|
buffer_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable the buffering capability of the PrintStream.
|
||||||
|
* Nothing will be sent to the client when buffering
|
||||||
|
* is enabled until you close or flush the stream.
|
||||||
|
*
|
||||||
|
* @param b
|
||||||
|
*/
|
||||||
|
public void enableBuffering(boolean b){
|
||||||
|
buffer_enabled = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a cookie that will be sent to the client
|
||||||
|
*
|
||||||
|
* @param key The name of the cookie
|
||||||
|
* @param value The value of the cookie
|
||||||
|
* @throws Exception Throws exception if the header has already been sent
|
||||||
|
*/
|
||||||
|
public void setCookie(String key, String value) throws Exception{
|
||||||
|
if(cookie == null)
|
||||||
|
throw new Exception("Header already sent!!!");
|
||||||
|
cookie.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the given header directly to the client.
|
||||||
|
* No buffering involved.
|
||||||
|
*
|
||||||
|
* @param header The header to send
|
||||||
|
* @throws Exception Throws exception if the header has already been sent
|
||||||
|
*/
|
||||||
|
public void sendHeader(String header) throws Exception{
|
||||||
|
if(cookie == null)
|
||||||
|
throw new Exception("Header already sent!!!");
|
||||||
|
super.println(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prints whit a new line
|
||||||
|
*/
|
||||||
|
public void println(String s){
|
||||||
|
printOrBuffer(s+"\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOT TO BE USED!!!!
|
||||||
|
* use printOrBuffer(String s) instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public void print(String s){
|
||||||
|
super.print(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prints to all
|
||||||
|
*/
|
||||||
|
public void printOrBuffer(String s){
|
||||||
|
if(buffer_enabled){
|
||||||
|
buffer.append(s);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(cookie != null){
|
||||||
|
for(String key : cookie.keySet()){
|
||||||
|
super.println("Set-Cookie: "+key+"="+cookie.get(key)+"; ");
|
||||||
|
}
|
||||||
|
super.println(" \n");
|
||||||
|
cookie = null;
|
||||||
|
}
|
||||||
|
super.print(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends out all the buffer and clears it
|
||||||
|
*/
|
||||||
|
public void flush(){
|
||||||
|
if(buffer_enabled){
|
||||||
|
buffer_enabled = false;
|
||||||
|
printOrBuffer(buffer.toString());
|
||||||
|
buffer.delete(0, buffer.length());
|
||||||
|
buffer_enabled = true;
|
||||||
|
}
|
||||||
|
super.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close(){
|
||||||
|
flush();
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void println(){ println("");}
|
||||||
|
public void println(boolean x){ println(""+x);}
|
||||||
|
public void println(char x){ println(""+x);}
|
||||||
|
public void println(char[] x){ println(new String(x));}
|
||||||
|
public void println(double x){ println(""+x);}
|
||||||
|
public void println(float x){ println(""+x);}
|
||||||
|
public void println(int x){ println(""+x);}
|
||||||
|
public void println(long x){ println(""+x);}
|
||||||
|
public void println(Object x){ println(""+x);}
|
||||||
|
|
||||||
|
public void print(boolean x){ printOrBuffer(""+x);}
|
||||||
|
public void print(char x){ printOrBuffer(""+x);}
|
||||||
|
public void print(char[] x){ printOrBuffer(new String(x));}
|
||||||
|
public void print(double x){ printOrBuffer(""+x);}
|
||||||
|
public void print(float x){ printOrBuffer(""+x);}
|
||||||
|
public void print(int x){ printOrBuffer(""+x);}
|
||||||
|
public void print(long x){ printOrBuffer(""+x);}
|
||||||
|
public void print(Object x){ printOrBuffer(""+x);}
|
||||||
|
}
|
||||||
282
src/zutil/network/http/HttpServer.java
Normal file
282
src/zutil/network/http/HttpServer.java
Normal file
|
|
@ -0,0 +1,282 @@
|
||||||
|
package zutil.network.http;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import zutil.MultiPrintStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple web server that handles both cookies and
|
||||||
|
* sessions for all the clients
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
* TODO: File upload
|
||||||
|
*/
|
||||||
|
public class HttpServer extends Thread{
|
||||||
|
public static final boolean DEBUG = false;
|
||||||
|
public static final String SERVER_VERSION = "Evil HttpServer 1.0";
|
||||||
|
public static final int COOKIE_TTL = 200;
|
||||||
|
public static final int SESSION_TTL = 200;
|
||||||
|
|
||||||
|
public final String server_url;
|
||||||
|
public final int server_port;
|
||||||
|
|
||||||
|
private HashMap<String,HttpPage> pages;
|
||||||
|
private HttpPage defaultPage;
|
||||||
|
private HashMap<String,HashMap<String,String>> sessions;
|
||||||
|
private int nextSessionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of the sever
|
||||||
|
*
|
||||||
|
* @param url The address to the server
|
||||||
|
* @param port The port that the server should listen to
|
||||||
|
*/
|
||||||
|
public HttpServer(String url, int port){
|
||||||
|
this.server_url = url;
|
||||||
|
this.server_port = port;
|
||||||
|
|
||||||
|
pages = new HashMap<String,HttpPage>();
|
||||||
|
sessions = new HashMap<String,HashMap<String,String>>();
|
||||||
|
nextSessionId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a HttpPage to a specific URL
|
||||||
|
*
|
||||||
|
* @param name The URL or name of the page
|
||||||
|
* @param page The page itself
|
||||||
|
*/
|
||||||
|
public void setPage(String name, HttpPage page){
|
||||||
|
pages.put(name, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a default page that will be shown
|
||||||
|
* if there is no other matching page,
|
||||||
|
*
|
||||||
|
* @param page The HttpPage that will be shown
|
||||||
|
*/
|
||||||
|
public void setDefaultPage(HttpPage page){
|
||||||
|
defaultPage = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run(){
|
||||||
|
try{
|
||||||
|
ServerSocket ss = new ServerSocket(server_port);
|
||||||
|
MultiPrintStream.out.println("Http Server Running!!!");
|
||||||
|
|
||||||
|
while(true){
|
||||||
|
new HttpServerThread(ss.accept());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal class that handles all the requests
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class HttpServerThread extends Thread{
|
||||||
|
private HttpPrintStream out;
|
||||||
|
private BufferedReader in;
|
||||||
|
private Socket socket;
|
||||||
|
|
||||||
|
public HttpServerThread(Socket socket) throws IOException{
|
||||||
|
out = new HttpPrintStream(socket.getOutputStream());
|
||||||
|
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
this.socket = socket;
|
||||||
|
start();
|
||||||
|
if(DEBUG)MultiPrintStream.out.println("New Connection!!! "+socket.getInetAddress().getHostName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run(){
|
||||||
|
String tmp = null;
|
||||||
|
int tmpi;
|
||||||
|
|
||||||
|
String page_url = "";
|
||||||
|
HashMap<String,String> client_info = new HashMap<String,String>();
|
||||||
|
HashMap<String,String> cookie = new HashMap<String,String>();
|
||||||
|
HashMap<String,String> request = new HashMap<String,String>();
|
||||||
|
|
||||||
|
//**************************** REQUEST *********************************
|
||||||
|
try {
|
||||||
|
if(DEBUG)MultiPrintStream.out.println("Reciving Http Request!!!");
|
||||||
|
while(!(tmp=in.readLine()).isEmpty()){
|
||||||
|
//System.err.println(tmp);
|
||||||
|
//*********** Handling Get variables
|
||||||
|
if(tmp.startsWith("GET")){
|
||||||
|
// Gets the file URL and get values
|
||||||
|
tmp = (tmp.substring(5, tmp.indexOf("HTTP/"))).trim();
|
||||||
|
page_url = parseHttpHeader(tmp, request);
|
||||||
|
}
|
||||||
|
//********* Handling Post variable data
|
||||||
|
else if(tmp.startsWith("POST")){
|
||||||
|
// Gets the file URL and get values
|
||||||
|
tmp = (tmp.substring(6, tmp.indexOf("HTTP/"))).trim();
|
||||||
|
page_url = parseHttpHeader(tmp, request);
|
||||||
|
}
|
||||||
|
//********* Handling Cookies
|
||||||
|
else if(tmp.startsWith("Cookie")){
|
||||||
|
tmp = tmp.substring(tmp.indexOf(':')+1, tmp.length());
|
||||||
|
while(!tmp.isEmpty()){
|
||||||
|
tmpi = ( (tmpi = tmp.indexOf(';')) == -1 ? tmp.length() : tmpi);
|
||||||
|
cookie.put(
|
||||||
|
(tmp.substring(0, tmp.indexOf('=')).trim() ), // Key
|
||||||
|
(tmp.substring(tmp.indexOf('=')+1, tmpi)).trim() ); //Value
|
||||||
|
if(tmp.indexOf(';') > 0)
|
||||||
|
tmp = tmp.substring(tmp.indexOf(';')+1, tmp.length());
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//********* Handling Client info
|
||||||
|
else{
|
||||||
|
if(tmp.indexOf(':') > -1){
|
||||||
|
client_info.put(
|
||||||
|
(tmp.substring(0, tmp.indexOf(':')).trim() ), // Key
|
||||||
|
(tmp.substring(tmp.indexOf(':')+1, tmp.length())).trim() ); //Value
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
MultiPrintStream.out.println("Faild to parsse header: "+tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******* Read in the post data if available
|
||||||
|
if(client_info.containsKey("Content-Length")){
|
||||||
|
// Reads the post data size
|
||||||
|
tmp = client_info.get("Content-Length");
|
||||||
|
int post_data_length = Integer.parseInt(
|
||||||
|
tmp.substring(tmp.indexOf(':')+1, tmp.length()).trim() );
|
||||||
|
|
||||||
|
if(client_info.get("Content-Type").equals("application/x-www-form-urlencoded")){
|
||||||
|
StringBuffer tmpb = new StringBuffer();
|
||||||
|
// read the data
|
||||||
|
for(int i=0; i<post_data_length ;i++){
|
||||||
|
tmpb.append((char)in.read());
|
||||||
|
}
|
||||||
|
// get the variables
|
||||||
|
parseVariables(tmpb.toString(), request);
|
||||||
|
}
|
||||||
|
else if(client_info.get("Content-Type").contains("multipart/form-data")){
|
||||||
|
// TODO:
|
||||||
|
throw new Exception("\"multipart/form-data\" Not implemented!!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//*****************
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
try {
|
||||||
|
out.sendHeader("HTTP/1.0 500 ERROR");
|
||||||
|
} catch (Exception e1) {}
|
||||||
|
out.println("500 Internal Error(Header: "+tmp+"): "+e.getMessage());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
//**************************** HANDLE REQUEST *********************************
|
||||||
|
// Get the client session or create one
|
||||||
|
HashMap<String,String> client_session;
|
||||||
|
if(cookie.containsKey("session_id") && sessions.containsKey(cookie.get("session_id"))){
|
||||||
|
client_session = sessions.get(cookie.get("session_id"));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
client_session = new HashMap<String,String>();
|
||||||
|
client_session.put("session_id", ""+nextSessionId);
|
||||||
|
sessions.put(""+nextSessionId, client_session);
|
||||||
|
nextSessionId++;
|
||||||
|
}
|
||||||
|
// Debug
|
||||||
|
if(DEBUG){
|
||||||
|
MultiPrintStream.out.println("# page_url: "+page_url);
|
||||||
|
MultiPrintStream.out.println("# cookie: "+cookie);
|
||||||
|
MultiPrintStream.out.println("# client_session: "+client_session);
|
||||||
|
MultiPrintStream.out.println("# client_info: "+client_info);
|
||||||
|
MultiPrintStream.out.println("# request: "+request);
|
||||||
|
}
|
||||||
|
//**************************** RESPONSE ************************************
|
||||||
|
if(DEBUG)MultiPrintStream.out.println("Sending Http Response!!!");
|
||||||
|
out.sendHeader("HTTP/1.0 200 OK");
|
||||||
|
out.sendHeader("Server: "+SERVER_VERSION);
|
||||||
|
out.sendHeader("Content-Type: text/html");
|
||||||
|
out.setCookie("session_id", client_session.get("session_id"));
|
||||||
|
|
||||||
|
|
||||||
|
if(!page_url.isEmpty() && pages.containsKey(page_url)){
|
||||||
|
pages.get(page_url).respond(out, client_info, client_session, cookie, request);
|
||||||
|
}
|
||||||
|
else if(defaultPage != null){
|
||||||
|
defaultPage.respond(out, client_info, client_session, cookie, request);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
out.println("404 ERROR");
|
||||||
|
}
|
||||||
|
|
||||||
|
//********************************************************************************
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
out.println("500 Internal Error: "+e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
if(DEBUG)MultiPrintStream.out.println("Conection Closed!!!");
|
||||||
|
out.close();
|
||||||
|
in.close();
|
||||||
|
socket.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the first header line and ads the values to
|
||||||
|
* the map and returns the file name and path
|
||||||
|
*
|
||||||
|
* @param header The header String
|
||||||
|
* @param map The HashMap to put the variables to
|
||||||
|
* @return The path and file name as a String
|
||||||
|
*/
|
||||||
|
private String parseHttpHeader(String header, HashMap<String, String> map){
|
||||||
|
String page_url = "";
|
||||||
|
// cut out the page name
|
||||||
|
if(header.indexOf('?') > -1){
|
||||||
|
page_url = header.substring(0, header.indexOf('?'));
|
||||||
|
header = header.substring(header.indexOf('?')+1, header.length());
|
||||||
|
parseVariables(header, map);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
page_url = header;
|
||||||
|
}
|
||||||
|
|
||||||
|
return page_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a String with variables from a get or post
|
||||||
|
* from a client and puts the data into a HashMap
|
||||||
|
*
|
||||||
|
* @param header A String with all the variables
|
||||||
|
* @param map The HashMap to put all the variables into
|
||||||
|
*/
|
||||||
|
private void parseVariables(String header, HashMap<String, String> map){
|
||||||
|
int tmpi;
|
||||||
|
// get the variables
|
||||||
|
while(!header.isEmpty()){
|
||||||
|
tmpi = ( (tmpi = header.indexOf('&')) == -1 ? header.length() : tmpi);
|
||||||
|
map.put(
|
||||||
|
(header.substring(0, header.indexOf('=')).trim() ), // Key
|
||||||
|
(header.substring(header.indexOf('=')+1, tmpi )).trim() ); //Value
|
||||||
|
if(header.indexOf('&') > 0)
|
||||||
|
header = header.substring(header.indexOf('&')+1, header.length());
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
src/zutil/network/nio/NioClient.java
Normal file
57
src/zutil/network/nio/NioClient.java
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
package zutil.network.nio;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.channels.Selector;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.channels.spi.SelectorProvider;
|
||||||
|
|
||||||
|
import zutil.network.nio.message.Message;
|
||||||
|
import zutil.network.nio.message.type.ResponseRequestMessage;
|
||||||
|
import zutil.network.nio.response.ResponseEvent;
|
||||||
|
|
||||||
|
|
||||||
|
public class NioClient extends NioNetwork{
|
||||||
|
private SocketChannel serverSocket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a NioClient that connects to a server
|
||||||
|
*
|
||||||
|
* @param hostAddress The server address
|
||||||
|
* @param port The port to listen on
|
||||||
|
*/
|
||||||
|
public NioClient(InetAddress serverAddress, int port) throws IOException {
|
||||||
|
super(InetAddress.getLocalHost(), port, NetworkType.CLIENT);
|
||||||
|
serverSocket = initiateConnection(new InetSocketAddress(serverAddress, port));
|
||||||
|
Thread thread = new Thread(this);
|
||||||
|
thread.setDaemon(false);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Selector initSelector() throws IOException {
|
||||||
|
// Create a new selector
|
||||||
|
return SelectorProvider.provider().openSelector();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a Message to the default server
|
||||||
|
*
|
||||||
|
* @param data The data to be sent
|
||||||
|
* @throws IOException Something got wrong
|
||||||
|
*/
|
||||||
|
public void send(Message data) throws IOException {
|
||||||
|
send(serverSocket, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is for the Client to send a message to the server
|
||||||
|
*
|
||||||
|
* @param handler The response handler
|
||||||
|
* @param data The data to send
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void send(ResponseEvent handler, ResponseRequestMessage data) throws IOException {
|
||||||
|
send(serverSocket, handler, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
433
src/zutil/network/nio/NioNetwork.java
Normal file
433
src/zutil/network/nio/NioNetwork.java
Normal file
|
|
@ -0,0 +1,433 @@
|
||||||
|
package zutil.network.nio;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ConnectException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.SelectionKey;
|
||||||
|
import java.nio.channels.Selector;
|
||||||
|
import java.nio.channels.ServerSocketChannel;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import zutil.Converter;
|
||||||
|
import zutil.Encrypter;
|
||||||
|
import zutil.MultiPrintStream;
|
||||||
|
import zutil.network.nio.message.type.ResponseRequestMessage;
|
||||||
|
import zutil.network.nio.message.type.SystemMessage;
|
||||||
|
import zutil.network.nio.response.ResponseEvent;
|
||||||
|
import zutil.network.nio.server.ChangeRequest;
|
||||||
|
import zutil.network.nio.server.ClientData;
|
||||||
|
import zutil.network.nio.worker.SystemWorker;
|
||||||
|
import zutil.network.nio.worker.Worker;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class NioNetwork implements Runnable {
|
||||||
|
/**
|
||||||
|
* Debug level
|
||||||
|
* 0 = nothing
|
||||||
|
* 1 = connection debug
|
||||||
|
* 2 = message debug
|
||||||
|
* 3 = selector debug
|
||||||
|
*/
|
||||||
|
public static final int DEBUG = 1;
|
||||||
|
public static enum NetworkType {SERVER, CLIENT};
|
||||||
|
|
||||||
|
private NetworkType type;
|
||||||
|
|
||||||
|
// The host:port combination to listen on
|
||||||
|
protected InetAddress address;
|
||||||
|
protected int port;
|
||||||
|
|
||||||
|
// The channel on which we'll accept connections
|
||||||
|
protected ServerSocketChannel serverChannel;
|
||||||
|
// The selector we'll be monitoring
|
||||||
|
private Selector selector;
|
||||||
|
// The buffer into which we'll read data when it's available
|
||||||
|
private ByteBuffer readBuffer = ByteBuffer.allocate(8192);
|
||||||
|
protected Worker worker;
|
||||||
|
protected SystemWorker systemWorker;
|
||||||
|
|
||||||
|
// This map contains all the clients that are conncted
|
||||||
|
protected Map<InetSocketAddress, ClientData> clients = new HashMap<InetSocketAddress, ClientData>();
|
||||||
|
|
||||||
|
// A list of PendingChange instances
|
||||||
|
private List<ChangeRequest> pendingChanges = new LinkedList<ChangeRequest>();
|
||||||
|
// Maps a SocketChannel to a list of ByteBuffer instances
|
||||||
|
private Map<SocketChannel, List<ByteBuffer>> pendingData = new HashMap<SocketChannel, List<ByteBuffer>>();
|
||||||
|
// The encrypter
|
||||||
|
private Encrypter encrypter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a nio network class
|
||||||
|
*
|
||||||
|
* @param hostAddress The host address
|
||||||
|
* @param port The port
|
||||||
|
* @param type The type of network host
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public NioNetwork(InetAddress address, int port, NetworkType type) throws IOException {
|
||||||
|
this.port = port;
|
||||||
|
this.address = address;
|
||||||
|
this.type = type;
|
||||||
|
this.selector = initSelector();
|
||||||
|
this.systemWorker = new SystemWorker(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Selector initSelector() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Worker for the network messages
|
||||||
|
*
|
||||||
|
* @param worker The worker that handles the incoming messages
|
||||||
|
*/
|
||||||
|
public void setDefaultWorker(Worker worker){
|
||||||
|
this.worker = worker;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the encrypter to use in the network
|
||||||
|
*
|
||||||
|
* @param enc The encrypter to use or null fo no encryption
|
||||||
|
*/
|
||||||
|
public void setEncrypter(Encrypter enc){
|
||||||
|
encrypter = enc;
|
||||||
|
MultiPrintStream.out.println("Network Encryption "+
|
||||||
|
(encrypter != null ? "Enabled("+encrypter.getAlgorithm()+")" : "Disabled")+"!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(SocketChannel socket, Object data) {
|
||||||
|
send(socket, Converter.toBytes(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(InetSocketAddress address, Object data){
|
||||||
|
send(address, Converter.toBytes(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(InetSocketAddress address, byte[] data){
|
||||||
|
send(getSocketChannel(address), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(SocketChannel socket, ResponseEvent handler, ResponseRequestMessage data) throws IOException {
|
||||||
|
// Register the response handler
|
||||||
|
systemWorker.addResponseHandler(handler, data);
|
||||||
|
|
||||||
|
queueSend(socket,Converter.toBytes(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sends data true the given socket
|
||||||
|
*
|
||||||
|
* @param socket The socket
|
||||||
|
* @param data The data to send
|
||||||
|
*/
|
||||||
|
public void send(SocketChannel socket, byte[] data) {
|
||||||
|
queueSend(socket,data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queues the message to be sent and wakeups the selector
|
||||||
|
*
|
||||||
|
* @param socket The socet to send the message thrue
|
||||||
|
* @param data The data to send
|
||||||
|
*/
|
||||||
|
protected void queueSend(SocketChannel socket, byte[] data){
|
||||||
|
if(DEBUG>=3)MultiPrintStream.out.println("Sending Queue...");
|
||||||
|
// And queue the data we want written
|
||||||
|
synchronized (pendingData) {
|
||||||
|
List<ByteBuffer> queue = pendingData.get(socket);
|
||||||
|
if (queue == null) {
|
||||||
|
queue = new ArrayList<ByteBuffer>();
|
||||||
|
pendingData.put(socket, queue);
|
||||||
|
}
|
||||||
|
//encrypts
|
||||||
|
if(encrypter != null)
|
||||||
|
queue.add(ByteBuffer.wrap(encrypter.encrypt(data)));
|
||||||
|
else queue.add(ByteBuffer.wrap(data));
|
||||||
|
}
|
||||||
|
// Changing the key state to write
|
||||||
|
synchronized (pendingChanges) {
|
||||||
|
// Indicate we want the interest ops set changed
|
||||||
|
pendingChanges.add(new ChangeRequest(socket, ChangeRequest.CHANGEOPS, SelectionKey.OP_WRITE));
|
||||||
|
}
|
||||||
|
if(DEBUG>=3)MultiPrintStream.out.println("selector.wakeup();");
|
||||||
|
// Finally, wake up our selecting thread so it can make the required changes
|
||||||
|
selector.wakeup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
if(DEBUG>=1)MultiPrintStream.out.println("NioNetwork Started!!!");
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
// Process any pending changes
|
||||||
|
synchronized (pendingChanges) {
|
||||||
|
Iterator<ChangeRequest> changes = pendingChanges.iterator();
|
||||||
|
while (changes.hasNext()) {
|
||||||
|
ChangeRequest change = changes.next();
|
||||||
|
switch (change.type) {
|
||||||
|
case ChangeRequest.CHANGEOPS:
|
||||||
|
SelectionKey key = change.socket.keyFor(selector);
|
||||||
|
key.interestOps(change.ops);
|
||||||
|
if(DEBUG>=3)MultiPrintStream.out.println("change.ops "+change.ops);
|
||||||
|
break;
|
||||||
|
case ChangeRequest.REGISTER:
|
||||||
|
change.socket.register(selector, change.ops);
|
||||||
|
if(DEBUG>=3)MultiPrintStream.out.println("register socket ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pendingChanges.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for an event one of the registered channels
|
||||||
|
selector.select();
|
||||||
|
if(DEBUG>=3)MultiPrintStream.out.println("selector is awake");
|
||||||
|
|
||||||
|
// Iterate over the set of keys for which events are available
|
||||||
|
Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
|
||||||
|
while (selectedKeys.hasNext()) {
|
||||||
|
SelectionKey key = (SelectionKey) selectedKeys.next();
|
||||||
|
selectedKeys.remove();
|
||||||
|
if(DEBUG>=3)MultiPrintStream.out.println("KeyOP: "+key.interestOps()+" isAcceptable: "+SelectionKey.OP_ACCEPT+" isConnectable: "+SelectionKey.OP_CONNECT+" isWritable: "+SelectionKey.OP_WRITE+" isReadable: "+SelectionKey.OP_READ);
|
||||||
|
|
||||||
|
if (key.isValid()) {
|
||||||
|
// Check what event is available and deal with it
|
||||||
|
if (key.isAcceptable()) {
|
||||||
|
if(DEBUG>=3)MultiPrintStream.out.println("Accepting Connection!!");
|
||||||
|
accept(key);
|
||||||
|
}
|
||||||
|
else if (key.isConnectable()) {
|
||||||
|
if(DEBUG>=3)MultiPrintStream.out.println("Finnishing Connection!!");
|
||||||
|
finishConnection(key);
|
||||||
|
}
|
||||||
|
else if (key.isWritable()) {
|
||||||
|
if(DEBUG>=3)MultiPrintStream.out.println("Writing");
|
||||||
|
write(key);
|
||||||
|
}
|
||||||
|
else if (key.isReadable()) {
|
||||||
|
if(DEBUG>=3)MultiPrintStream.out.println("Reading");
|
||||||
|
read(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server
|
||||||
|
*/
|
||||||
|
private void accept(SelectionKey key) throws IOException {
|
||||||
|
// For an accept to be pending the channel must be a server socket channel.
|
||||||
|
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
|
||||||
|
|
||||||
|
// Accept the connection and make it non-blocking
|
||||||
|
SocketChannel socketChannel = serverSocketChannel.accept();
|
||||||
|
socketChannel.socket().setReuseAddress(true);
|
||||||
|
socketChannel.configureBlocking(false);
|
||||||
|
|
||||||
|
// Register the new SocketChannel with our Selector, indicating
|
||||||
|
// we'd like to be notified when there's data waiting to be read
|
||||||
|
socketChannel.register(selector, SelectionKey.OP_READ);
|
||||||
|
|
||||||
|
// adds the client to the clients list
|
||||||
|
InetSocketAddress remoteAdr = (InetSocketAddress) socketChannel.socket().getRemoteSocketAddress();
|
||||||
|
if(!clients.containsValue(remoteAdr)){
|
||||||
|
clients.put(remoteAdr, new ClientData(socketChannel));
|
||||||
|
if(DEBUG>=1)MultiPrintStream.out.println("New Connection("+remoteAdr+")!!! Count: "+clients.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client and Server
|
||||||
|
*/
|
||||||
|
private void read(SelectionKey key) throws IOException {
|
||||||
|
SocketChannel socketChannel = (SocketChannel) key.channel();
|
||||||
|
InetSocketAddress remoteAdr = (InetSocketAddress) socketChannel.socket().getRemoteSocketAddress();
|
||||||
|
|
||||||
|
// Clear out our read buffer so it's ready for new data
|
||||||
|
readBuffer.clear();
|
||||||
|
|
||||||
|
// Attempt to read off the channel
|
||||||
|
int numRead;
|
||||||
|
try {
|
||||||
|
numRead = socketChannel.read(readBuffer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// The remote forcibly closed the connection, cancel
|
||||||
|
// the selection key and close the channel.
|
||||||
|
key.cancel();
|
||||||
|
socketChannel.close();
|
||||||
|
clients.remove(remoteAdr);
|
||||||
|
if(DEBUG>=1)MultiPrintStream.out.println("Connection Forced Close("+remoteAdr+")!!! Connection Count: "+clients.size());
|
||||||
|
if(type == NetworkType.CLIENT) throw new ConnectException("Server Closed The Connection!!!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numRead == -1) {
|
||||||
|
// Remote entity shut the socket down cleanly. Do the
|
||||||
|
// same from our end and cancel the channel.
|
||||||
|
key.channel().close();
|
||||||
|
key.cancel();
|
||||||
|
clients.remove(remoteAdr);
|
||||||
|
if(DEBUG>=1)MultiPrintStream.out.println("Connection Close("+remoteAdr+")!!! Connection Count: "+clients.size());
|
||||||
|
if(type == NetworkType.CLIENT) throw new ConnectException("Server Closed The Connection!!!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a correctly sized copy of the data before handing it
|
||||||
|
// to the client
|
||||||
|
byte[] rspByteData = new byte[numRead];
|
||||||
|
System.arraycopy(readBuffer.array(), 0, rspByteData, 0, numRead);
|
||||||
|
|
||||||
|
handleRecivedMessage(socketChannel, rspByteData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client and Server
|
||||||
|
*/
|
||||||
|
private void write(SelectionKey key) throws IOException {
|
||||||
|
SocketChannel socketChannel = (SocketChannel) key.channel();
|
||||||
|
|
||||||
|
synchronized (pendingData) {
|
||||||
|
List<ByteBuffer> queue = pendingData.get(socketChannel);
|
||||||
|
if(queue == null){
|
||||||
|
queue = new ArrayList<ByteBuffer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write until there's not more data ...
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
ByteBuffer buf = queue.get(0);
|
||||||
|
socketChannel.write(buf);
|
||||||
|
if (buf.remaining() > 0) {
|
||||||
|
// ... or the socket's buffer fills up
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
queue.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queue.isEmpty()) {
|
||||||
|
// We wrote away all data, so we're no longer interested
|
||||||
|
// in writing on this socket. Switch back to waiting for
|
||||||
|
// data.
|
||||||
|
if(DEBUG>=3)MultiPrintStream.out.println("No more Data to write!!");
|
||||||
|
key.interestOps(SelectionKey.OP_READ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleRecivedMessage(SocketChannel socketChannel, byte[] rspByteData){
|
||||||
|
//Encryption
|
||||||
|
Object rspData;
|
||||||
|
if(encrypter != null)
|
||||||
|
rspData = Converter.toObject(encrypter.decrypt(rspByteData));
|
||||||
|
else rspData = Converter.toObject(rspByteData);
|
||||||
|
if(DEBUG>=2)MultiPrintStream.out.println("Handling incomming message...");
|
||||||
|
|
||||||
|
if(rspData instanceof SystemMessage){
|
||||||
|
if(systemWorker != null){
|
||||||
|
if(DEBUG>=3)MultiPrintStream.out.println("System Message!!!");
|
||||||
|
systemWorker.processData(this, socketChannel, rspData);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(DEBUG>=2)MultiPrintStream.out.println("Unhandled System Message!!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// Hand the data off to our worker thread
|
||||||
|
if(worker != null){
|
||||||
|
if(DEBUG>=3)MultiPrintStream.out.println("Worker Message!!!");
|
||||||
|
worker.processData(this, socketChannel, rspData);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(DEBUG>=1)MultiPrintStream.out.println("Unhandled Message!!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a socket to the server
|
||||||
|
*/
|
||||||
|
protected SocketChannel initiateConnection(InetSocketAddress address) throws IOException {
|
||||||
|
// Create a non-blocking socket channel
|
||||||
|
SocketChannel socketChannel = SocketChannel.open();
|
||||||
|
socketChannel.socket().setReuseAddress(true);
|
||||||
|
socketChannel.configureBlocking(false);
|
||||||
|
if(DEBUG>=1)MultiPrintStream.out.println("Connecting to: "+address);
|
||||||
|
|
||||||
|
// Kick off connection establishment
|
||||||
|
socketChannel.connect(address);
|
||||||
|
|
||||||
|
// Queue a channel registration since the caller is not the
|
||||||
|
// selecting thread. As part of the registration we'll register
|
||||||
|
// an interest in connection events. These are raised when a channel
|
||||||
|
// is ready to complete connection establishment.
|
||||||
|
synchronized(this.pendingChanges) {
|
||||||
|
pendingChanges.add(new ChangeRequest(socketChannel, ChangeRequest.REGISTER, SelectionKey.OP_CONNECT));
|
||||||
|
}
|
||||||
|
|
||||||
|
return socketChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SocketChannel getSocketChannel(InetSocketAddress address){
|
||||||
|
return clients.get(address).getSocketChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client
|
||||||
|
*/
|
||||||
|
private void finishConnection(SelectionKey key){
|
||||||
|
SocketChannel socketChannel = (SocketChannel) key.channel();
|
||||||
|
|
||||||
|
// Finish the connection. If the connection operation failed
|
||||||
|
// this will raise an IOException.
|
||||||
|
try {
|
||||||
|
socketChannel.finishConnect();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Cancel the channel's registration with our selector
|
||||||
|
e.printStackTrace();
|
||||||
|
key.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register an interest in writing on this channel
|
||||||
|
key.interestOps(SelectionKey.OP_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
protected void closeConnection(SocketChannel socketChannel) throws IOException{
|
||||||
|
socketChannel.close();
|
||||||
|
socketChannel.keyFor(selector).cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
protected void closeConnection(InetSocketAddress address) throws IOException{
|
||||||
|
closeConnection(getSocketChannel(address));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public void close() throws IOException{
|
||||||
|
if(serverChannel != null){
|
||||||
|
serverChannel.close();
|
||||||
|
serverChannel.keyFor(selector).cancel();
|
||||||
|
}
|
||||||
|
selector.close();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public NetworkType getType(){
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/zutil/network/nio/NioServer.java
Normal file
68
src/zutil/network/nio/NioServer.java
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
package zutil.network.nio;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.channels.SelectionKey;
|
||||||
|
import java.nio.channels.Selector;
|
||||||
|
import java.nio.channels.ServerSocketChannel;
|
||||||
|
import java.nio.channels.spi.SelectorProvider;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
public class NioServer extends NioNetwork{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a NioServer object which listens on localhost
|
||||||
|
*
|
||||||
|
* @param port The port to listen to
|
||||||
|
*/
|
||||||
|
public NioServer(int port) throws IOException {
|
||||||
|
this(null, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a NioServer object which listens to a specific address
|
||||||
|
*
|
||||||
|
* @param address The address to listen to
|
||||||
|
* @param port The port to listen to
|
||||||
|
*/
|
||||||
|
public NioServer(InetAddress address, int port) throws IOException {
|
||||||
|
super(address, port, NetworkType.SERVER);
|
||||||
|
new Thread(this).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Selector initSelector() throws IOException {
|
||||||
|
// Create a new selector
|
||||||
|
Selector socketSelector = SelectorProvider.provider().openSelector();
|
||||||
|
|
||||||
|
// Create a new non-blocking server socket channel
|
||||||
|
serverChannel = ServerSocketChannel.open();
|
||||||
|
serverChannel.socket().setReuseAddress(true);
|
||||||
|
serverChannel.configureBlocking(false);
|
||||||
|
|
||||||
|
// Bind the server socket to the specified address and port
|
||||||
|
InetSocketAddress isa = new InetSocketAddress(address, port);
|
||||||
|
serverChannel.socket().bind(isa);
|
||||||
|
|
||||||
|
// Register the server socket channel, indicating an interest in
|
||||||
|
// accepting new connections
|
||||||
|
serverChannel.register(socketSelector, SelectionKey.OP_ACCEPT);
|
||||||
|
|
||||||
|
return socketSelector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcasts the message to all the connected clients
|
||||||
|
*
|
||||||
|
* @param data The data to broadcast
|
||||||
|
*/
|
||||||
|
public void broadcast(byte[] data){
|
||||||
|
synchronized(clients){
|
||||||
|
Iterator<InetSocketAddress> it = clients.keySet().iterator();
|
||||||
|
while(it.hasNext()){
|
||||||
|
send(it.next(), data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
45
src/zutil/network/nio/message/ChatMessage.java
Normal file
45
src/zutil/network/nio/message/ChatMessage.java
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
package zutil.network.nio.message;
|
||||||
|
|
||||||
|
public class ChatMessage extends Message{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public static enum ChatMessageType {REGISTER, UNREGISTER, MESSAGE};
|
||||||
|
|
||||||
|
public ChatMessageType type;
|
||||||
|
public String msg;
|
||||||
|
public String room;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the user to the main chat
|
||||||
|
*
|
||||||
|
* @param name Name of user
|
||||||
|
*/
|
||||||
|
public ChatMessage(){
|
||||||
|
this("", "", ChatMessageType.REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the user to the given room
|
||||||
|
*
|
||||||
|
* @param room The room to register to
|
||||||
|
*/
|
||||||
|
public ChatMessage(String room){
|
||||||
|
this("", room, ChatMessageType.REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a message to the given room
|
||||||
|
*
|
||||||
|
* @param msg The message
|
||||||
|
* @param room The room
|
||||||
|
*/
|
||||||
|
public ChatMessage(String msg, String room){
|
||||||
|
this(msg, room, ChatMessageType.MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChatMessage(String msg, String room, ChatMessageType type){
|
||||||
|
this.msg = msg;
|
||||||
|
this.room = room;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/zutil/network/nio/message/GraphicsSyncMessage.java
Normal file
31
src/zutil/network/nio/message/GraphicsSyncMessage.java
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
package zutil.network.nio.message;
|
||||||
|
|
||||||
|
|
||||||
|
public class GraphicsSyncMessage extends SyncMessage{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public float locX;
|
||||||
|
public float locY;
|
||||||
|
public float locZ;
|
||||||
|
|
||||||
|
public float rotX;
|
||||||
|
public float rotY;
|
||||||
|
public float rotZ;
|
||||||
|
public float rotW;
|
||||||
|
|
||||||
|
public GraphicsSyncMessage(String id){
|
||||||
|
this.type = MessageType.SYNC;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object obj){
|
||||||
|
if(obj instanceof GraphicsSyncMessage){
|
||||||
|
GraphicsSyncMessage tmp = (GraphicsSyncMessage)obj;
|
||||||
|
return (tmp.locX == locX && tmp.locY == locY &&
|
||||||
|
tmp.locZ == locZ && tmp.rotX == rotX &&
|
||||||
|
tmp.rotY == rotY && tmp.rotZ == rotZ &&
|
||||||
|
tmp.rotW == rotW);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/zutil/network/nio/message/KeepAliveMessage.java
Normal file
16
src/zutil/network/nio/message/KeepAliveMessage.java
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
package zutil.network.nio.message;
|
||||||
|
|
||||||
|
import zutil.network.nio.message.type.SystemMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells the destination that the
|
||||||
|
* source is still online
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class KeepAliveMessage extends Message implements SystemMessage{
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
||||||
9
src/zutil/network/nio/message/Message.java
Normal file
9
src/zutil/network/nio/message/Message.java
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
package zutil.network.nio.message;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class Message implements Serializable{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
34
src/zutil/network/nio/message/StringMessage.java
Normal file
34
src/zutil/network/nio/message/StringMessage.java
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
package zutil.network.nio.message;
|
||||||
|
|
||||||
|
import zutil.network.nio.message.type.EchoMessage;
|
||||||
|
import zutil.network.nio.message.type.ResponseRequestMessage;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class StringMessage extends EchoMessage implements ResponseRequestMessage{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private double responseId;
|
||||||
|
|
||||||
|
private String msg;
|
||||||
|
|
||||||
|
public StringMessage(String msg){
|
||||||
|
this.msg = msg;
|
||||||
|
responseId = Math.random();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(){
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setString(String msg){
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString(){
|
||||||
|
return getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getResponseId() {
|
||||||
|
return responseId;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/zutil/network/nio/message/SyncMessage.java
Normal file
13
src/zutil/network/nio/message/SyncMessage.java
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
package zutil.network.nio.message;
|
||||||
|
|
||||||
|
import zutil.network.nio.message.type.SystemMessage;
|
||||||
|
|
||||||
|
public class SyncMessage extends Message implements SystemMessage{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
public static enum MessageType { REQUEST_ID, NEW, REMOVE, SYNC };
|
||||||
|
|
||||||
|
// type of message
|
||||||
|
public MessageType type;
|
||||||
|
// id of the Object
|
||||||
|
public String id;
|
||||||
|
}
|
||||||
34
src/zutil/network/nio/message/type/EchoMessage.java
Normal file
34
src/zutil/network/nio/message/type/EchoMessage.java
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
package zutil.network.nio.message.type;
|
||||||
|
|
||||||
|
import zutil.network.nio.message.Message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reciver will echo out this message to the sender
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
public abstract class EchoMessage extends Message implements SystemMessage{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private boolean echo;
|
||||||
|
|
||||||
|
public EchoMessage(){
|
||||||
|
echo = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns if the message should be echoed
|
||||||
|
* @return If the message should be echoed
|
||||||
|
*/
|
||||||
|
public boolean echo() {
|
||||||
|
return echo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the reciver to disable looping of the message
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void recived() {
|
||||||
|
echo = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package zutil.network.nio.message.type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface means that the sender
|
||||||
|
* wants a reply from the destination
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ResponseRequestMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id of the response to identify the response event
|
||||||
|
* @return Response id
|
||||||
|
*/
|
||||||
|
public double getResponseId();
|
||||||
|
|
||||||
|
}
|
||||||
12
src/zutil/network/nio/message/type/SystemMessage.java
Normal file
12
src/zutil/network/nio/message/type/SystemMessage.java
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
package zutil.network.nio.message.type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message that implements this will be
|
||||||
|
* handeld internaly by the network engine
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface SystemMessage {
|
||||||
|
|
||||||
|
}
|
||||||
12
src/zutil/network/nio/response/PrintRsp.java
Normal file
12
src/zutil/network/nio/response/PrintRsp.java
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
package zutil.network.nio.response;
|
||||||
|
|
||||||
|
import zutil.MultiPrintStream;
|
||||||
|
|
||||||
|
public class PrintRsp extends ResponseEvent{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void responseEvent(Object rsp) {
|
||||||
|
MultiPrintStream.out.println(rsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
43
src/zutil/network/nio/response/ResponseEvent.java
Normal file
43
src/zutil/network/nio/response/ResponseEvent.java
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
package zutil.network.nio.response;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class ResponseEvent {
|
||||||
|
private Object rsp = null;
|
||||||
|
|
||||||
|
public synchronized boolean handleResponse(Object rsp) {
|
||||||
|
this.rsp = rsp;
|
||||||
|
notify();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks the Thread until there is a response
|
||||||
|
*/
|
||||||
|
public synchronized void waitForResponse() {
|
||||||
|
while(!gotResponse()) {
|
||||||
|
try {
|
||||||
|
this.wait();
|
||||||
|
} catch (InterruptedException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
responseEvent(rsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the response
|
||||||
|
*/
|
||||||
|
public void handleResponse(){
|
||||||
|
if(gotResponse()){
|
||||||
|
responseEvent(rsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return If there is an response
|
||||||
|
*/
|
||||||
|
public boolean gotResponse(){
|
||||||
|
return (rsp != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void responseEvent(Object rsp);
|
||||||
|
}
|
||||||
41
src/zutil/network/nio/response/ResponseHandler.java
Normal file
41
src/zutil/network/nio/response/ResponseHandler.java
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
package zutil.network.nio.response;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class ResponseHandler implements Runnable{
|
||||||
|
private List<ResponseEvent> queue = new LinkedList<ResponseEvent>();
|
||||||
|
|
||||||
|
public ResponseHandler(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void addResponseEvent(ResponseEvent re){
|
||||||
|
queue.add(re);
|
||||||
|
notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void removeResponseEvent(ResponseEvent re){
|
||||||
|
queue.remove(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
while(true) {
|
||||||
|
try {
|
||||||
|
this.wait();
|
||||||
|
} catch (InterruptedException e) {}
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void update(){
|
||||||
|
while(!queue.isEmpty()){
|
||||||
|
queue.get(0).handleResponse();
|
||||||
|
if(queue.get(0).gotResponse()){
|
||||||
|
queue.remove(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/zutil/network/nio/server/ChangeRequest.java
Normal file
18
src/zutil/network/nio/server/ChangeRequest.java
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
package zutil.network.nio.server;
|
||||||
|
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
|
||||||
|
public class ChangeRequest {
|
||||||
|
public static final int REGISTER = 1;
|
||||||
|
public static final int CHANGEOPS = 2;
|
||||||
|
|
||||||
|
public SocketChannel socket;
|
||||||
|
public int type;
|
||||||
|
public int ops;
|
||||||
|
|
||||||
|
public ChangeRequest(SocketChannel socket, int type, int ops) {
|
||||||
|
this.socket = socket;
|
||||||
|
this.type = type;
|
||||||
|
this.ops = ops;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/zutil/network/nio/server/ClientData.java
Normal file
29
src/zutil/network/nio/server/ClientData.java
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
package zutil.network.nio.server;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
|
||||||
|
public class ClientData {
|
||||||
|
private SocketChannel socketChannel;
|
||||||
|
private long lastMessageReceived;
|
||||||
|
|
||||||
|
public ClientData(SocketChannel socketChannel){
|
||||||
|
this.socketChannel = socketChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketChannel getSocketChannel(){
|
||||||
|
return socketChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InetSocketAddress getAddress(){
|
||||||
|
return (InetSocketAddress) socketChannel.socket().getRemoteSocketAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastMessageReceived(long time){
|
||||||
|
lastMessageReceived = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLastMessageReceived(){
|
||||||
|
return lastMessageReceived;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/zutil/network/nio/service/ChatListener.java
Normal file
10
src/zutil/network/nio/service/ChatListener.java
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
package zutil.network.nio.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tis is a listener class for new chat messages
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ChatListener {
|
||||||
|
public void messageAction(String msg, String room);
|
||||||
|
}
|
||||||
121
src/zutil/network/nio/service/ChatService.java
Normal file
121
src/zutil/network/nio/service/ChatService.java
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
package zutil.network.nio.service;
|
||||||
|
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import zutil.MultiPrintStream;
|
||||||
|
import zutil.network.nio.NioNetwork;
|
||||||
|
import zutil.network.nio.message.ChatMessage;
|
||||||
|
import zutil.network.nio.message.Message;
|
||||||
|
|
||||||
|
public class ChatService extends NetworkService{
|
||||||
|
private HashMap<String,LinkedList<SocketChannel>> rooms;
|
||||||
|
private ChatListener listener;
|
||||||
|
|
||||||
|
public ChatService(NioNetwork nio){
|
||||||
|
super(nio);
|
||||||
|
rooms = new HashMap<String,LinkedList<SocketChannel>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message message, SocketChannel socket) {
|
||||||
|
// New message
|
||||||
|
if(message instanceof ChatMessage){
|
||||||
|
ChatMessage chatmessage = (ChatMessage)message;
|
||||||
|
//is this a new message
|
||||||
|
if(chatmessage.type == ChatMessage.ChatMessageType.MESSAGE){
|
||||||
|
// Is this the server
|
||||||
|
if(nio.getType() == NioNetwork.NetworkType.SERVER){
|
||||||
|
if(rooms.containsKey(chatmessage.room)){
|
||||||
|
LinkedList<SocketChannel> tmpList = rooms.get(chatmessage.room);
|
||||||
|
|
||||||
|
// Broadcast the message
|
||||||
|
for(SocketChannel s : tmpList){
|
||||||
|
if(s.isConnected()){
|
||||||
|
nio.send(s, chatmessage);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
unRegisterUser(chatmessage.room, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(NioNetwork.DEBUG>=2)MultiPrintStream.out.println("New Chat Message: "+chatmessage.msg);
|
||||||
|
listener.messageAction(chatmessage.msg, chatmessage.room);
|
||||||
|
}
|
||||||
|
// register to a room
|
||||||
|
else if(chatmessage.type == ChatMessage.ChatMessageType.REGISTER){
|
||||||
|
registerUser(chatmessage.room, socket);
|
||||||
|
}
|
||||||
|
// unregister to a room
|
||||||
|
else if(chatmessage.type == ChatMessage.ChatMessageType.UNREGISTER){
|
||||||
|
unRegisterUser(chatmessage.room, socket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a user to the main room
|
||||||
|
*
|
||||||
|
* @param socket The socket to the user
|
||||||
|
*/
|
||||||
|
public void registerUser(SocketChannel socket){
|
||||||
|
registerUser("", socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the given user to a specific room
|
||||||
|
*
|
||||||
|
* @param room The room
|
||||||
|
* @param socket The socket to the user
|
||||||
|
*/
|
||||||
|
public void registerUser(String room, SocketChannel socket){
|
||||||
|
addRoom(room);
|
||||||
|
if(NioNetwork.DEBUG>=1)MultiPrintStream.out.println("New Chat User: "+socket);
|
||||||
|
rooms.get(room).add(socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters a user from a room and removes the room if its empty
|
||||||
|
*
|
||||||
|
* @param room The room
|
||||||
|
* @param socket The socket to the user
|
||||||
|
*/
|
||||||
|
public void unRegisterUser(String room, SocketChannel socket){
|
||||||
|
if(rooms.containsKey(room)){
|
||||||
|
if(NioNetwork.DEBUG>=1)MultiPrintStream.out.println("Remove Chat User: "+socket);
|
||||||
|
rooms.get(room).remove(socket);
|
||||||
|
removeRoom(room);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a room into the list
|
||||||
|
*
|
||||||
|
* @param room The name of the room
|
||||||
|
*/
|
||||||
|
public void addRoom(String room){
|
||||||
|
if(!rooms.containsKey(room)){
|
||||||
|
if(NioNetwork.DEBUG>=1)MultiPrintStream.out.println("New Chat Room: "+room);
|
||||||
|
rooms.put(room, new LinkedList<SocketChannel>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the given room if its empty
|
||||||
|
*
|
||||||
|
* @param room The room
|
||||||
|
*/
|
||||||
|
public void removeRoom(String room){
|
||||||
|
if(rooms.get(room).isEmpty()){
|
||||||
|
if(NioNetwork.DEBUG>=1)MultiPrintStream.out.println("Remove Chat Room: "+room);
|
||||||
|
rooms.remove(room);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChatService getInstance(){
|
||||||
|
return (ChatService)instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/zutil/network/nio/service/NetworkService.java
Normal file
25
src/zutil/network/nio/service/NetworkService.java
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package zutil.network.nio.service;
|
||||||
|
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
|
||||||
|
import zutil.network.nio.NioNetwork;
|
||||||
|
import zutil.network.nio.message.Message;
|
||||||
|
|
||||||
|
public abstract class NetworkService {
|
||||||
|
protected static NetworkService instance;
|
||||||
|
protected NioNetwork nio;
|
||||||
|
|
||||||
|
public NetworkService(NioNetwork nio){
|
||||||
|
instance = this;
|
||||||
|
this.nio = nio;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void handleMessage(Message message, SocketChannel socket);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A instance of this class
|
||||||
|
*/
|
||||||
|
public static NetworkService getInstance(){
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/zutil/network/nio/service/sync/ObjectSync.java
Normal file
28
src/zutil/network/nio/service/sync/ObjectSync.java
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package zutil.network.nio.service.sync;
|
||||||
|
|
||||||
|
import zutil.network.nio.message.SyncMessage;
|
||||||
|
|
||||||
|
public abstract class ObjectSync {
|
||||||
|
public String id;
|
||||||
|
|
||||||
|
public ObjectSync(String id){
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends sync message if the object has bean changed
|
||||||
|
*/
|
||||||
|
public abstract void sendSync();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the SyncMessage to the object
|
||||||
|
* @param message
|
||||||
|
* @param object
|
||||||
|
*/
|
||||||
|
public abstract void syncObject(SyncMessage message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the object is removed from the sync list
|
||||||
|
*/
|
||||||
|
public abstract void remove();
|
||||||
|
}
|
||||||
58
src/zutil/network/nio/service/sync/SyncService.java
Normal file
58
src/zutil/network/nio/service/sync/SyncService.java
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
package zutil.network.nio.service.sync;
|
||||||
|
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import zutil.MultiPrintStream;
|
||||||
|
import zutil.network.nio.NioNetwork;
|
||||||
|
import zutil.network.nio.message.Message;
|
||||||
|
import zutil.network.nio.message.SyncMessage;
|
||||||
|
import zutil.network.nio.service.NetworkService;
|
||||||
|
|
||||||
|
public class SyncService extends NetworkService{
|
||||||
|
// list of objects to sync
|
||||||
|
private HashMap<String, ObjectSync> sync;
|
||||||
|
|
||||||
|
public SyncService(NioNetwork nio){
|
||||||
|
super(nio);
|
||||||
|
sync = new HashMap<String, ObjectSync>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a SyncObject to the sync list
|
||||||
|
* @param os The object to sync
|
||||||
|
*/
|
||||||
|
public void addSyncObject(ObjectSync os){
|
||||||
|
sync.put(os.id, os);
|
||||||
|
if(NioNetwork.DEBUG>=1)MultiPrintStream.out.println("New Sync object: "+os);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleMessage(Message message, SocketChannel socket){
|
||||||
|
if(message instanceof SyncMessage){
|
||||||
|
SyncMessage syncMessage = (SyncMessage)message;
|
||||||
|
if(syncMessage.type == SyncMessage.MessageType.SYNC){
|
||||||
|
ObjectSync obj = sync.get(syncMessage.id);
|
||||||
|
if(obj != null){
|
||||||
|
if(NioNetwork.DEBUG>=2)MultiPrintStream.out.println("Syncing Message...");
|
||||||
|
obj.syncObject(syncMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(syncMessage.type == SyncMessage.MessageType.REMOVE){
|
||||||
|
sync.remove(syncMessage.id).remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs all the objects whit the server
|
||||||
|
*/
|
||||||
|
public void sync(){
|
||||||
|
for(String id : sync.keySet()){
|
||||||
|
sync.get(id).sendSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SyncService getInstance(){
|
||||||
|
return (SyncService)instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/zutil/network/nio/worker/EchoWorker.java
Normal file
16
src/zutil/network/nio/worker/EchoWorker.java
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
package zutil.network.nio.worker;
|
||||||
|
|
||||||
|
import zutil.MultiPrintStream;
|
||||||
|
|
||||||
|
public class EchoWorker extends ThreadedEventWorker {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageEvent(WorkerDataEvent dataEvent) {
|
||||||
|
// Return to sender
|
||||||
|
MultiPrintStream.out.println("Recived Msg: "+dataEvent.data);
|
||||||
|
dataEvent.network.send(dataEvent.socket, dataEvent.data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
126
src/zutil/network/nio/worker/SystemWorker.java
Normal file
126
src/zutil/network/nio/worker/SystemWorker.java
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
package zutil.network.nio.worker;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import zutil.MultiPrintStream;
|
||||||
|
import zutil.network.nio.NioNetwork;
|
||||||
|
import zutil.network.nio.message.ChatMessage;
|
||||||
|
import zutil.network.nio.message.Message;
|
||||||
|
import zutil.network.nio.message.SyncMessage;
|
||||||
|
import zutil.network.nio.message.type.EchoMessage;
|
||||||
|
import zutil.network.nio.message.type.ResponseRequestMessage;
|
||||||
|
import zutil.network.nio.response.ResponseEvent;
|
||||||
|
import zutil.network.nio.service.ChatService;
|
||||||
|
import zutil.network.nio.service.NetworkService;
|
||||||
|
import zutil.network.nio.service.sync.SyncService;
|
||||||
|
|
||||||
|
|
||||||
|
public class SystemWorker extends ThreadedEventWorker {
|
||||||
|
private NioNetwork nio;
|
||||||
|
// Maps a SocketChannel to a RspHandler
|
||||||
|
private Map<Double, ResponseEvent> rspEvents = new HashMap<Double, ResponseEvent>();
|
||||||
|
// Difren services listening on specific messages
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private Map<Class, NetworkService> services = new HashMap<Class, NetworkService>();
|
||||||
|
/**
|
||||||
|
* Creates a new SystemWorker
|
||||||
|
* @param nio The Network
|
||||||
|
*/
|
||||||
|
public SystemWorker(NioNetwork nio){
|
||||||
|
this.nio = nio;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageEvent(WorkerDataEvent event) {
|
||||||
|
if(NioNetwork.DEBUG>=2)MultiPrintStream.out.println("System Message: "+event.data.getClass().getName());
|
||||||
|
if(event.data instanceof Message){
|
||||||
|
if(event.data instanceof EchoMessage && ((EchoMessage)event.data).echo()){
|
||||||
|
// Echos back the recived message
|
||||||
|
((EchoMessage)event.data).recived();
|
||||||
|
if(NioNetwork.DEBUG>=3)MultiPrintStream.out.println("Echoing Message: "+event.data);
|
||||||
|
nio.send(event.socket, event.data);
|
||||||
|
}
|
||||||
|
else if(event.data instanceof ResponseRequestMessage &&
|
||||||
|
rspEvents.get(((ResponseRequestMessage)event.data).getResponseId()) != null){
|
||||||
|
// Handle the response
|
||||||
|
handleResponse(((ResponseRequestMessage)event.data).getResponseId(), event.data);
|
||||||
|
if(NioNetwork.DEBUG>=3)MultiPrintStream.out.println("Response Request Message: "+event.data);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//Services
|
||||||
|
if(services.containsKey(event.data.getClass()) ||
|
||||||
|
!services.containsKey(event.data.getClass()) && defaultServices(event.data)){
|
||||||
|
services.get(event.data.getClass()).handleMessage((Message)event.data, event.socket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a Service to a specific message
|
||||||
|
*
|
||||||
|
* @param c The Message class
|
||||||
|
* @param ns The service
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void registerService(Class c, NetworkService ns){
|
||||||
|
services.put(c, ns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters a service
|
||||||
|
*
|
||||||
|
* @param c The class
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void unregisterService(Class c){
|
||||||
|
services.remove(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects a ResponseHandler to a specific message
|
||||||
|
* @param handler The Handler
|
||||||
|
* @param data The Message
|
||||||
|
*/
|
||||||
|
public void addResponseHandler(ResponseEvent handler, ResponseRequestMessage data){
|
||||||
|
rspEvents.put(data.getResponseId(), handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client And Server ResponseEvent
|
||||||
|
*/
|
||||||
|
private void handleResponse(double responseId, Object rspData){
|
||||||
|
// Look up the handler for this channel
|
||||||
|
ResponseEvent handler = rspEvents.get(responseId);
|
||||||
|
// And pass the response to it
|
||||||
|
handler.handleResponse(rspData);
|
||||||
|
|
||||||
|
rspEvents.remove(responseId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the default services in the engin e
|
||||||
|
* if the message needs one of them
|
||||||
|
*
|
||||||
|
* @param o The message
|
||||||
|
*/
|
||||||
|
private boolean defaultServices(Object o){
|
||||||
|
if(o instanceof SyncMessage){
|
||||||
|
if(SyncService.getInstance() == null)
|
||||||
|
registerService(o.getClass(), new SyncService(nio));
|
||||||
|
else
|
||||||
|
registerService(o.getClass(), SyncService.getInstance());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(o instanceof ChatMessage){
|
||||||
|
if(ChatService.getInstance() == null)
|
||||||
|
registerService(o.getClass(), new ChatService(nio));
|
||||||
|
else
|
||||||
|
registerService(o.getClass(), ChatService.getInstance());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
34
src/zutil/network/nio/worker/ThreadedEventWorker.java
Normal file
34
src/zutil/network/nio/worker/ThreadedEventWorker.java
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
package zutil.network.nio.worker;
|
||||||
|
|
||||||
|
public abstract class ThreadedEventWorker extends Worker{
|
||||||
|
private Thread thread;
|
||||||
|
|
||||||
|
public ThreadedEventWorker(){
|
||||||
|
thread = new Thread(this);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
WorkerDataEvent dataEvent;
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
try{
|
||||||
|
// Wait for data to become available
|
||||||
|
synchronized(getEventQueue()) {
|
||||||
|
while(getEventQueue().isEmpty()) {
|
||||||
|
try {
|
||||||
|
getEventQueue().wait();
|
||||||
|
} catch (InterruptedException e) {}
|
||||||
|
}
|
||||||
|
dataEvent = (WorkerDataEvent) getEventQueue().remove(0);
|
||||||
|
}
|
||||||
|
messageEvent(dataEvent);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void messageEvent(WorkerDataEvent e);
|
||||||
|
|
||||||
|
}
|
||||||
52
src/zutil/network/nio/worker/Worker.java
Normal file
52
src/zutil/network/nio/worker/Worker.java
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
package zutil.network.nio.worker;
|
||||||
|
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import zutil.network.nio.NioNetwork;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class Worker implements Runnable {
|
||||||
|
private LinkedList<WorkerDataEvent> queue = new LinkedList<WorkerDataEvent>();
|
||||||
|
|
||||||
|
public void processData(NioNetwork server, SocketChannel socket, Object data) {
|
||||||
|
synchronized(queue) {
|
||||||
|
queue.add(new WorkerDataEvent(server, socket, data));
|
||||||
|
queue.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The event queue
|
||||||
|
*/
|
||||||
|
protected List<WorkerDataEvent> getEventQueue(){
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return If there is a event in the queue
|
||||||
|
*/
|
||||||
|
protected boolean hasEvent(){
|
||||||
|
return !queue.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Polls a event from the list or waits until there is a event
|
||||||
|
* @return The next event
|
||||||
|
*/
|
||||||
|
protected WorkerDataEvent pollEvent(){
|
||||||
|
while(queue.isEmpty()) {
|
||||||
|
try {
|
||||||
|
this.wait();
|
||||||
|
} catch (InterruptedException e) {}
|
||||||
|
}
|
||||||
|
return queue.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run(){
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void update();
|
||||||
|
}
|
||||||
18
src/zutil/network/nio/worker/WorkerDataEvent.java
Normal file
18
src/zutil/network/nio/worker/WorkerDataEvent.java
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
package zutil.network.nio.worker;
|
||||||
|
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
|
||||||
|
import zutil.network.nio.NioNetwork;
|
||||||
|
|
||||||
|
|
||||||
|
public class WorkerDataEvent {
|
||||||
|
public NioNetwork network;
|
||||||
|
public SocketChannel socket;
|
||||||
|
public Object data;
|
||||||
|
|
||||||
|
public WorkerDataEvent(NioNetwork server, SocketChannel socket, Object data) {
|
||||||
|
this.network = server;
|
||||||
|
this.socket = socket;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/zutil/test/ConsoleTest.java
Normal file
25
src/zutil/test/ConsoleTest.java
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package zutil.test;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
import zutil.ui.Console;
|
||||||
|
|
||||||
|
public class ConsoleTest {
|
||||||
|
public static void main(String[] args) throws IOException{
|
||||||
|
new Console("Console Test", true);
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
|
||||||
|
|
||||||
|
while(true){
|
||||||
|
System.out.println("hello= "+in.readLine());
|
||||||
|
for(int i=0; i<20 ;i++){
|
||||||
|
System.out.println(i+"Hello World!!!sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss");
|
||||||
|
System.err.println(i+"Hello World!!!sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss");
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/zutil/test/EncryptionTest.java
Normal file
38
src/zutil/test/EncryptionTest.java
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
package zutil.test;
|
||||||
|
|
||||||
|
import zutil.Encrypter;
|
||||||
|
|
||||||
|
public class EncryptionTest {
|
||||||
|
public static String data = "Hello there wats yor name my is a secret 123456789";
|
||||||
|
public static Encrypter enc;
|
||||||
|
public static Encrypter enc2;
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
System.out.println("input text : " + data);
|
||||||
|
|
||||||
|
//****************************************************************************************
|
||||||
|
System.out.println("Test1 passphrase");
|
||||||
|
Encrypter.randomizeSalt();
|
||||||
|
enc = new Encrypter("Hello World!!", Encrypter.PASSPHRASE_DES_ALGO);
|
||||||
|
enc2 = new Encrypter("Hello World!!", Encrypter.PASSPHRASE_DES_ALGO);
|
||||||
|
|
||||||
|
byte[] encrypted = enc.encrypt(data.getBytes());
|
||||||
|
System.out.println("cipher text: " + new String(encrypted) + " bytes: " + encrypted.length);
|
||||||
|
|
||||||
|
byte[] decrypted = enc2.decrypt(encrypted);
|
||||||
|
System.out.println("plain text : " + new String(decrypted) + " bytes: " + decrypted.length);
|
||||||
|
|
||||||
|
//****************************************************************************************
|
||||||
|
System.out.println("Test2 randome");
|
||||||
|
Encrypter.randomizeSalt();
|
||||||
|
enc = new Encrypter(Encrypter.BLOWFISH_ALGO);
|
||||||
|
Encrypter.randomizeSalt();
|
||||||
|
enc2 = new Encrypter(enc.getKey());
|
||||||
|
|
||||||
|
encrypted = enc.encrypt(data.getBytes());
|
||||||
|
System.out.println("cipher text: " + new String(encrypted) + " bytes: " + encrypted.length);
|
||||||
|
|
||||||
|
decrypted = enc2.decrypt(encrypted);
|
||||||
|
System.out.println("plain text : " + new String(decrypted) + " bytes: " + decrypted.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/zutil/test/ExternalSortTest.java
Normal file
20
src/zutil/test/ExternalSortTest.java
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
package zutil.test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import zutil.algo.sort.ExternalSort;
|
||||||
|
|
||||||
|
|
||||||
|
public class ExternalSortTest {
|
||||||
|
public static void main(String[] args){
|
||||||
|
try {
|
||||||
|
File file = new File("C:\\Users\\Ziver\\Desktop\\IndexFile.txt");
|
||||||
|
File sortedFile = new File("C:\\Users\\Ziver\\Desktop\\SortedIndexFile.txt");
|
||||||
|
|
||||||
|
ExternalSort sort = new ExternalSort(file, sortedFile);
|
||||||
|
sort.sort();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/zutil/test/FileChangedTest.java
Normal file
29
src/zutil/test/FileChangedTest.java
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
package zutil.test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
|
import zutil.FileChangeListener;
|
||||||
|
import zutil.FileFinder;
|
||||||
|
import zutil.FileWatcher;
|
||||||
|
|
||||||
|
public class FileChangedTest implements FileChangeListener{
|
||||||
|
public static void main(String[] args) throws URISyntaxException, FileNotFoundException{
|
||||||
|
FileWatcher watcher = new FileWatcher(FileFinder.find("test.txt"));
|
||||||
|
watcher.setListener(new FileChangedTest());
|
||||||
|
|
||||||
|
while(true){
|
||||||
|
try {
|
||||||
|
Thread.sleep(10);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fileChangedEvent(File file) {
|
||||||
|
System.out.println(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/zutil/test/FileFinderHasherTest.java
Normal file
26
src/zutil/test/FileFinderHasherTest.java
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
package zutil.test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import zutil.FileFinder;
|
||||||
|
import zutil.Hasher;
|
||||||
|
|
||||||
|
public class FileFinderHasherTest {
|
||||||
|
public static void main(String[] args) throws URISyntaxException{
|
||||||
|
String relativePath = "zutil/test";
|
||||||
|
|
||||||
|
File path = FileFinder.find(relativePath);
|
||||||
|
ArrayList<File> files = FileFinder.search(path);
|
||||||
|
for(int i=0; i<files.size(); i++){
|
||||||
|
try {
|
||||||
|
System.out.println(
|
||||||
|
FileFinder.relativePath(files.get(i), relativePath)+
|
||||||
|
": "+Hasher.hash(files.get(i),"MD5"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
79
src/zutil/test/HTTPGuessTheNumber.java
Normal file
79
src/zutil/test/HTTPGuessTheNumber.java
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
package zutil.test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import zutil.network.http.HttpPage;
|
||||||
|
import zutil.network.http.HttpPrintStream;
|
||||||
|
import zutil.network.http.HttpServer;
|
||||||
|
|
||||||
|
public class HTTPGuessTheNumber implements HttpPage{
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException{
|
||||||
|
HttpServer server = new HttpServer("localhost", 80);
|
||||||
|
server.setDefaultPage(new HTTPGuessTheNumber());
|
||||||
|
server.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void respond(HttpPrintStream out,
|
||||||
|
HashMap<String, String> client_info,
|
||||||
|
HashMap<String, String> session, HashMap<String, String> cookie,
|
||||||
|
HashMap<String, String> request) {
|
||||||
|
|
||||||
|
out.enableBuffering(true);
|
||||||
|
out.println("<html>");
|
||||||
|
out.println("<H2>Welcome To The Number Guess Game!</H2>");
|
||||||
|
|
||||||
|
if(session.containsKey("random_nummber") && request.containsKey("guess")){
|
||||||
|
int guess = Integer.parseInt(request.get("guess"));
|
||||||
|
int nummber = Integer.parseInt(session.get("random_nummber"));
|
||||||
|
try {
|
||||||
|
if(guess == nummber){
|
||||||
|
session.remove("random_nummber");
|
||||||
|
out.println("You Guessed Right! Congrats!");
|
||||||
|
out.println("</html>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(guess > nummber){
|
||||||
|
out.println("<b>To High</b><br>");
|
||||||
|
if(Integer.parseInt(cookie.get("high")) > guess){
|
||||||
|
out.setCookie("high", ""+guess);
|
||||||
|
cookie.put("high", ""+guess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
out.println("<b>To Low</b><br>");
|
||||||
|
if(Integer.parseInt(cookie.get("low")) < guess){
|
||||||
|
out.setCookie("low", ""+guess);
|
||||||
|
cookie.put("low", ""+guess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
session.put("random_nummber", ""+(int)(Math.random()*99+1));
|
||||||
|
try {
|
||||||
|
out.setCookie("low", "0");
|
||||||
|
out.setCookie("high", "100");
|
||||||
|
cookie.put("low", "0");
|
||||||
|
cookie.put("high", "100");
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.println("<form method='post'>");
|
||||||
|
out.println(cookie.get("low")+" < X < "+cookie.get("high")+"<br>");
|
||||||
|
out.println("Guess a number between 0 and 100:<br>");
|
||||||
|
out.println("<input type='text' name='guess'>");
|
||||||
|
out.println("<input type='hidden' name='test' value='test'>");
|
||||||
|
out.println("<input type='submit' value='Guess'>");
|
||||||
|
out.println("</form>");
|
||||||
|
out.println("<script>document.all.guess.focus();</script>");
|
||||||
|
//out.println("<b>DEBUG: nummber="+session.get("random_nummber")+"</b><br>");
|
||||||
|
out.println("</html>");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
116
src/zutil/test/ImageProcessorTest.java
Normal file
116
src/zutil/test/ImageProcessorTest.java
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
package zutil.test;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.swing.ImageIcon;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JProgressBar;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
|
||||||
|
import zutil.ProgressListener;
|
||||||
|
import zutil.image.ImageFilterProcessor;
|
||||||
|
import zutil.image.filters.BlurFilter;
|
||||||
|
import zutil.image.filters.ColorIntensityFilter;
|
||||||
|
import zutil.image.filters.ContrastBrightnessFilter;
|
||||||
|
import zutil.image.filters.DitheringFilter;
|
||||||
|
import zutil.image.filters.FaceDetectionFilter;
|
||||||
|
import zutil.image.filters.MedianFilter;
|
||||||
|
import zutil.image.filters.ResizeImage;
|
||||||
|
import zutil.image.filters.SpotLightFilter;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class ImageProcessorTest implements ProgressListener{
|
||||||
|
private static String imgPath = "Image6.gif";
|
||||||
|
|
||||||
|
private JLabel processedLabel;
|
||||||
|
private JLabel orginalLabel;
|
||||||
|
private JProgressBar progress;
|
||||||
|
|
||||||
|
public static void main(String[] args){
|
||||||
|
new ImageProcessorTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageProcessorTest(){
|
||||||
|
JFrame frame = getJFrame();
|
||||||
|
BufferedImage img = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Read from an input stream
|
||||||
|
InputStream is = new BufferedInputStream(new FileInputStream(imgPath));
|
||||||
|
img = ImageIO.read(is);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageIcon orginalIcon = new ImageIcon(img);
|
||||||
|
orginalLabel.setIcon(orginalIcon);
|
||||||
|
frame.setVisible(true);
|
||||||
|
frame.pack();
|
||||||
|
|
||||||
|
BufferedImage procImg = null;
|
||||||
|
try {
|
||||||
|
//ImageFilterProcessor processor = new SpotLightFilter(img,100,100,100);
|
||||||
|
//ImageFilterProcessor processor = new ContrastBrightnessFilter(img);
|
||||||
|
//ImageFilterProcessor processor = new ColorIntensityFilter(img, true);
|
||||||
|
//ImageFilterProcessor processor = new BlurFilter(img);
|
||||||
|
//ImageFilterProcessor processor = new DitheringFilter(img);
|
||||||
|
//ImageFilterProcessor processor = new ResizeImage(img,100,100);
|
||||||
|
//ImageFilterProcessor processor = new MedianFilter(img);
|
||||||
|
ImageFilterProcessor processor = new FaceDetectionFilter(img);
|
||||||
|
|
||||||
|
processor.setProgressListener(this);
|
||||||
|
procImg = processor.process();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
ImageIcon processedIcon = new ImageIcon(procImg);
|
||||||
|
processedLabel.setIcon(processedIcon);
|
||||||
|
|
||||||
|
|
||||||
|
frame.pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
private JFrame getJFrame() {
|
||||||
|
processedLabel = new JLabel("Processed");
|
||||||
|
orginalLabel = new JLabel("Orginal");
|
||||||
|
|
||||||
|
progress = new JProgressBar();
|
||||||
|
progress.setMaximum(100);
|
||||||
|
progress.setValue(0);
|
||||||
|
progress.setIndeterminate(false);
|
||||||
|
progress.setStringPainted(true);
|
||||||
|
|
||||||
|
JPanel jPanel = new JPanel();
|
||||||
|
jPanel.setLayout(new BorderLayout());
|
||||||
|
jPanel.add(orginalLabel, BorderLayout.NORTH);
|
||||||
|
jPanel.add(processedLabel, BorderLayout.CENTER);
|
||||||
|
jPanel.add(progress, BorderLayout.SOUTH);
|
||||||
|
|
||||||
|
JFrame jFrame = new JFrame("ImageProcessorTest");
|
||||||
|
jFrame.setSize(new Dimension(715, 361));
|
||||||
|
jFrame.setContentPane(jPanel);
|
||||||
|
jFrame.addWindowListener(new WindowAdapter() {
|
||||||
|
public void windowClosing(WindowEvent e) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return jFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void progressUpdate(Object source, Object info, double percent) {
|
||||||
|
progress.setValue((int)percent);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/zutil/test/NetworkClientTest.java
Normal file
37
src/zutil/test/NetworkClientTest.java
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
package zutil.test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import zutil.Encrypter;
|
||||||
|
import zutil.network.nio.NioClient;
|
||||||
|
import zutil.network.nio.message.StringMessage;
|
||||||
|
import zutil.network.nio.response.PrintRsp;
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class NetworkClientTest {
|
||||||
|
public static void main(String[] args) throws NoSuchAlgorithmException {
|
||||||
|
try {
|
||||||
|
int count = 0;
|
||||||
|
long time = System.currentTimeMillis()+1000*60;
|
||||||
|
NioClient client = new NioClient(InetAddress.getByName("localhost"), 6056);
|
||||||
|
//client.setEncrypter(new Encrypter("lol", Encrypter.PASSPHRASE_DES_ALGO));
|
||||||
|
while(time > System.currentTimeMillis()){
|
||||||
|
PrintRsp handler = new PrintRsp();
|
||||||
|
client.send(handler, new StringMessage("StringMessage: "+count));
|
||||||
|
handler.waitForResponse();
|
||||||
|
//try {Thread.sleep(100);} catch (InterruptedException e) {}
|
||||||
|
//System.out.println("sending..");
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Message Count 1m: "+count);
|
||||||
|
System.out.println("Message Count 1s: "+count/60);
|
||||||
|
System.exit(0);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/zutil/test/NetworkServerTest.java
Normal file
20
src/zutil/test/NetworkServerTest.java
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
package zutil.test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import zutil.Encrypter;
|
||||||
|
import zutil.network.nio.NioServer;
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class NetworkServerTest {
|
||||||
|
public static void main(String[] args) throws NoSuchAlgorithmException {
|
||||||
|
try {
|
||||||
|
NioServer server = new NioServer(6056);
|
||||||
|
//server.setEncrypter(new Encrypter("lol", Encrypter.PASSPHRASE_DES_ALGO));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/zutil/test/QuickSelectTest.java
Normal file
26
src/zutil/test/QuickSelectTest.java
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
package zutil.test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import zutil.algo.QuickSelect;
|
||||||
|
import zutil.algo.sort.sortable.SortableIntArray;
|
||||||
|
|
||||||
|
public class QuickSelectTest {
|
||||||
|
public static void main(String[] args){
|
||||||
|
int[] array = {1,3,4,6,3,2,98,5,7,8,543,2,4,5,8,9,5,2,3,5,7,5,3,2,6,8,5,324,8,6};
|
||||||
|
//int[] array = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,18,19,20};
|
||||||
|
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
int median = (Integer)QuickSelect.find(new SortableIntArray(array), array.length/2);
|
||||||
|
System.out.println("QuickSelection("+(System.currentTimeMillis()-time)+"ms): "+median);
|
||||||
|
|
||||||
|
time = System.currentTimeMillis();
|
||||||
|
Arrays.sort(array);
|
||||||
|
System.out.println("RightAnswer("+(System.currentTimeMillis()-time)+"ms): "+array[array.length/2]);
|
||||||
|
|
||||||
|
System.out.println("Sorted Array("+array.length+"): ");
|
||||||
|
for(int i=0; i<array.length ;i++){
|
||||||
|
System.out.println(array[i] +",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
137
src/zutil/test/QuickSortTest.java
Normal file
137
src/zutil/test/QuickSortTest.java
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
package zutil.test;
|
||||||
|
import zutil.algo.sort.QuickSort;
|
||||||
|
import zutil.algo.sort.sortable.SortableIntArray;
|
||||||
|
import junit.framework.*;
|
||||||
|
|
||||||
|
public class QuickSortTest extends TestCase {
|
||||||
|
public static boolean debug = false;
|
||||||
|
//the size of the arrays to be tested
|
||||||
|
private static final int[] cases = new int[]{10000,100000,1000000,10000000};
|
||||||
|
//the type of array to be tested
|
||||||
|
// 0 = random
|
||||||
|
// 1 = mirror
|
||||||
|
// 2 = sorted
|
||||||
|
private static final int[] types = new int[]{0,1,2};
|
||||||
|
//the strings for the diffrent arrays
|
||||||
|
private static final String[] typesS = new String[]{"Random array","Mirrored array","Sorted array"};
|
||||||
|
//the pivots that will be tested
|
||||||
|
// 0 = random
|
||||||
|
// 1 = median
|
||||||
|
// 2 = middle
|
||||||
|
private static final int[] pivots = new int[]{0,1,2};
|
||||||
|
//the strings for the pivots
|
||||||
|
private static final String[] pivotsS = new String[]{"Random pivot","Median pivot","Half pivot"};
|
||||||
|
//the current array size index of cases
|
||||||
|
private static int currentCase = 0;
|
||||||
|
//the current type of arrays
|
||||||
|
private static int typeCase = 0;
|
||||||
|
//the current pivot to use
|
||||||
|
private static int pivotCase = 0;
|
||||||
|
//the current state of using insertionsort in quicksort
|
||||||
|
private static boolean insertSort;
|
||||||
|
//the temp array that will be sorted
|
||||||
|
private int[] array;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*The main method to run the test. was going to use junit but did
|
||||||
|
*no find a way to loop the test like in this method.
|
||||||
|
*/
|
||||||
|
public static void main(String[] args){
|
||||||
|
QuickSortTest test = new QuickSortTest("Test");
|
||||||
|
insertSort = true;
|
||||||
|
//the insertion sort tests loop
|
||||||
|
for(int z=0; z<2 ; insertSort=false,z++){
|
||||||
|
System.out.println("**************** Whit insertionSort: "+insertSort+" *****************");
|
||||||
|
// the pivots tests loop
|
||||||
|
for(pivotCase=0; pivotCase<pivots.length ;pivotCase++){
|
||||||
|
System.out.println("********** "+pivotsS[pivots[pivotCase]]+" ***********");
|
||||||
|
//the array size tests loop
|
||||||
|
for(typeCase=0; typeCase<types.length ;typeCase++){
|
||||||
|
currentCase = 0;
|
||||||
|
System.out.println("**** "+typesS[types[typeCase]]+" ****");
|
||||||
|
//the array size loop
|
||||||
|
for(currentCase=0; currentCase<cases.length ;currentCase++){
|
||||||
|
try{
|
||||||
|
test.setUp();
|
||||||
|
test.TestSort();
|
||||||
|
test.tearDown();
|
||||||
|
}catch(Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public QuickSortTest(String name){
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setUp() method that initializes common objects
|
||||||
|
*/
|
||||||
|
public void setUp() throws Exception{
|
||||||
|
super.setUp();
|
||||||
|
array = new int[cases[currentCase]];
|
||||||
|
|
||||||
|
switch(types[typeCase]){
|
||||||
|
//Randome Array test
|
||||||
|
case 0:
|
||||||
|
for(int i=0; i<array.length ;i++){
|
||||||
|
array[i] = (int)(Math.random()*array.length*10);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
//Mirrored Array test
|
||||||
|
case 1:
|
||||||
|
for(int i=0; i<array.length ;i++){
|
||||||
|
array[i] = array.length-i;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
//Sorted Array test
|
||||||
|
case 2:
|
||||||
|
for(int i=0; i<array.length ;i++){
|
||||||
|
array[i] = i;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tearDown() method that cleanup the common objects
|
||||||
|
*/
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
super.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*Tests if the array is sorted
|
||||||
|
*/
|
||||||
|
public void TestSort() {
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
if(debug){
|
||||||
|
for(int i=0; i<array.length ;i++)
|
||||||
|
System.out.print(array[i]+", ");
|
||||||
|
System.out.println("");
|
||||||
|
}
|
||||||
|
QuickSort.sort(new SortableIntArray(array),pivotCase,insertSort);
|
||||||
|
//Sort.insertionSort(array);
|
||||||
|
System.out.print("*");
|
||||||
|
//the time to sort
|
||||||
|
System.out.println(array.length+" elements: "+
|
||||||
|
((double)(System.currentTimeMillis()-time)/1000)+" sec("+
|
||||||
|
(System.currentTimeMillis()-time)+" ms)");
|
||||||
|
if(debug){
|
||||||
|
for(int i=0; i<array.length ;i++)
|
||||||
|
System.out.print(array[i]+", ");
|
||||||
|
System.out.println("");
|
||||||
|
}
|
||||||
|
//checking if sorted correct
|
||||||
|
for(int i=1; i<array.length ; i++){
|
||||||
|
if(array[i-1] > array[i]){
|
||||||
|
fail("Array not sorted!! ("+array[i-1]+" > "+array[i]+")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue