RESOLVED - # 99: Change StringBuffer deleteCharAt() to integer
http://bugs.koc.se/view.php?id=99 Added Base64 decoder
This commit is contained in:
parent
e46ecc1dca
commit
6e890b81e1
8 changed files with 292 additions and 16 deletions
|
|
@ -488,6 +488,13 @@ public abstract class DBBean {
|
|||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function cancels the internal cache garbage collector in DBBean
|
||||
*/
|
||||
public static void cancelGBC(){
|
||||
DBBeanSQLResultHandler.cancelGBC();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be called whenever the bean has been updated from the database.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -26,11 +26,12 @@ import java.sql.PreparedStatement;
|
|||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.ResultSet;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import zutil.db.DBConnection;
|
||||
|
|
@ -42,10 +43,12 @@ import zutil.log.LogUtil;
|
|||
public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{
|
||||
public static final Logger logger = LogUtil.getLogger();
|
||||
/** This is the time to live for the cached items **/
|
||||
public static final long CACHE_TTL = 1000*60*1; // 1 min in ms
|
||||
public static final long CACHE_TTL = 1000*60*5; // 5 min in ms
|
||||
/** A cache for detecting recursion **/
|
||||
protected static Map<Class<?>, Map<Long,DBBeanCache>> cache =
|
||||
Collections.synchronizedMap(new HashMap<Class<?>, Map<Long,DBBeanCache>>());
|
||||
new ConcurrentHashMap<Class<?>, Map<Long,DBBeanCache>>();
|
||||
private static Timer timer;
|
||||
|
||||
/**
|
||||
* A cache container that contains a object and last read time
|
||||
*/
|
||||
|
|
@ -113,8 +116,64 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{
|
|||
this.list = list;
|
||||
this.db = db;
|
||||
this.bean_config = DBBean.getBeanConfig( cl );
|
||||
|
||||
// Initiate DBBeanGarbageCollector
|
||||
if( timer == null ){
|
||||
timer = new Timer( true ); // Run as daemon
|
||||
timer.schedule( new DBBeanGarbageCollector(), 10000, CACHE_TTL );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function cancels the internal cache garbage collector in DBBean
|
||||
*/
|
||||
public static void cancelGBC(){
|
||||
if( timer != null ){
|
||||
timer.cancel();
|
||||
timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class acts as an garbage collector that removes old DBBeans
|
||||
*
|
||||
* @author Ziver
|
||||
*/
|
||||
private static class DBBeanGarbageCollector extends TimerTask {
|
||||
public void run(){
|
||||
logger.fine("DBBean GarbageCollector has started.");
|
||||
if( cache == null ){
|
||||
logger.severe("DBBeanSQLResultHandler not initialized, stopping DBBeanGarbageCollector timer.");
|
||||
this.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
int removed = 0;
|
||||
long time = System.currentTimeMillis();
|
||||
Object[] class_keys = cache.keySet().toArray();
|
||||
for(Object key : class_keys){
|
||||
if( key == null ) continue;
|
||||
|
||||
Map<Long,DBBeanCache> class_cache = cache.get(key);
|
||||
Object[] bean_keys = class_cache.keySet().toArray();
|
||||
for(Object sub_key : bean_keys){
|
||||
if( sub_key == null ) continue;
|
||||
|
||||
DBBeanCache beanCache = class_cache.get(sub_key);
|
||||
// Check if session is still valid
|
||||
if( beanCache.timestamp + CACHE_TTL*2 < time ){
|
||||
class_cache.remove(sub_key);
|
||||
removed++;
|
||||
logger.finer("Removing old DBBean(id: "+beanCache.bean.getId()+") from cache.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( removed > 0 )
|
||||
logger.info("DBBeanGarbageCollector has cleard "+removed+" beans from cache.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called to handle a result from a query.
|
||||
*
|
||||
|
|
@ -289,7 +348,7 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{
|
|||
if( cache.containsKey(obj.getClass()) )
|
||||
cache.get(obj.getClass()).put(id, item);
|
||||
else{
|
||||
HashMap<Long, DBBeanCache> map = new HashMap<Long, DBBeanCache>();
|
||||
Map<Long, DBBeanCache> map = new ConcurrentHashMap<Long, DBBeanCache>();
|
||||
map.put(id, item);
|
||||
cache.put(obj.getClass(), map);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
|
@ -54,7 +55,7 @@ public class HttpServer extends ThreadedTCPNetworkServer{
|
|||
public final String server_url;
|
||||
public final int server_port;
|
||||
|
||||
private HashMap<String,HttpPage> pages;
|
||||
private Map<String,HttpPage> pages;
|
||||
private HttpPage defaultPage;
|
||||
private Map<String,Map<String,Object>> sessions;
|
||||
private int nextSessionId;
|
||||
|
|
@ -83,12 +84,12 @@ public class HttpServer extends ThreadedTCPNetworkServer{
|
|||
this.server_url = url;
|
||||
this.server_port = port;
|
||||
|
||||
pages = new HashMap<String,HttpPage>();
|
||||
sessions = Collections.synchronizedMap(new HashMap<String,Map<String,Object>>());
|
||||
pages = new ConcurrentHashMap<String,HttpPage>();
|
||||
sessions = new ConcurrentHashMap<String,Map<String,Object>>();
|
||||
nextSessionId = 0;
|
||||
|
||||
Timer timer = new Timer();
|
||||
timer.schedule(new GarbageCollector(), 0, SESSION_TTL / 2);
|
||||
timer.schedule(new GarbageCollector(), 10000, SESSION_TTL / 2);
|
||||
|
||||
logger.info("HTTP"+(keyStore==null?"":"S")+" Server ready!");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import zutil.net.ws.WebServiceDef;
|
|||
* This is an factory that generates clients for web services
|
||||
*
|
||||
* @author Ziver
|
||||
* TODO: Incomplete
|
||||
*/
|
||||
public class SOAPClientFactory {
|
||||
|
||||
|
|
|
|||
|
|
@ -94,12 +94,12 @@ public abstract class ThreadedTCPNetworkServer extends Thread{
|
|||
}
|
||||
} catch(Exception e) {
|
||||
logger.log(Level.SEVERE, null, e);
|
||||
}
|
||||
|
||||
if( ss!=null ){
|
||||
try{
|
||||
ss.close();
|
||||
}catch(IOException e){ logger.log(Level.SEVERE, null, e); }
|
||||
} finally {
|
||||
if( ss!=null ){
|
||||
try{
|
||||
ss.close();
|
||||
}catch(IOException e){ logger.log(Level.SEVERE, null, e); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -135,4 +135,12 @@ public abstract class ThreadedTCPNetworkServer extends Thread{
|
|||
System.setProperty("javax.net.ssl.keyStore", keyStore.getAbsolutePath());
|
||||
System.setProperty("javax.net.ssl.keyStorePassword", keyStorePass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the server and interrupts its internal thread.
|
||||
* This is a permanent action that will not be able to recover from
|
||||
*/
|
||||
public void close(){
|
||||
this.interrupt();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,5 +132,12 @@ public class ThreadedUDPNetwork extends Thread{
|
|||
this.thread = thread;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stops the server and interrupts its internal thread.
|
||||
* This is a permanent action that will not be able to recover from
|
||||
*/
|
||||
public void close(){
|
||||
this.interrupt();
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
145
src/zutil/parser/Base64Decoder.java
Normal file
145
src/zutil/parser/Base64Decoder.java
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
package zutil.parser;
|
||||
|
||||
public class Base64Decoder {
|
||||
public static final char[] B64_ENCODE_TABLE = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
|
||||
'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
|
||||
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
|
||||
'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
|
||||
's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8',
|
||||
'9', '+', '/'
|
||||
};
|
||||
|
||||
private StringBuilder output;
|
||||
private byte rest_data;
|
||||
private int rest = 0;
|
||||
|
||||
public Base64Decoder(){
|
||||
output = new StringBuilder();
|
||||
}
|
||||
|
||||
public void decode( String data ){
|
||||
byte[] buffer = new byte[ (data.length()*6/8) + 1 ];
|
||||
int buffi = 0;
|
||||
if( rest != 0 )
|
||||
buffer[0] = rest_data;
|
||||
|
||||
for( int i=0; i<data.length(); i++){
|
||||
char c = data.charAt(i);
|
||||
if( c == '='){
|
||||
rest = (rest + 2) % 8;
|
||||
continue;
|
||||
}
|
||||
byte b = getByte(c);
|
||||
|
||||
switch(rest){
|
||||
case 0:
|
||||
buffer[buffi] = (byte) ((b << 2) & 0xFC);
|
||||
break;
|
||||
case 2:
|
||||
buffer[buffi] |= (byte) ((b >> 4) & 0x03);
|
||||
buffer[++buffi] = (byte) ((b << 4) & 0xF0);
|
||||
break;
|
||||
case 4:
|
||||
buffer[buffi] |= (byte) ((b >> 2) & 0x0F);
|
||||
buffer[++buffi] = (byte) ((b << 6) & 0xC0);
|
||||
break;
|
||||
case 6:
|
||||
buffer[buffi++]|= (byte) (b & 0x3F);
|
||||
break;
|
||||
}
|
||||
|
||||
rest = (rest + 2) % 8;
|
||||
}
|
||||
|
||||
if( rest != 0 )
|
||||
rest_data = buffer[buffi--];
|
||||
output.append(new String(buffer, 0, buffi));
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
public void reset(){
|
||||
output = new StringBuilder();
|
||||
rest = 0;
|
||||
rest_data = 0;
|
||||
}
|
||||
|
||||
private byte getByte( char c ){
|
||||
switch(c){
|
||||
case 'A': return (byte)( 0 & 0xff);
|
||||
case 'B': return (byte)( 1 & 0xff);
|
||||
case 'C': return (byte)( 2 & 0xff);
|
||||
case 'D': return (byte)( 3 & 0xff);
|
||||
case 'E': return (byte)( 4 & 0xff);
|
||||
case 'F': return (byte)( 5 & 0xff);
|
||||
case 'G': return (byte)( 6 & 0xff);
|
||||
case 'H': return (byte)( 7 & 0xff);
|
||||
case 'I': return (byte)( 8 & 0xff);
|
||||
case 'J': return (byte)( 9 & 0xff);
|
||||
case 'K': return (byte)(10 & 0xff);
|
||||
case 'L': return (byte)(11 & 0xff);
|
||||
case 'M': return (byte)(12 & 0xff);
|
||||
case 'N': return (byte)(13 & 0xff);
|
||||
case 'O': return (byte)(14 & 0xff);
|
||||
case 'P': return (byte)(15 & 0xff);
|
||||
case 'Q': return (byte)(16 & 0xff);
|
||||
case 'R': return (byte)(17 & 0xff);
|
||||
case 'S': return (byte)(18 & 0xff);
|
||||
case 'T': return (byte)(19 & 0xff);
|
||||
case 'U': return (byte)(20 & 0xff);
|
||||
case 'V': return (byte)(21 & 0xff);
|
||||
case 'W': return (byte)(22 & 0xff);
|
||||
case 'X': return (byte)(23 & 0xff);
|
||||
case 'Y': return (byte)(24 & 0xff);
|
||||
case 'Z': return (byte)(25 & 0xff);
|
||||
|
||||
case 'a': return (byte)(26 & 0xff);
|
||||
case 'b': return (byte)(27 & 0xff);
|
||||
case 'c': return (byte)(28 & 0xff);
|
||||
case 'd': return (byte)(29 & 0xff);
|
||||
case 'e': return (byte)(30 & 0xff);
|
||||
case 'f': return (byte)(31 & 0xff);
|
||||
case 'g': return (byte)(32 & 0xff);
|
||||
case 'h': return (byte)(33 & 0xff);
|
||||
case 'i': return (byte)(34 & 0xff);
|
||||
case 'j': return (byte)(35 & 0xff);
|
||||
case 'k': return (byte)(36 & 0xff);
|
||||
case 'l': return (byte)(37 & 0xff);
|
||||
case 'm': return (byte)(38 & 0xff);
|
||||
case 'n': return (byte)(39 & 0xff);
|
||||
case 'o': return (byte)(40 & 0xff);
|
||||
case 'p': return (byte)(41 & 0xff);
|
||||
case 'q': return (byte)(42 & 0xff);
|
||||
case 'r': return (byte)(43 & 0xff);
|
||||
case 's': return (byte)(44 & 0xff);
|
||||
case 't': return (byte)(45 & 0xff);
|
||||
case 'u': return (byte)(46 & 0xff);
|
||||
case 'v': return (byte)(47 & 0xff);
|
||||
case 'w': return (byte)(48 & 0xff);
|
||||
case 'x': return (byte)(49 & 0xff);
|
||||
case 'y': return (byte)(50 & 0xff);
|
||||
case 'z': return (byte)(51 & 0xff);
|
||||
|
||||
case '0': return (byte)(52 & 0xff);
|
||||
case '1': return (byte)(53 & 0xff);
|
||||
case '2': return (byte)(54 & 0xff);
|
||||
case '3': return (byte)(55 & 0xff);
|
||||
case '4': return (byte)(56 & 0xff);
|
||||
case '5': return (byte)(57 & 0xff);
|
||||
case '6': return (byte)(58 & 0xff);
|
||||
case '7': return (byte)(59 & 0xff);
|
||||
case '8': return (byte)(60 & 0xff);
|
||||
case '9': return (byte)(61 & 0xff);
|
||||
case '+': return (byte)(62 & 0xff);
|
||||
case '/': return (byte)(63 & 0xff);
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/zutil/test/Base64Test.java
Normal file
48
src/zutil/test/Base64Test.java
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Ziver Koc
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package zutil.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import zutil.parser.Base64Decoder;
|
||||
|
||||
public class Base64Test {
|
||||
|
||||
@Test
|
||||
public void testHexToByte() {
|
||||
Base64Decoder decoder = new Base64Decoder();
|
||||
//decoder.decode("TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=");
|
||||
//assertEquals( "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.", decoder.toString() );
|
||||
decoder.reset();
|
||||
decoder.decode("YW55IGNhcm5hbCBwbGVhc3VyZQ==");
|
||||
assertEquals( "any carnal pleasure", decoder.toString() );
|
||||
decoder.reset();
|
||||
decoder.decode("bGVhc3VyZS4=");
|
||||
assertEquals( "leasure.", decoder.toString() );
|
||||
decoder.reset();
|
||||
decoder.decode("YW55IGNhcm5hbCBwbGVhc3Vy");
|
||||
assertEquals( "any carnal pleasur", decoder.toString() );
|
||||
decoder.reset();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue