diff --git a/src/zutil/Hasher.java b/src/zutil/Hasher.java index 7db683f..df4d79c 100644 --- a/src/zutil/Hasher.java +++ b/src/zutil/Hasher.java @@ -21,7 +21,7 @@ public class Hasher { * @return a String with the hash */ public static String hash(File file, String hashType) throws NoSuchAlgorithmException, IOException { - MessageDigest digest = MessageDigest.getInstance(hashType);//"MD5" + MessageDigest digest = MessageDigest.getInstance(hashType); //"MD5" InputStream is = new FileInputStream(file); String output = ""; byte[] buffer = new byte[8192]; @@ -71,6 +71,22 @@ public class Hasher { } return null; } + + /** + * Returns the MD5 hash of the given file + * + * @param object is the file to hash + * @return an String containing the hash + */ + public static String MD5(File file) throws IOException{ + try { + return hash(file, "MD5"); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return null; + } + /** * Returns the SHA-1 hash of the given object diff --git a/src/zutil/ProgressListener.java b/src/zutil/ProgressListener.java index e3c0f85..5055bc1 100644 --- a/src/zutil/ProgressListener.java +++ b/src/zutil/ProgressListener.java @@ -7,7 +7,7 @@ package zutil; * @author Ziver * */ -public interface ProgressListener { +public interface ProgressListener { /** * This method is called when the progress is updated @@ -16,5 +16,5 @@ public interface ProgressListener { * @param info is some information from the source object * @param percent is the progress of the object (0-100) */ - public void progressUpdate(Object source, T info, double percent); + public void progressUpdate(S source, D info, double percent); } diff --git a/src/zutil/converters/Converter.java b/src/zutil/converters/Converter.java index 4bb6554..e9cb650 100644 --- a/src/zutil/converters/Converter.java +++ b/src/zutil/converters/Converter.java @@ -15,9 +15,8 @@ public class Converter { /** * Converts an object to an array of bytes. * - * @param object the object to convert. - * @return the associated byte array. - * @throws IOException + * @param object the object to convert. + * @return the associated byte array. */ public static byte[] toBytes(Object object) throws IOException{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -33,8 +32,8 @@ public class Converter { /** * Converts a Integer to an byte array * - * @param num is the number to convert - * @return an byte array of four bytes + * @param num is the number to convert + * @return an byte array of four bytes */ public static byte[] toBytes(int num){ return new byte[]{ @@ -45,22 +44,62 @@ public class Converter { } /** - * Converts a Integer to an byte + * Converts a Integer to a byte * - * @param num is the number to convert - * @return an byte + * @param num is the number to convert + * @return an byte */ public static byte toByte(int num){ return (byte)(num & 0xff); } + + /** + * Converts hex chars to a byte + * + * @param quad1 is the first hex value + * @param quad2 is the second hex value + * @return a byte that corresponds to the hex + */ + public static int hexToByte( char quad1, char quad2){ + byte b = hexToByte( quad2 ); + b |= hexToByte( quad1 ) << 4; + return toInt(b); + } + + /** + * Converts a hex chars to a byte + * + * @param quad1 is the hex value + * @return a byte that corresponds to the hex + */ + public static byte hexToByte( char hex ){ + switch( Character.toLowerCase(hex) ){ + case '0': return 0x00; + case '1': return 0x01; + case '2': return 0x02; + case '3': return 0x03; + case '4': return 0x04; + case '5': return 0x05; + case '6': return 0x06; + case '7': return 0x07; + case '8': return 0x08; + case '9': return 0x09; + case 'a': return 0x0a; + case 'b': return 0x0b; + case 'c': return 0x0c; + case 'd': return 0x0d; + case 'e': return 0x0e; + case 'f': return 0x0f; + } + return (byte)0; + } /** * 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. - * @throws Exception + * @param bytes the byte array to convert. + * @return the associated object. */ public static Object toObject(byte[] bytes) throws Exception{ Object object = null; @@ -76,9 +115,8 @@ public class Converter { * 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. - * @throws Exception + * @param bytes the byte array to convert. + * @return the associated object. */ public static Object toObject(DynamicByteArrayStream bytes) throws Exception{ Object object = null; @@ -93,9 +131,9 @@ public class Converter { /** * 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 + * @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 */ public static boolean isInstanceOf(Object object, Class interf){ Class[] objectInterf = object.getClass().getInterfaces(); @@ -112,8 +150,8 @@ public class Converter { /** * Converts a byte Array to a Hex String * - * @param raw the byte array to convert - * @return a Hex String + * @param raw the byte array to convert + * @return a Hex String */ public static String toHexString(byte[][] raw){ StringBuffer ret = new StringBuffer(); @@ -144,8 +182,8 @@ public class Converter { /** * Converts a byte Array to a Hex String * - * @param raw the byte array to convert - * @return a Hex String + * @param raw the byte array to convert + * @return a Hex String */ public static String toHexString(byte[] raw){ StringBuffer ret = new StringBuffer(); @@ -161,8 +199,8 @@ public class Converter { /** * Converts a byte to a Hex String * - * @param raw the byte to convert - * @return a Hex String + * @param raw the byte to convert + * @return a Hex String */ public static String toHexString(byte raw){ String ret = ""+HEX_CHARS[(int) (raw >>> 0x04)& 0x0F ]; @@ -174,8 +212,8 @@ public class Converter { /** * Converts the given byte to a String with 1's and 0's * - * @param raw the byte to convert - * @return a String with 1's and 0's + * @param raw the byte to convert + * @return a String with 1's and 0's */ public static String toString(byte raw){ StringBuffer ret = new StringBuffer(); @@ -188,8 +226,8 @@ public class Converter { /** * Converts the given byte array to a String with 1's and 0's * - * @param raw the byte array to convert - * @return a String with 1's and 0's + * @param raw the byte array to convert + * @return a String with 1's and 0's */ public static String toString(byte[] raw){ StringBuffer ret = new StringBuffer(); @@ -204,8 +242,8 @@ public class Converter { /** * Converts a BitSet to a Integer * - * @param bits the BitSet to convert - * @return a Integer + * @param bits the BitSet to convert + * @return a Integer */ public static int toInt(BitSet bits){ int ret = 0; @@ -220,8 +258,8 @@ public class Converter { /** * Converts a boolean array(bit sequence whit most significant bit at index 0) to a Integer * - * @param bits the boolean array to convert - * @return a Integer + * @param bits the boolean array to convert + * @return a Integer */ public static int toInt(boolean[] bits){ int ret = 0; @@ -232,12 +270,22 @@ public class Converter { return ret; } + + /** + * Converts a byte to a integer + * + * @param num is the byte to convert + * @return an integer + */ + public static int toInt(byte b){ + return (int)(b & 0xff); + } /** * Converts a Integer to a BitSet * - * @param i the Integer to convert - * @return a BitSet object + * @param i the Integer to convert + * @return a BitSet object */ public static BitSet toBitSet(int num){ BitSet ret = new BitSet(); @@ -253,10 +301,10 @@ public class Converter { /** * Converts a given String to a specified class * - * @param is the resulting class - * @param data is the String data to be converted - * @param c is the class to convert to - * @return a instance of the class with the value in the string or null if there was an problem + * @param is the resulting class + * @param data is the String data to be converted + * @param c is the class to convert to + * @return a instance of the class with the value in the string or null if there was an problem */ @SuppressWarnings("unchecked") public static T fromString(String data, Class c){ @@ -283,4 +331,40 @@ public class Converter { } return null; } + + /** + * Replaces reserved and unsafe characters in URLs with hex values + */ + public static String urlEncode( String str ){ + StringBuilder out = new StringBuilder(); + for( char c : str.toCharArray() ){ + if( c>='0' && c<='9' || c>='A' && c<='Z' || c>='a' && c<='z' || + c=='$' || c=='-' || c=='_' || c=='.' || c=='+' || c=='!' || + c=='*' || c=='\'' || c=='(' || c==')' || c==',' ) + out.append( c ); + else{ + out.append( '%' ).append( toHexString((byte)c) ); + } + } + + return out.toString(); + } + + /** + * Replaces hex values from a URL with the proper characters + */ + public static String urlDecode( String str ){ + StringBuilder out = new StringBuilder(); + char[] array = str.toCharArray(); + for( int i=0; i()); + return exec("SELECT LAST_INSERT_ID()", new SimpleSQLHandler()); }catch(SQLException e){ logger.log(Level.WARNING, null, e); } diff --git a/src/zutil/db/bean/DBBean.java b/src/zutil/db/bean/DBBean.java index 316e779..5e396d5 100644 --- a/src/zutil/db/bean/DBBean.java +++ b/src/zutil/db/bean/DBBean.java @@ -25,7 +25,7 @@ import zutil.log.LogUtil; * * The class that extends this will be able to save its state to a DB. * Fields that are transient will be ignored, and fields that extend - * DBBean will be replaced by the id field of that class. + * DBBean will be replaced with the id field of that class in the database. * * Supported fields: * *Boolean @@ -54,8 +54,10 @@ public abstract class DBBean { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface DBTable { - /** This is the name of the table, SQL rules apply, No " or whitespace **/ + /** This is the name of the table, SQL rules apply should not contain any strange characters or spaces **/ String value(); + /** Change the id column name of the bean, default column name is "id", SQL rules apply should not contain any strange characters or spaces **/ + String idColumn() default "id"; /** Sets if the fields in the super classes is also part of the bean **/ boolean superBean() default false; } @@ -66,11 +68,11 @@ public abstract class DBBean { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface DBLinkTable { - /** The name of the Link table, should not contain any strange characters or spaces */ - String name(); + /** The name of the Link table, SQL rules apply should not contain any strange characters or spaces */ + String table(); /** The class of the linked bean */ Class<? extends DBBean> beanClass(); - /** The name of the column that contains the main objects id */ + /** The name of the column that contains the main objects id, SQL rules apply should not contain any strange characters or spaces */ String idColumn() default ""; } @@ -78,9 +80,11 @@ public abstract class DBBean { * A Class that contains information about a bean */ protected static class DBBeanConfig{ - /** The name of the table in the DB */ + /** The name of the table in the DB **/ protected String tableName; - /** All the fields in the bean */ + /** The name of the id column **/ + protected String idColumn; + /** All the fields in the bean **/ protected ArrayList<Field> fields; protected DBBeanConfig(){ @@ -128,8 +132,14 @@ public abstract class DBBean { DBBeanConfig config = new DBBeanConfig(); // Find the table name DBTable tableAnn = c.getAnnotation(DBTable.class); - if( tableAnn != null ) - config.tableName = tableAnn.value().replace('\"', '_'); + if( tableAnn != null ){ + config.tableName = tableAnn.value(); + config.idColumn = tableAnn.idColumn(); + } + else{ + config.tableName = c.getSimpleName(); + config.idColumn = "id"; + } // Add the fields in the bean and all the super classes fields for(Class<?> cc = c; cc != DBBean.class ;cc = cc.getSuperclass()){ Field[] fields = cc.getDeclaredFields(); @@ -196,7 +206,7 @@ public abstract class DBBean { query.append( " SET" ); query.append( params ); if( id != null ) - query.append( " WHERE id=?" ); + query.append(" WHERE ").append(config.idColumn).append("=?"); } logger.finest("Save query("+c.getName()+" id:"+this.getId()+"): "+query.toString()); PreparedStatement stmt = db.getPreparedStatement( query.toString() ); @@ -243,7 +253,7 @@ public abstract class DBBean { List<DBBean> list = (List<DBBean>)getFieldValue(field); if( list != null ){ DBLinkTable linkTable = field.getAnnotation( DBLinkTable.class ); - String subtable = linkTable.name(); + String subtable = linkTable.table(); String idcol = (linkTable.idColumn().isEmpty() ? config.tableName : linkTable.idColumn() ); String sub_idcol = "id"; @@ -257,8 +267,10 @@ public abstract class DBBean { continue; } // Get the Sub object configuration - if(subConfig == null) + if(subConfig == null){ subConfig = getBeanConfig( subobj.getClass() ); + sub_idcol = subConfig.idColumn; + } // Save links in link table String subsql = ""; if( subtable.equals(subConfig.tableName) ) @@ -294,7 +306,7 @@ public abstract class DBBean { if( this.getId() == null ) throw new NoSuchElementException("ID field is null( Has the bean been saved?)!"); - String sql = "DELETE FROM "+config.tableName+" WHERE id=?"; + String sql = "DELETE FROM "+config.tableName+" WHERE "+config.idColumn+"=?"; logger.fine("Delete query("+c.getName()+" id:"+this.getId()+"): "+sql); PreparedStatement stmt = db.getPreparedStatement( sql ); // Put in the variables in the SQL @@ -336,7 +348,7 @@ public abstract class DBBean { // Initiate a BeanConfig if there is non DBBeanConfig config = getBeanConfig( c ); // Generate query - String sql = "SELECT * FROM "+config.tableName+" WHERE id=? LIMIT 1"; + String sql = "SELECT * FROM "+config.tableName+" WHERE "+config.idColumn+"=? LIMIT 1"; logger.fine("Load query("+c.getName()+" id:"+id+"): "+sql); PreparedStatement stmt = db.getPreparedStatement( sql ); stmt.setObject(1, id ); @@ -357,7 +369,7 @@ public abstract class DBBean { query.append("CREATE TABLE "+config.tableName+" ( "); // ID - query.append(" id "); + query.append(" ").append(config.idColumn).append(" "); query.append( classToDBName( Long.class ) ); query.append(" PRIMARY KEY AUTO_INCREMENT, "); @@ -424,7 +436,10 @@ public abstract class DBBean { */ protected void setFieldValue(Field field, Object o){ try { - field.setAccessible(true); + if( !Modifier.isPublic( field.getModifiers())) + field.setAccessible(true); + + // Set basic datatype if( o == null && !Object.class.isAssignableFrom( field.getType() ) ){ logger.fine("Trying to set primitive data type to null!"); if( field.getType() == Integer.TYPE ) field.setInt(this, 0); @@ -449,4 +464,9 @@ public abstract class DBBean { public Long getId(){ return id; } + + /** + * Will be called whenever the bean has been updated from the database. + */ + protected void updatePerformed(){} } diff --git a/src/zutil/db/bean/DBBeanSQLResultHandler.java b/src/zutil/db/bean/DBBeanSQLResultHandler.java index fc7e9f0..fb3f1c8 100644 --- a/src/zutil/db/bean/DBBeanSQLResultHandler.java +++ b/src/zutil/db/bean/DBBeanSQLResultHandler.java @@ -95,7 +95,7 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{ } /** - * Is called to handle an result from an query. + * Is called to handle a result from a query. * * @param stmt is the query * @param result is the ResultSet @@ -179,13 +179,13 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{ if(db != null){ DBLinkTable linkTable = field.getAnnotation( DBLinkTable.class ); DBBeanConfig subConfig = DBBean.getBeanConfig( linkTable.beanClass() ); - String linkTableName = linkTable.name(); + String linkTableName = linkTable.table(); String subTable = subConfig.tableName; String idcol = (linkTable.idColumn().isEmpty() ? bean_config.tableName : linkTable.idColumn() ); // Load list from link table //String subsql = "SELECT * FROM "+linkTableName+" NATURAL JOIN "+subConfig.tableName+" WHERE "+idcol+"=?"; - String subsql = "SELECT obj.* FROM "+linkTableName+" as link, "+subTable+" as obj WHERE obj."+idcol+"=? AND obj.id=link.id"; + String subsql = "SELECT obj.* FROM "+linkTableName+" as link, "+subTable+" as obj WHERE obj."+idcol+"=? AND obj."+bean_config.idColumn+"=link.id"; logger.finest("List Load Query: "+subsql); PreparedStatement subStmt = db.getPreparedStatement( subsql ); subStmt.setObject(1, obj.getId() ); @@ -203,6 +203,8 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{ } finally{ obj.processing_update = false; } + + obj.updatePerformed(); } /** diff --git a/src/zutil/db/handler/PropertiesSQLHandler.java b/src/zutil/db/handler/PropertiesSQLHandler.java new file mode 100644 index 0000000..ec22719 --- /dev/null +++ b/src/zutil/db/handler/PropertiesSQLHandler.java @@ -0,0 +1,45 @@ +package zutil.db.handler; + +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.ResultSet; +import java.util.Properties; + +import zutil.db.SQLResultHandler; + +/** + * Adds the result of the query to a Properties object, + * + * The handler sets the first column of the result as + * the key and the second column as the value + * + * @author Ziver + */ +public class PropertiesSQLHandler implements SQLResultHandler<Properties> { + + private Properties prop; + + /** + * Creates a new Properties object to be filled + */ + public PropertiesSQLHandler(){ + this.prop = new Properties(); + } + + /** + * Adds data to a existing Properties object + */ + public PropertiesSQLHandler(Properties p){ + this.prop = p; + } + + + /** + * Is called to handle an result from an query. + */ + public Properties handleQueryResult(Statement stmt, ResultSet result) throws SQLException{ + while( result.next() ) + prop.setProperty(result.getString(0), result.getString(1)); + return prop; + } +} diff --git a/src/zutil/db/handler/SimpleResultHandler.java b/src/zutil/db/handler/SimpleSQLHandler.java similarity index 85% rename from src/zutil/db/handler/SimpleResultHandler.java rename to src/zutil/db/handler/SimpleSQLHandler.java index 5a4036d..e1d5e6e 100644 --- a/src/zutil/db/handler/SimpleResultHandler.java +++ b/src/zutil/db/handler/SimpleSQLHandler.java @@ -11,7 +11,7 @@ import zutil.db.SQLResultHandler; * * @author Ziver */ -public class SimpleResultHandler<T> implements SQLResultHandler<T> { +public class SimpleSQLHandler<T> implements SQLResultHandler<T> { /** * Is called to handle an result from an query. * diff --git a/src/zutil/image/ImageFilterProcessor.java b/src/zutil/image/ImageFilterProcessor.java index 8ca727a..29f2df0 100644 --- a/src/zutil/image/ImageFilterProcessor.java +++ b/src/zutil/image/ImageFilterProcessor.java @@ -14,7 +14,7 @@ import zutil.ProgressListener; */ public abstract class ImageFilterProcessor { private BufferedImage img; - private ProgressListener<?> progress; + private ProgressListener<ImageFilterProcessor,?> progress; public ImageFilterProcessor(BufferedImage img){ this.img = img; @@ -22,16 +22,16 @@ public abstract class ImageFilterProcessor { /** * Sets the listener - * @param listener is the listener, null to disable the progress + * @param listener is the listener, null to disable the progress */ - public void setProgressListener(ProgressListener<?> listener){ + public void setProgressListener(ProgressListener<ImageFilterProcessor,?> listener){ this.progress = listener; } /** * Returns the listener */ - public ProgressListener<?> getProgressListener(){ + public ProgressListener<?,?> getProgressListener(){ return this.progress; } @@ -45,9 +45,9 @@ public abstract class ImageFilterProcessor { /** * Applies a effect to a given image * - * @param effect The effect to use - * @param img The image to process - * @return The processed 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(); @@ -58,8 +58,7 @@ public abstract class ImageFilterProcessor { /** * Adds the chosen effect to the image * - * @return The Image with the effect - * @throws InterruptedException + * @return The Image with the effect */ public BufferedImage process() throws InterruptedException{ int cols = img.getWidth(); @@ -78,18 +77,17 @@ public abstract class ImageFilterProcessor { } /** - * Creates a Integer array with the pixel data of the image - * int[row][col][4] + * Creates a Integer array with the pixel data of the image <XMP> + * int[row][col][4] * 0 -> Alpha data - * Red data - * Green data - * 4 -> Blue data + * Red data + * Green data + * 4 -> Blue data * - * @param img is the image to convert - * @param cols is the columns of the image - * @param rows is the rows of the image - * @return A is the integer array - * @throws InterruptedException + * @param img is the image to convert + * @param cols is the columns of the image + * @param rows is the rows of the image + * @return A is the integer array */ public static int[][][] convertToArray(BufferedImage img, int cols, int rows) throws InterruptedException{ int[][][] data = new int[rows][cols][4]; @@ -124,10 +122,10 @@ public abstract class ImageFilterProcessor { /** * Converts a pixel data array to a java Image object * - * @param pixels is the pixel data array - * @param cols is the columns of the image - * @param rows is the rows of the image - * @return A Image + * @param pixels is the pixel data array + * @param cols is the columns of the image + * @param rows is the rows of the image + * @return A Image */ public static BufferedImage convertToImage(int[][][] pixels, int cols, int rows){ int[] data = new int[cols * rows * 4]; @@ -156,7 +154,8 @@ public abstract class ImageFilterProcessor { /** * Runs the image thru the processor - * @param data is the raw image to apply the effect to. This will NOT be altered + * + * @param data is the raw image to apply the effect to. This will NOT be altered */ public int[][][] process(int[][][] data){ return process(data, 0, 0, data[0].length, data.length); @@ -165,12 +164,12 @@ public abstract class ImageFilterProcessor { /** * The underlying effect is run here * - * @param data is the raw image to apply the effect to. This will NOT be altered - * @param startX is the x pixel of the image to start from - * @param startY is the y pixel of the image to start from - * @param stopX is the x pixel of the image to stop - * @param stopY is the y pixel of the image to stop - * @return either the modified data parameter or an new array + * @param data is the raw image to apply the effect to. This will NOT be altered + * @param startX is the x pixel of the image to start from + * @param startY is the y pixel of the image to start from + * @param stopX is the x pixel of the image to stop + * @param stopY is the y pixel of the image to stop + * @return either the modified data parameter or an new array */ public abstract int[][][] process(int[][][] data, int startX, int startY, int stopX, int stopY); } diff --git a/src/zutil/io/BoundaryBufferedInputStream.java b/src/zutil/io/BoundaryBufferedInputStream.java index a4dd6b3..4d2996b 100644 --- a/src/zutil/io/BoundaryBufferedInputStream.java +++ b/src/zutil/io/BoundaryBufferedInputStream.java @@ -27,7 +27,7 @@ public class BoundaryBufferedInputStream extends FilterInputStream{ /** * Creates a instance of this class with a default buffer size of 64K * - * @param in is the InputStream that the buffer will use + * @param in is the InputStream that the buffer will use */ public BoundaryBufferedInputStream(InputStream in){ this(in, DEFAULT_BUF_SIZE); @@ -41,7 +41,8 @@ public class BoundaryBufferedInputStream extends FilterInputStream{ */ public BoundaryBufferedInputStream(InputStream in, int buf_size){ super(in); - reset(); + buf_end = 0; + buf_pos = 0; buffer = new byte[buf_size]; } @@ -50,7 +51,7 @@ public class BoundaryBufferedInputStream extends FilterInputStream{ * buffer and then fills the buffer with data from * the source stream to the buffer * - * @return the size of the buffer + * @return the size of the buffer * @throws IOException */ protected int fillBuffer() throws IOException { @@ -64,38 +65,28 @@ public class BoundaryBufferedInputStream extends FilterInputStream{ return n+leftover; } - /** - * Resets the buffer - * - * @throws IOException - */ - public synchronized void reset(){ - buf_end = 0; - buf_pos = 0; - } /** - * @return the next byte in the buffer + * @return the next byte in the buffer */ public final int read() throws IOException{ - if(buf_pos >= buf_end) { + if(buf_pos >= buf_end-boundary.length) { if(fillBuffer() < 0) return -1; } if(buf_end == 0) { return -1; } else { - buf_pos++; - return buffer[buf_pos-1]; + return buffer[buf_pos++]; } } /** * Fills the given array with data from the buffer * - * @param b is the array that will be filled - * @return the amount of bytes read or -1 if eof - */ + * @param b is the array that will be filled + * @return the amount of bytes read or -1 if EOF + */ public int read(byte b[]) throws IOException { return read(b, 0, b.length); } @@ -106,10 +97,10 @@ public class BoundaryBufferedInputStream extends FilterInputStream{ * @param b is the array that will be filled * @param off is the offset in the array * @param len is the amount to read - * @return the amount of bytes read or -1 if eof + * @return the amount of bytes read or -1 if EOF */ public int read(byte b[], int off, int len) throws IOException { - if(buf_pos >= buf_end) { + if(buf_pos >= buf_end-boundary.length) { if(fillBuffer() < 0) return -1; // EOF } @@ -129,6 +120,13 @@ public class BoundaryBufferedInputStream extends FilterInputStream{ return leftover; } + /** + * TODO: Skips over the boundary + */ + public void next(){ + + } + /** * @param n the number of bytes to be skipped. * @return the actual number of bytes skipped. @@ -141,6 +139,21 @@ public class BoundaryBufferedInputStream extends FilterInputStream{ } return buf_pos += n; } + + /** + * Sets the boundary for the stream + */ + public void setBoundary(String b){ + this.boundary = b.getBytes(); + } + + /** + * Sets the boundary for the stream + */ + public void setBoundary(byte[] b){ + boundary = new byte[b.length]; + System.arraycopy(b, 0, boundary, 0, b.length); + } /** * @return an estimate of the number of bytes that can be read (or skipped @@ -152,7 +165,10 @@ public class BoundaryBufferedInputStream extends FilterInputStream{ } /** - * Unimplemented - */ - public synchronized void mark(int readlimit) {} + * Tests if this input stream supports the mark and + * reset methods. + */ + public boolean markSupported(){ + return false; + } } diff --git a/src/zutil/io/StringInputStream.java b/src/zutil/io/StringInputStream.java new file mode 100644 index 0000000..d8b98b4 --- /dev/null +++ b/src/zutil/io/StringInputStream.java @@ -0,0 +1,108 @@ +package zutil.io; + +import java.io.InputStream; + +/** + * This class saves all the input data in to an StringBuffer + * + * @author Ziver + * + */ +public class StringInputStream extends InputStream{ + // The buffer + protected StringBuilder buffer; + + /** + * Creates an new instance of this class + */ + public StringInputStream(){ + clear(); + } + + /** + * Returns an estimate of the number of bytes + * that can be read (or skipped over) from this + * input stream without blocking by the next + * invocation of a method for this input stream. + */ + public int available(){ + return buffer.length(); + } + + + /** + * Reads the next byte of data from the input stream. + */ + public int read(){ + int ret = Character.getNumericValue( buffer.charAt( 0 )); + buffer.deleteCharAt( 0 ); + return ret; + } + + /** + * Reads some number of bytes from the input stream + * and stores them into the buffer array b. + */ + public int read(byte[] b){ + return read( b, 0, b.length ); + } + + /** + * Reads up to len bytes of data from the input stream + * into an array of bytes. + */ + public int read(byte[] b, int off, int len){ + if( buffer.length() < len ){ + len = buffer.length(); + } + char[] ctmp = new char[len]; + buffer.getChars(0, len, ctmp, 0); + byte[] btmp = new String( ctmp ).getBytes(); + System.arraycopy(btmp, 0, b, off, len); + return len; + } + + + /** + * Skips over and discards n bytes of data from this + * input stream. + * + * @param n is the amount characters to skip + */ + public long skip(long n){ + if( buffer.length() < n ){ + int len = buffer.length(); + buffer.delete(0, len); + return len; + } + else{ + buffer.delete(0, (int) n); + return n; + } + } + + /** + * Tests if this input stream supports the mark and + * reset methods. + */ + public boolean markSupported(){ + return false; + } + + + /** + * Closes this input stream and releases any system + * resources associated with the stream. + */ + public void close(){ + clear(); + } + + public void clear(){ + buffer = new StringBuilder(); + } + + public void add( String data ){ + buffer.append( data ); + } +} diff --git a/src/zutil/io/file/FileUtil.java b/src/zutil/io/file/FileUtil.java index 975930d..8913830 100644 --- a/src/zutil/io/file/FileUtil.java +++ b/src/zutil/io/file/FileUtil.java @@ -10,10 +10,12 @@ import java.net.URL; import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.logging.Logger; import java.util.regex.Matcher; import zutil.io.IOUtil; import zutil.io.MultiPrintStream; +import zutil.log.LogUtil; /** * File path utilities @@ -21,6 +23,7 @@ import zutil.io.MultiPrintStream; * @author Ziver */ public class FileUtil { + public static final Logger logger = LogUtil.getLogger(); /** * Returns a String with a relative path from the given path @@ -30,6 +33,8 @@ public class FileUtil { * @return A String with a relative path */ public static String relativePath(File file, String path){ + if( file == null || path == null ) + return null; String absolute = file.getAbsolutePath(); String tmpPath = path.replaceAll( "[/\\\\]", @@ -231,10 +236,11 @@ public class FileUtil { for(int i=0; i @@ -139,7 +139,7 @@ public abstract class AjaxFileUpload extends HttpServlet { } // Generate JSON - JSONNode root = new JSONNode( JSONType.List ); + DataNode root = new DataNode( DataType.List ); Iterator it = list.iterator(); while( it.hasNext() ) { FileUploadListener listener = it.next(); diff --git a/src/zutil/jee/upload/FileUploadListener.java b/src/zutil/jee/upload/FileUploadListener.java index 231169c..9923c3f 100644 --- a/src/zutil/jee/upload/FileUploadListener.java +++ b/src/zutil/jee/upload/FileUploadListener.java @@ -3,8 +3,8 @@ package zutil.jee.upload; import org.apache.commons.fileupload.ProgressListener; import zutil.StringUtil; -import zutil.parser.json.JSONNode; -import zutil.parser.json.JSONNode.JSONType; +import zutil.parser.DataNode; +import zutil.parser.DataNode.DataType; /** @@ -121,18 +121,18 @@ public class FileUploadListener implements ProgressListener{ return (int)((100 * bytes) / length); } - public JSONNode getJSON() { - JSONNode node = new JSONNode( JSONType.Map ); - node.add("id", id); + public DataNode getJSON() { + DataNode node = new DataNode( DataType.Map ); + node.set("id", id); - node.add("status", status.toString()); - node.add("message", message.replaceAll("\"", "\\\"") ); - node.add("filename", filename); - node.add("percent", getPercentComplete()); + node.set("status", status.toString()); + node.set("message", message.replaceAll("\"", "\\\"") ); + node.set("filename", filename); + node.set("percent", getPercentComplete()); - node.add("uploaded", StringUtil.formatBytesToString( bytes )); - node.add("total", StringUtil.formatBytesToString( length )); - node.add("speed", StringUtil.formatBytesToString( speed )+"/s"); + node.set("uploaded", StringUtil.formatBytesToString( bytes )); + node.set("total", StringUtil.formatBytesToString( length )); + node.set("speed", StringUtil.formatBytesToString( speed )+"/s"); return node; } } \ No newline at end of file diff --git a/src/zutil/log/CompactLogFormatter.java b/src/zutil/log/CompactLogFormatter.java index 0057d83..29e6ee0 100644 --- a/src/zutil/log/CompactLogFormatter.java +++ b/src/zutil/log/CompactLogFormatter.java @@ -1,5 +1,6 @@ package zutil.log; +import java.io.PrintStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; @@ -7,13 +8,15 @@ import java.util.logging.Formatter; import java.util.logging.LogRecord; import java.util.regex.Pattern; +import zutil.io.StringOutputStream; + public class CompactLogFormatter extends Formatter{ // The split pattern where the private static final Pattern splitter = Pattern.compile("\n"); // the stream should print time stamp private boolean timeStamp = true; //The time stamp style - private SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss "); + private SimpleDateFormat dateFormatter = new SimpleDateFormat(); // If displaying class names are enabled private boolean className = true; // If displaying method names are enabled @@ -24,26 +27,28 @@ public class CompactLogFormatter extends Formatter{ private static HashMap padd_cache = new HashMap(); // Date temp file private Date date = new Date(); - + @Override public String format(LogRecord record) { StringBuilder data = new StringBuilder(); - + if( timeStamp ){ date.setTime( record.getMillis() ); - data.append( dateFormatter.format(date) ); + data.append( dateFormatter.format(date) ); + data.append(' '); } - + switch( record.getLevel().intValue() ){ - case /* SEVERE */ 1000: data.append("SEVERE "); break; - case /* WARNING */ 900 : data.append("WARNING "); break; - case /* INFO */ 800 : data.append("INFO "); break; - case /* CONFIG */ 700 : data.append("CONFIG "); break; - case /* FINE */ 500 : data.append("FINE "); break; - case /* FINER */ 400 : data.append("FINER "); break; - case /* FINEST */ 300 : data.append("FINEST "); break; + case /* SEVERE */ 1000: data.append("[SEVERE] "); break; + case /* WARNING */ 900 : data.append("[WARNING]"); break; + case /* INFO */ 800 : data.append("[INFO] "); break; + case /* CONFIG */ 700 : data.append("[CONFIG] "); break; + case /* FINE */ 500 : data.append("[FINE] "); break; + case /* FINER */ 400 : data.append("[FINER] "); break; + case /* FINEST */ 300 : data.append("[FINEST] "); break; } - + data.append(' '); + if( className ){ data.append( paddClassName(record.getSourceClassName()) ); } @@ -51,20 +56,35 @@ public class CompactLogFormatter extends Formatter{ data.append( record.getSourceMethodName() ); } data.append( ": " ); - + StringBuffer ret = new StringBuffer(); - String[] array = splitter.split( record.getMessage() ); - for( int i=0; i 0 ) - ret.append( data ); - ret.append( array[i] ); + if( record.getMessage() != null ){ + String[] array = splitter.split( record.getMessage() ); + for( int i=0; i 0 ) + ret.append( data ); + ret.append( array[i] ); + } + } + ret.append( '\n' ); + if( record.getThrown() != null ){ + StringOutputStream out = new StringOutputStream(); + record.getThrown().printStackTrace(new PrintStream(out)); + String[] array = splitter.split( out.toString() ); + for( int i=0; i 0 ) + ret.append( data ); + ret.append( array[i] ); + } + ret.append( '\n' ); } - ret.append( '\n' ); return ret.toString(); } - + /** * If the formatter should add a time stamp in front of the log message * @@ -82,7 +102,7 @@ public class CompactLogFormatter extends Formatter{ public void setTimeStamp(String ts){ dateFormatter = new SimpleDateFormat(ts); } - + /** * If the formatter should add the class/source name in front of the log message * @@ -91,7 +111,7 @@ public class CompactLogFormatter extends Formatter{ public void enableClassName(boolean enable){ className = enable; } - + /** * If the formatter should add the class/source name in front of the log message * @@ -100,7 +120,7 @@ public class CompactLogFormatter extends Formatter{ public void enableMethodName(boolean enable){ methodName = enable; } - + /** * @return the Class name */ @@ -108,18 +128,18 @@ public class CompactLogFormatter extends Formatter{ String tmp = padd_cache.get(source); if( tmp != null ) return tmp; - + String c_name = source.substring( source.lastIndexOf('.')+1 ); if( c_name.length() > max_class_name ) max_class_name = c_name.length(); - + StringBuilder sb = new StringBuilder( c_name ); - for( int i=c_name.length(); i 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 = FileUtil.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(); - } -} diff --git a/src/zutil/net/UpdateServer.java b/src/zutil/net/UpdateServer.java deleted file mode 100644 index f06ca0c..0000000 --- a/src/zutil/net/UpdateServer.java +++ /dev/null @@ -1,166 +0,0 @@ -package zutil.net; - -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 java.util.List; - -import zutil.Hasher; -import zutil.io.MultiPrintStream; -import zutil.io.file.FileUtil; - -public class UpdateServer extends Thread{ - private ArrayList 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 clientFileList = (ArrayList)in.readObject(); - File tmpPath = FileUtil.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 getFileList(String path) throws Exception{ - ArrayList fileHash = new ArrayList(); - - List files = FileUtil.search(FileUtil.find(path)); - for(File file : files){ - fileHash.add(new FileHash( - FileUtil.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; - } -} diff --git a/src/zutil/net/Zupdater.java b/src/zutil/net/Zupdater.java deleted file mode 100644 index 89e04a1..0000000 --- a/src/zutil/net/Zupdater.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Zupdater.java - * - * Created on den 27 juli 2008, 23:32 - */ - -package zutil.net; - -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. - */ - // - 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(); - }// - - 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 - -} diff --git a/src/zutil/net/http/HttpClient.java b/src/zutil/net/http/HttpClient.java new file mode 100644 index 0000000..553a6d1 --- /dev/null +++ b/src/zutil/net/http/HttpClient.java @@ -0,0 +1,98 @@ +package zutil.net.http; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.Socket; +import java.net.URL; +import java.util.HashMap; + +import zutil.net.http.HttpPrintStream.HttpMessageType; + +/** + * This class connects to a HTTP server and + * parses the result + * + * @author Ziver + */ +public class HttpClient { + public static enum HttpRequestType{ + GET, POST + } + + private HttpURL url; + private HttpRequestType type; + private HashMap headers; + private HashMap cookies; + + + public static HttpClient POST(){ + return new HttpClient( HttpRequestType.POST ); + } + + public static HttpClient GET(){ + return new HttpClient( HttpRequestType.GET ); + } + + + private HttpClient(HttpRequestType type){ + this.type = type; + headers = new HashMap(); + cookies = new HashMap(); + } + + + public void setURL( URL url){ + this.url = new HttpURL( url ); + } + + /** + * Adds a parameter to the request + */ + public void setParameter( String key, String value ){ + url.setParameter(key, value); + } + + /** + * Adds a cookie to the request + */ + public void setCookie( String key, String value ){ + cookies.put(key, value); + } + + /** + * Adds a header value to the request + */ + public void setHeader( String key, String value ){ + headers.put(key, value); + } + + public HttpHeaderParser send() throws IOException{ + Socket conn = new Socket( url.getHost(), url.getPort()); + + // Request + HttpPrintStream request = new HttpPrintStream( conn.getOutputStream(), HttpMessageType.REQUEST ); + request.setRequestType( type.toString() ); + request.setRequestURL( url.getHttpURL() ); + request.setHeaders( headers ); + request.setCookies( cookies ); + + if( type == HttpRequestType.POST ){ + String data = url.getParameterString(); + request.setHeader("Content-Length", data); + request.println(); + request.print( data ); + + } + else + request.println(""); + request.flush(); + + // Response + BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); + HttpHeaderParser response = new HttpHeaderParser( in ); + conn.close(); + + return response; + } +} diff --git a/src/zutil/net/http/HTTPHeaderParser.java b/src/zutil/net/http/HttpHeaderParser.java similarity index 91% rename from src/zutil/net/http/HTTPHeaderParser.java rename to src/zutil/net/http/HttpHeaderParser.java index 3ec6800..3c9dc43 100644 --- a/src/zutil/net/http/HTTPHeaderParser.java +++ b/src/zutil/net/http/HttpHeaderParser.java @@ -6,7 +6,7 @@ import java.util.HashMap; import java.util.Scanner; import java.util.regex.Pattern; -public class HTTPHeaderParser { +public class HttpHeaderParser { // Some Cached regex's private static final Pattern colonPattern = Pattern.compile(":"); private static final Pattern equalPattern = Pattern.compile("="); @@ -30,7 +30,7 @@ public class HTTPHeaderParser { * @param in is the stream * @throws IOException */ - public HTTPHeaderParser(BufferedReader in) throws IOException{ + public HttpHeaderParser(BufferedReader in) throws IOException{ url_attr = new HashMap(); headers = new HashMap(); cookies = new HashMap(); @@ -50,7 +50,7 @@ public class HTTPHeaderParser { * * @param in is the string */ - public HTTPHeaderParser(String in){ + public HttpHeaderParser(String in){ url_attr = new HashMap(); headers = new HashMap(); cookies = new HashMap(); @@ -92,7 +92,7 @@ public class HTTPHeaderParser { if(index > -1){ url = line.substring(0, index ); line = line.substring( index+1, line.length()); - parseUrlAttributes(line, url_attr); + parseURLParameters(line, url_attr); } else{ url = line; @@ -108,9 +108,9 @@ public class HTTPHeaderParser { * * @param attributes is the String containing all the attributes */ - public static HashMap parseUrlAttributes( String attributes ){ + public static HashMap parseURLParameters( String attributes ){ HashMap map = new HashMap(); - parseUrlAttributes(attributes, map); + parseURLParameters(attributes, map); return map; } @@ -121,7 +121,7 @@ public class HTTPHeaderParser { * @param attributes is the String containing all the attributes * @param map is the HashMap to put all the values into */ - public static void parseUrlAttributes(String attributes, HashMap map){ + public static void parseURLParameters(String attributes, HashMap map){ String[] tmp; // get the variables String[] data = andPattern.split( attributes ); diff --git a/src/zutil/net/http/HttpPrintStream.java b/src/zutil/net/http/HttpPrintStream.java index 4a2bd22..897606f 100644 --- a/src/zutil/net/http/HttpPrintStream.java +++ b/src/zutil/net/http/HttpPrintStream.java @@ -13,13 +13,13 @@ import java.util.HashMap; */ public class HttpPrintStream extends PrintStream{ // Defines the type of message - public enum HTTPMessageType{ + public enum HttpMessageType{ REQUEST, RESPONSE } // This defines the type of message that will be generated - private HTTPMessageType message_type; + private HttpMessageType message_type; // The status code of the message, ONLY for response private Integer res_status_code; // The request type of the message ONLY for request @@ -27,9 +27,9 @@ public class HttpPrintStream extends PrintStream{ // The requesting url ONLY for request private String req_url; // An Map of all the header values - private HashMap header; + private HashMap headers; // An Map of all the cookies - private HashMap cookie; + private HashMap cookies; // The buffered header private StringBuffer buffer; // If the header buffering is enabled @@ -42,7 +42,7 @@ public class HttpPrintStream extends PrintStream{ * @param out is the OutputStream to send the message */ public HttpPrintStream(OutputStream out) { - this( out, HTTPMessageType.RESPONSE ); + this( out, HttpMessageType.RESPONSE ); } /** * Creates an new instance of HttpPrintStream with @@ -51,13 +51,13 @@ public class HttpPrintStream extends PrintStream{ * @param out is the OutputStream to send the message * @param type is the type of message */ - public HttpPrintStream(OutputStream out, HTTPMessageType type) { + public HttpPrintStream(OutputStream out, HttpMessageType type) { super(out); this.message_type = type; res_status_code = 0; - header = new HashMap(); - cookie = new HashMap(); + headers = new HashMap(); + cookies = new HashMap(); buffer = new StringBuffer(); buffer_enabled = false; } @@ -84,9 +84,9 @@ public class HttpPrintStream extends PrintStream{ * @throws Exception Throws exception if the header has already been sent */ public void setCookie(String key, String value) throws RuntimeException{ - if(cookie == null) + if(cookies == null) throw new RuntimeException("Header already sent!!!"); - cookie.put(key, value); + cookies.put(key, value); } /** @@ -97,9 +97,9 @@ public class HttpPrintStream extends PrintStream{ * @throws Exception Throws exception if the header has already been sent */ public void setHeader(String key, String value) throws RuntimeException{ - if(header == null) + if(headers == null) throw new RuntimeException("Header already sent!!!"); - header.put(key, value); + headers.put(key, value); } /** @@ -111,7 +111,7 @@ public class HttpPrintStream extends PrintStream{ public void setStatusCode(int code) throws RuntimeException{ if( res_status_code == null ) throw new RuntimeException("Header already sent!!!"); - if( message_type != HTTPMessageType.RESPONSE ) + if( message_type != HttpMessageType.RESPONSE ) throw new RuntimeException("Status Code is only available in HTTP RESPONSE!!!"); res_status_code = code; } @@ -125,7 +125,7 @@ public class HttpPrintStream extends PrintStream{ public void setRequestType(String req_type) throws RuntimeException{ if( req_type == null ) throw new RuntimeException("Header already sent!!!"); - if( message_type != HTTPMessageType.REQUEST ) + if( message_type != HttpMessageType.REQUEST ) throw new RuntimeException("Request Message Type is only available in HTTP REQUEST!!!"); this.req_type = req_type; } @@ -138,11 +138,18 @@ public class HttpPrintStream extends PrintStream{ public void setRequestURL(String req_url) throws RuntimeException{ if( req_url == null ) throw new RuntimeException("Header already sent!!!"); - if( message_type != HTTPMessageType.REQUEST ) + if( message_type != HttpMessageType.REQUEST ) throw new RuntimeException("Request URL is only available in HTTP REQUEST!!!"); this.req_url = req_url; } + protected void setHeaders( HashMap map ){ + headers = map; + } + protected void setCookies( HashMap map ){ + cookies = map; + } + /** * Prints with a new line */ @@ -166,40 +173,40 @@ public class HttpPrintStream extends PrintStream{ } else{ if(res_status_code != null){ - if( message_type==HTTPMessageType.REQUEST ) - super.print(req_type+" "+req_url+" HTTP/1.1"); + if( message_type==HttpMessageType.REQUEST ) + super.print(req_type+" "+req_url+" HTTP/1.0"); else - super.print("HTTP/1.1 "+res_status_code+" "+getStatusString(res_status_code)); + super.print("HTTP/1.0 "+res_status_code+" "+getStatusString(res_status_code)); super.println(); res_status_code = null; req_type = null; req_url = null; } - if(header != null){ - for(String key : header.keySet()){ - super.print(key+": "+header.get(key)); + if(headers != null){ + for(String key : headers.keySet()){ + super.print(key+": "+headers.get(key)); super.println(); } - header = null; + headers = null; } - if(cookie != null){ - if( !cookie.isEmpty() ){ - if( message_type==HTTPMessageType.REQUEST ){ + if(cookies != null){ + if( !cookies.isEmpty() ){ + if( message_type==HttpMessageType.REQUEST ){ super.print("Cookie: "); - for(String key : cookie.keySet()){ - super.print(key+"="+cookie.get(key)+"; "); + for(String key : cookies.keySet()){ + super.print(key+"="+cookies.get(key)+"; "); } super.println(); } else{ - for(String key : cookie.keySet()){ - super.print("Set-Cookie: "+key+"="+cookie.get(key)+";"); + for(String key : cookies.keySet()){ + super.print("Set-Cookie: "+key+"="+cookies.get(key)+";"); super.println(); } } } super.println(); - cookie = null; + cookies = null; } super.print(s); } @@ -215,7 +222,7 @@ public class HttpPrintStream extends PrintStream{ buffer.delete(0, buffer.length()); buffer_enabled = true; } - else if(res_status_code != null || header != null || cookie != null){ + else if(res_status_code != null || headers != null || cookies != null){ printOrBuffer(""); } super.flush(); diff --git a/src/zutil/net/http/HttpServer.java b/src/zutil/net/http/HttpServer.java index 61d5c87..2333cd7 100644 --- a/src/zutil/net/http/HttpServer.java +++ b/src/zutil/net/http/HttpServer.java @@ -151,7 +151,7 @@ public class HttpServer extends ThreadedTCPNetworkServer{ try { logger.finer("Reciving Http Request!!!"); - HTTPHeaderParser parser = new HTTPHeaderParser(in); + HttpHeaderParser parser = new HttpHeaderParser(in); logger.finest(parser.toString()); client_info = parser.getHeaders(); request = parser.getURLAttributes(); @@ -173,7 +173,7 @@ public class HttpServer extends ThreadedTCPNetworkServer{ tmp = parser.getHeader("Content-Type"); if( tmp.contains("application/x-www-form-urlencoded") ){ // get the variables - HTTPHeaderParser.parseUrlAttributes( tmpb.toString(), request ); + HttpHeaderParser.parseURLParameters( tmpb.toString(), request ); } else if( tmp.contains("application/soap+xml" ) || tmp.contains("text/xml") || diff --git a/src/zutil/net/http/HttpURL.java b/src/zutil/net/http/HttpURL.java new file mode 100644 index 0000000..b9abfa8 --- /dev/null +++ b/src/zutil/net/http/HttpURL.java @@ -0,0 +1,139 @@ +package zutil.net.http; + +import java.net.URL; +import java.util.HashMap; + +/** + * Handles URLs in the HTTP protocol + * + * @author Ziver + */ +public class HttpURL { + public static final String PROTOCOL_SEPARATOR = "://"; + public static final String PORT_SEPARATOR = ":"; + public static final String PATH_SEPARATOR = "/"; + public static final String PARAMETER_SEPARATOR = "?"; + public static final String ANCHOR_SEPARATOR = "#"; + + private String protocol = ""; + private String host = "127.0.0.1"; + private int port = -1; + private String path; + private String anchor; + + private HashMap parameters = new HashMap(); + + + public HttpURL(){} + + public HttpURL( URL url ){ + this.setProtocol( url.getProtocol() ); + this.setHost( url.getHost() ); + this.setPort( url.getPort() ); + this.setPath( url.getPath() ); + } + + + public String getProtocol( ){ + return protocol; + } + public String getHost( ){ + return host; + } + public int getPort( ){ + return port; + } + public String getPath( ){ + return path; + } + public String getAnchor( ){ + return anchor; + } + + public void setProtocol( String prot ){ + this.protocol = prot; + } + public void setHost( String host ){ + this.host = host; + } + public void setPort( int port ){ + this.port = port; + } + public void setPath( String path ){ + if( path.length() >= 1 && !path.startsWith(PATH_SEPARATOR)) + path = PATH_SEPARATOR + path; + this.path = path; + } + public void setAnchor( String anch ){ + this.anchor = anch; + } + public void setParameter( String key, String value ){ + this.parameters.put(key, value); + } + + protected void setParameters( HashMap pars ){ + this.parameters = pars; + } + + /** + * Generates the parameter string in a URL. + * + * e.g. + * "key=value&key2=value&..." + */ + public String getParameterString(){ + StringBuilder param = new StringBuilder(); + for(String key : parameters.keySet()){ + param.append(key); + param.append('='); + param.append( parameters.get(key) ); + param.append('&'); + } + if( param.length() > 0 ) + param.deleteCharAt( param.length()-1 ); + return param.toString(); + } + + /** + * Generates a path that are used in the HTTP header + */ + public String getHttpURL(){ + StringBuilder url = new StringBuilder(); + url.append( path ); + if( !parameters.isEmpty() ) + url.append( PARAMETER_SEPARATOR ).append( getParameterString() ); + + return url.toString(); + } + + /** + * Generates a full URL + */ + public String getURL(){ + return toString(); + } + + /** + * Generates the whole URL + */ + public String toString(){ + StringBuilder url = new StringBuilder(); + url.append( protocol ); + url.append( PROTOCOL_SEPARATOR ); + url.append( host ); + if( port > 0 ) + url.append( PORT_SEPARATOR ).append( port ); + + if( path != null ) + url.append( path ); + else + url.append( PATH_SEPARATOR ); + + if( !parameters.isEmpty() ) + url.append( PARAMETER_SEPARATOR ).append( getParameterString() ); + if( anchor != null ) + url.append( ANCHOR_SEPARATOR ).append( anchor ); + + return url.toString(); + } +} diff --git a/src/zutil/net/http/multipart/MultipartParser.java b/src/zutil/net/http/multipart/MultipartParser.java index 01d28a9..8460093 100644 --- a/src/zutil/net/http/multipart/MultipartParser.java +++ b/src/zutil/net/http/multipart/MultipartParser.java @@ -13,7 +13,7 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; import zutil.ProgressListener; -import zutil.net.http.HTTPHeaderParser; +import zutil.net.http.HttpHeaderParser; /** * Parses a multipart/form-data http request, @@ -35,11 +35,11 @@ public class MultipartParser { private BufferedReader in; /** This is the listener that will listen on the progress */ - private ProgressListener listener; + private ProgressListener listener; - public MultipartParser(BufferedReader in, HTTPHeaderParser header){ + public MultipartParser(BufferedReader in, HttpHeaderParser header){ this.in = in; String cotype = header.getHeader("Content-type"); @@ -69,7 +69,7 @@ public class MultipartParser { /** * @param listener is the listener that will be called for progress */ - public void setListener(ProgressListener listener){ + public void setListener(ProgressListener listener){ this.listener = listener; } diff --git a/src/zutil/net/ssdp/SSDPClient.java b/src/zutil/net/ssdp/SSDPClient.java index e3f13f0..54a59d6 100644 --- a/src/zutil/net/ssdp/SSDPClient.java +++ b/src/zutil/net/ssdp/SSDPClient.java @@ -10,7 +10,7 @@ import java.util.logging.Logger; import zutil.io.StringOutputStream; import zutil.log.LogUtil; -import zutil.net.http.HTTPHeaderParser; +import zutil.net.http.HttpHeaderParser; import zutil.net.http.HttpPrintStream; import zutil.net.threaded.ThreadedUDPNetwork; import zutil.net.threaded.ThreadedUDPNetworkThread; @@ -75,7 +75,7 @@ public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetwork // Generate an SSDP discover message StringOutputStream msg = new StringOutputStream(); - HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HTTPMessageType.REQUEST ); + HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HttpMessageType.REQUEST ); http.setRequestType("M-SEARCH"); http.setRequestURL("*"); http.setHeader("Host", SSDPServer.SSDP_MULTICAST_ADDR+":"+SSDPServer.SSDP_PORT ); @@ -150,7 +150,7 @@ public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetwork * Location: http://localhost:80 */ public void receivedPacket(DatagramPacket packet, ThreadedUDPNetwork network) { - HTTPHeaderParser header = new HTTPHeaderParser( new String( packet.getData() ) ); + HttpHeaderParser header = new HttpHeaderParser( new String( packet.getData() ) ); logger.log(Level.FINEST, "*********** Recived\n"+header); String usn = header.getHeader("USN"); diff --git a/src/zutil/net/ssdp/SSDPServer.java b/src/zutil/net/ssdp/SSDPServer.java index dd72490..3d89192 100644 --- a/src/zutil/net/ssdp/SSDPServer.java +++ b/src/zutil/net/ssdp/SSDPServer.java @@ -12,7 +12,7 @@ import java.util.logging.Logger; import zutil.io.MultiPrintStream; import zutil.io.StringOutputStream; import zutil.log.LogUtil; -import zutil.net.http.HTTPHeaderParser; +import zutil.net.http.HttpHeaderParser; import zutil.net.http.HttpPrintStream; import zutil.net.threaded.ThreadedUDPNetworkThread; import zutil.net.threaded.ThreadedUDPNetwork; @@ -155,7 +155,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork try { String msg = new String( packet.getData() ); - HTTPHeaderParser header = new HTTPHeaderParser( msg ); + HttpHeaderParser header = new HttpHeaderParser( msg ); logger.log(Level.FINEST, "**** Received:\n"+header); // ******* Respond @@ -233,7 +233,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork try { // Generate the SSDP response StringOutputStream msg = new StringOutputStream(); - HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HTTPMessageType.REQUEST ); + HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HttpMessageType.REQUEST ); http.setRequestType("NOTIFY"); http.setRequestURL("*"); http.setHeader("Server", SERVER_INFO ); @@ -284,7 +284,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork try { // Generate the SSDP response StringOutputStream msg = new StringOutputStream(); - HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HTTPMessageType.REQUEST ); + HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HttpMessageType.REQUEST ); http.setRequestType("NOTIFY"); http.setRequestURL("*"); http.setHeader("Server", SERVER_INFO ); diff --git a/src/zutil/net/threaded/ThreadedTCPNetworkServer.java b/src/zutil/net/threaded/ThreadedTCPNetworkServer.java index 7e8dd63..3476097 100644 --- a/src/zutil/net/threaded/ThreadedTCPNetworkServer.java +++ b/src/zutil/net/threaded/ThreadedTCPNetworkServer.java @@ -8,19 +8,22 @@ import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.cert.CertificateException; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.net.ssl.SSLServerSocketFactory; -import zutil.io.MultiPrintStream; +import zutil.log.LogUtil; /** - * A simple web server that handles both cookies and - * sessions for all the clients + * A simple network server that handles TCP communication * * @author Ziver */ public abstract class ThreadedTCPNetworkServer extends Thread{ + public static final Logger logger = LogUtil.getLogger(); + public final int port; private File keyStore; private String keyStorePass; @@ -28,7 +31,7 @@ public abstract class ThreadedTCPNetworkServer extends Thread{ /** * Creates a new instance of the sever * - * @param port The port that the server should listen to + * @param port The port that the server should listen to */ public ThreadedTCPNetworkServer(int port){ this(port, null, null); @@ -36,9 +39,9 @@ public abstract class ThreadedTCPNetworkServer extends Thread{ /** * Creates a new instance of the sever * - * @param port The port that the server should listen to - * @param sslCert If this is not null then the server will use SSL connection with this keyStore file path - * @param sslCert If this is not null then the server will use a SSL connection with the given certificate + * @param port The port that the server should listen to + * @param sslCert If this is not null then the server will use SSL connection with this keyStore file path + * @param sslCert If this is not null then the server will use a SSL connection with the given certificate */ public ThreadedTCPNetworkServer(int port, File keyStore, String keyStorePass){ this.port = port; @@ -64,18 +67,18 @@ public abstract class ThreadedTCPNetworkServer extends Thread{ if( t!=null ) new Thread( t ).start(); else{ - MultiPrintStream.out.println("Unable to instantiate ThreadedTCPNetworkServerThread, closing connection!"); + logger.severe("Unable to instantiate ThreadedTCPNetworkServerThread, closing connection!"); s.close(); } } } catch(Exception e) { - e.printStackTrace( MultiPrintStream.out ); + logger.log(Level.SEVERE, null, e); } if( ss!=null ){ try{ ss.close(); - }catch(IOException e){ e.printStackTrace( MultiPrintStream.out ); } + }catch(IOException e){ logger.log(Level.SEVERE, null, e); } } } @@ -84,17 +87,16 @@ public abstract class ThreadedTCPNetworkServer extends Thread{ * that will handle the newly made connection, if an null value is returned * then the ThreadedTCPNetworkServer will close the new connection. * - * @param s is an new connection to an host - * @return a new instance of an thread or null + * @param s is an new connection to an host + * @return a new instance of an thread or null */ protected abstract ThreadedTCPNetworkServerThread getThreadInstance( Socket s ); /** * Initiates a SSLServerSocket * - * @param port The port to listen to - * @return The SSLServerSocket - * @throws IOException + * @param port The port to listen to + * @return The SSLServerSocket */ private ServerSocket initSSL(int port) throws IOException{ SSLServerSocketFactory sslserversocketfactory = @@ -106,7 +108,7 @@ public abstract class ThreadedTCPNetworkServer extends Thread{ /** * Registers the given cert file to the KeyStore * - * @param certFile The cert file + * @param certFile The cert file */ protected void registerCertificate(File keyStore, String keyStorePass) throws CertificateException, IOException, KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException{ System.setProperty("javax.net.ssl.keyStore", keyStore.getAbsolutePath()); diff --git a/src/zutil/net/threaded/ThreadedTCPNetworkServerThread.java b/src/zutil/net/threaded/ThreadedTCPNetworkServerThread.java index 1888c61..c322fb8 100644 --- a/src/zutil/net/threaded/ThreadedTCPNetworkServerThread.java +++ b/src/zutil/net/threaded/ThreadedTCPNetworkServerThread.java @@ -1,7 +1,7 @@ package zutil.net.threaded; /** - * The class that will handle the TCP connection will incclude + * The class that will handle the a TCP connection will include * this interface * * @author Ziver diff --git a/src/zutil/net/threaded/ThreadedUDPNetwork.java b/src/zutil/net/threaded/ThreadedUDPNetwork.java index 922e035..aee0d95 100644 --- a/src/zutil/net/threaded/ThreadedUDPNetwork.java +++ b/src/zutil/net/threaded/ThreadedUDPNetwork.java @@ -10,8 +10,7 @@ import java.net.SocketException; /** - * A simple web server that handles both cookies and - * sessions for all the clients + * * A simple network server that handles UDP communication * * @author Ziver */ diff --git a/src/zutil/net/threaded/ThreadedUDPNetworkThread.java b/src/zutil/net/threaded/ThreadedUDPNetworkThread.java index 496a1f1..bd5586c 100644 --- a/src/zutil/net/threaded/ThreadedUDPNetworkThread.java +++ b/src/zutil/net/threaded/ThreadedUDPNetworkThread.java @@ -4,7 +4,7 @@ import java.net.DatagramPacket; /** * This interface is for processing received packets - * from the TNetworkUDPServer + * from the ThreadedUDPNetworkServer * * @author Ziver * @@ -14,8 +14,8 @@ public interface ThreadedUDPNetworkThread extends Runnable{ /** * Packet will be processed in this method * - * @param packet is the received packet - * @param network is the network class that received the packet + * @param packet is the received packet + * @param network is the network class that received the packet */ public void receivedPacket(DatagramPacket packet, ThreadedUDPNetwork network); } diff --git a/src/zutil/net/torrent/Torrent.java b/src/zutil/net/torrent/Torrent.java deleted file mode 100644 index f0856e3..0000000 --- a/src/zutil/net/torrent/Torrent.java +++ /dev/null @@ -1,102 +0,0 @@ -package zutil.net.torrent; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; - -import zutil.io.file.FileUtil; - -public class Torrent { - // Name of the torrent - private String name; - // Comment - private String comment; - // Creation date as unix timestamp - private long date; - // Files in the torrent - private ArrayList file_list; - // Size of of the full torrent (after download) - private long size; - // Signature of the software which created the torrent - private String created_by; - // tracker (the tracker the torrent has been received from) - private String main_tracker; - // List of known trackers for the torrent - private ArrayList tracker_list; - private HashMap info_hash; - // Torrent is marked as 'private'. - private boolean is_private; - - public Torrent(File torrent) throws IOException{ - this(FileUtil.getFileContent( torrent )); - } - - public Torrent(String data){ - reset(); - decode(data); - } - - private void reset(){ - // Reset - name = ""; - comment = ""; - date = 0; - file_list = new ArrayList(); - size = 0; - created_by = ""; - main_tracker = ""; - tracker_list = new ArrayList(); - info_hash = new HashMap(); - is_private = false; - } - - @SuppressWarnings("unchecked") - private void decode(String data){ - HashMap dataMap = (HashMap)TorrentParser.decode(data); - - name = (String)dataMap.get("name"); - comment = (String)dataMap.get("comment"); - date = (Long)dataMap.get("creation date"); - file_list = new ArrayList(); - size = (Long)dataMap.get("length"); - created_by = (String)dataMap.get("created by"); - main_tracker = (String)dataMap.get("announce"); - tracker_list = (ArrayList)dataMap.get("announce-list"); - info_hash = (HashMap)dataMap.get("info"); - is_private = (((Integer)dataMap.get("private")) != 0); - } - - // ************** GETTER ************** - public String getName(){ - return name; - } - public String getComments(){ - return comment; - } - public long getDate(){ - return date; - } - public ArrayList getFileList(){ - return file_list; - } - public long getSize(){ - return size; - } - public String getAuthor(){ - return created_by; - } - public String getMainTracker(){ - return main_tracker; - } - public ArrayList getTrackerList(){ - return tracker_list; - } - public HashMap getInfoHash(){ - return info_hash; - } - public boolean isPrivate(){ - return is_private; - } - // ************************************ -} diff --git a/src/zutil/net/torrent/TorrentFile.java b/src/zutil/net/torrent/TorrentFile.java new file mode 100644 index 0000000..cda382a --- /dev/null +++ b/src/zutil/net/torrent/TorrentFile.java @@ -0,0 +1,32 @@ +package zutil.net.torrent; + +import zutil.Dumpable; + +/** + * This class represents a File for download + * + * @author Ziver + */ +public class TorrentFile implements Dumpable{ + private String filename; + private long length; + + public TorrentFile(String filename, long length){ + this.filename = filename; + this.length = length; + } + + + public String getFilename() { + return filename; + } + public void setFilename(String filename) { + this.filename = filename; + } + public long getLength() { + return length; + } + public void setLength(long length) { + this.length = length; + } +} \ No newline at end of file diff --git a/src/zutil/net/torrent/TorrentMetainfo.java b/src/zutil/net/torrent/TorrentMetainfo.java new file mode 100644 index 0000000..77d8296 --- /dev/null +++ b/src/zutil/net/torrent/TorrentMetainfo.java @@ -0,0 +1,165 @@ +package zutil.net.torrent; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; + +import zutil.io.MultiPrintStream; +import zutil.io.file.FileUtil; +import zutil.parser.BEncodedParser; +import zutil.parser.DataNode; + +public class TorrentMetainfo { + /** Comment (optional) **/ + private String comment; + /** Signature of the software which created the torrent (optional) **/ + private String created_by; + /** Creation date as Unix timestamp (optional) **/ + private long creation_date; + /** The main Tracker (the tracker the torrent has been received from) **/ + private String announce; + /** List of known trackers for the torrent (optional) **/ + private ArrayList announce_list; + /** The encoding of the Strings (optional) **/ + private String encoding; + + /** Size of of the full torrent (after download) **/ + private long size; + /** Number of bytes in each piece **/ + private long piece_length; + /** String consisting of the concatenation of all 20-byte SHA1 hash values, one per piece **/ + private ArrayList piece_hashes; + /** Torrent is private. No other trackers allowed other then those listed. (optional) **/ + private boolean is_private; + + // Files in the torrent + private ArrayList file_list; + + + + public TorrentMetainfo(File torrent) throws IOException{ + this(FileUtil.getFileContent( torrent )); + } + + public TorrentMetainfo(String data){ + decode(data); + } + + + private void decode(String data){ + DataNode metainfo = BEncodedParser.parse(data); + + // Main values + announce = metainfo.getString("announce"); + created_by = metainfo.getString("created by"); + comment = metainfo.getString("comment"); + encoding = metainfo.getString("encoding"); + if( metainfo.get("creation date") != null ) + creation_date = metainfo.getLong("creation date"); + if( metainfo.get("announce-list") != null ){ + DataNode tmp = metainfo.get("announce-list"); + announce_list = new ArrayList(); + for( DataNode tracker : tmp ) + announce_list.add( tracker.getString() ); + } + + // info data + DataNode info = metainfo.get("info"); + String name = info.getString("name"); + piece_length = info.getLong("piece length"); + if( info.get("private") != null ) + is_private = (info.getInt("private") != 0); + // Split the hashes + String hashes = info.getString("pieces"); + piece_hashes = new ArrayList(); + for(int i=0; i(); + // Single-file torrent + if( info.get("files") == null ){ + Long length = info.getLong("length"); + file_list.add( new TorrentFile(name, length) ); + } + // Multi-file torrent + else{ + DataNode files = info.get("files"); + for( DataNode file : files ){ + String filename = ""; + DataNode tmp = file.get("path"); + // File in subdir + if( tmp.isList() ){ + Iterator it = tmp.iterator(); + while( it.hasNext() ){ + filename += it.next().getString(); + if(it.hasNext()) filename += File.separator; + } + } + // File in root dir + else + filename = tmp.getString(); + Long length = file.getLong("length"); + filename = name + File.separator + filename; + file_list.add( new TorrentFile(filename, length) ); + } + } + } + + + + public String getComment() { + return comment; + } + public String getCreated_by() { + return created_by; + } + public long getCreation_date() { + return creation_date; + } + public String getAnnounce() { + return announce; + } + public ArrayList getAnnounce_list() { + return announce_list; + } + public String getEncoding() { + return encoding; + } + public long getSize() { + return size; + } + public long getPiece_length() { + return piece_length; + } + public ArrayList getPiece_hashes() { + return piece_hashes; + } + public boolean isIs_private() { + return is_private; + } + public ArrayList getFile_list() { + return file_list; + } + + /** + * Example use + */ + public static void main(String[] args){ + try { + TorrentMetainfo tmp = new TorrentMetainfo(FileUtil.find("C:\\Users\\Ziver\\Desktop\\test.torrent")); + MultiPrintStream.out.dump(tmp); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/zutil/net/torrent/TorrentTracker.java b/src/zutil/net/torrent/TorrentTracker.java new file mode 100644 index 0000000..f4dd8d5 --- /dev/null +++ b/src/zutil/net/torrent/TorrentTracker.java @@ -0,0 +1,26 @@ +package zutil.net.torrent; + +import java.io.IOException; +import java.net.URL; + +import zutil.net.http.HttpClient; +import zutil.net.http.HttpHeaderParser; + +/** + * This tracker represents a tracker client + * that connects to a tracker + * + * @author Ziver + */ +public class TorrentTracker { + /** The address to the tracker **/ + private URL trackerURL; + + + + private void update() throws IOException { + HttpClient request = HttpClient.GET(); + request.setURL( trackerURL ); + HttpHeaderParser response = request.send(); + } +} diff --git a/src/zutil/net/update/FileInfo.java b/src/zutil/net/update/FileInfo.java new file mode 100644 index 0000000..2d0e3b1 --- /dev/null +++ b/src/zutil/net/update/FileInfo.java @@ -0,0 +1,57 @@ +package zutil.net.update; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; + +import zutil.Hasher; +import zutil.io.file.FileUtil; + +/** + * This class is used to store the files + * and there hashes + * + * @author Ziver + */ +public class FileInfo implements Serializable{ + private static final long serialVersionUID = 1L; + + private transient File file; + private String path; + private String hash; + private long size; + + public FileInfo(String root, File file) throws IOException{ + path = FileUtil.relativePath(file, root); + hash = Hasher.MD5(file); + size = file.length(); + this.file = file; + } + + + public String getPath() { + return path; + } + public String getHash() { + return hash; + } + public long getSize() { + return size; + } + public File getFile(){ + return file; + } + + + public boolean equals(Object comp){ + if(comp instanceof FileInfo){ + FileInfo tmp = (FileInfo)comp; + return path.equals(tmp.path) && hash.equals(tmp.hash); + } + return false; + } + + public String toString(){ + return path; + } +} \ No newline at end of file diff --git a/src/zutil/net/update/FileListMessage.java b/src/zutil/net/update/FileListMessage.java new file mode 100644 index 0000000..3dc8d2e --- /dev/null +++ b/src/zutil/net/update/FileListMessage.java @@ -0,0 +1,82 @@ +package zutil.net.update; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import zutil.io.file.FileUtil; + +/** + * This class is used to store the files + * and there hashes + * + * @author Ziver + */ +class FileListMessage implements Serializable{ + private static final long serialVersionUID = 1L; + + private ArrayList fileList; + private long totalSize; + + private FileListMessage(){} + + /** + * Returns a ArrayList of FileInfo object for all the files in the specified folder + * + * @param path is the path to scan + **/ + public FileListMessage(String path) throws IOException{ + fileList = new ArrayList(); + + List files = FileUtil.search(FileUtil.find(path)); + long totalSize = 0; + for(File file : files){ + FileInfo fileInfo = new FileInfo(path, file); + fileList.add( fileInfo ); + totalSize += fileInfo.getSize(); + } + this.totalSize = totalSize; + } + + + public long getTotalSize() { + return totalSize; + } + + public ArrayList getFileList(){ + return fileList; + } + + /** + * Compares the files and returns the files that differ from this file list + * + * @param comp is the file list to compare with + * @return + */ + public FileListMessage getDiff( FileListMessage comp){ + FileListMessage diff = new FileListMessage(); + + long diffSize = 0; + diff.fileList = new ArrayList(); + for(FileInfo file : this.fileList){ + if( !comp.fileList.contains( file)){ + diff.fileList.add( file ); + diffSize += file.getSize(); + } + } + diff.totalSize = diffSize; + + return diff; + } + + + public boolean equals(Object comp){ + if(comp instanceof FileListMessage){ + FileListMessage tmp = (FileListMessage)comp; + return fileList.equals(tmp.fileList) && totalSize == tmp.totalSize; + } + return false; + } +} \ No newline at end of file diff --git a/src/zutil/net/update/UpdateClient.java b/src/zutil/net/update/UpdateClient.java new file mode 100644 index 0000000..854b5d0 --- /dev/null +++ b/src/zutil/net/update/UpdateClient.java @@ -0,0 +1,154 @@ +package zutil.net.update; + +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.logging.Level; +import java.util.logging.Logger; + +import zutil.ProgressListener; +import zutil.io.file.FileUtil; +import zutil.log.LogUtil; + +/** + * This class connects to a update server and updates a path + * with the servers + * + * @author Ziver + * + */ +public class UpdateClient{ + public static final Logger logger = LogUtil.getLogger(); + + private String path; + private Socket socket; + private FileListMessage fileList; + + private long speed; + private long totalReceived; + private long expectedSize; + private ProgressListener progress; + + /** + * 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{ + fileList = new FileListMessage(path); + socket = new Socket(address, port); + this.path = path; + } + + public void setProgressListener(ProgressListener p){ + progress = p; + } + + /** + * Updates the files + */ + public void update() throws IOException{ + try{ + ObjectOutputStream out = new ObjectOutputStream( socket.getOutputStream()); + ObjectInputStream in = new ObjectInputStream ( socket.getInputStream() ); + + // send client file list + out.writeObject( fileList ); + out.flush(); + // get update list + FileListMessage updateList = (FileListMessage) in.readObject(); + expectedSize = updateList.getTotalSize(); + + // receive file updates + File tmpPath = FileUtil.find(path); + totalReceived = 0; + for(FileInfo info : updateList.getFileList() ){ + // reading new file data + File file = new File( tmpPath, info.getPath() ); + logger.fine("Updating file: "+file); + if( !file.getParentFile().exists() && !file.getParentFile().mkdirs() ){ + throw new IOException("Unable to create folder: "+file.getParentFile()); + } + File tmpFile = File.createTempFile(file.getName(), ".tmp", tmpPath); + tmpFile.deleteOnExit(); + + FileOutputStream fileOut = new FileOutputStream(tmpFile); + byte[] buffer = new byte[socket.getReceiveBufferSize()]; + + long bytesReceived = 0; + int byteRead = 0; + long time = System.currentTimeMillis(); + long timeTotalRecived = 0; + + while( bytesReceived < info.getSize() ) { + byteRead = in.read(buffer); + fileOut.write(buffer, 0, byteRead); + bytesReceived += byteRead; + + if(time+1000 < System.currentTimeMillis()){ + time = System.currentTimeMillis(); + speed = (int)(totalReceived - timeTotalRecived); + timeTotalRecived = totalReceived; + } + + totalReceived += byteRead; + if(progress != null) progress.progressUpdate(this, info, ((double)totalReceived/updateList.getTotalSize())*100); + } + fileOut.close(); + speed = 0; + + // delete old file and replace whit new + file.delete(); + if( !tmpFile.renameTo(file) ){ + throw new IOException("Can not move downloaded file: "+tmpFile.getAbsolutePath()+" to: "+file); + } + } + }catch(ClassNotFoundException e){ + logger.log(Level.SEVERE, null, e); + } + + logger.info("Update done."); + } + + /** + * Returns the speed of the transfer + * + * @return The speed in bytes/s + */ + public long getSpeed(){ + return speed; + } + + /** + * Returns the total amount of data received + * + * @return a long that represents bytes + */ + public long getTotalReceived(){ + return totalReceived; + } + + /** + * Returns the expected total amount of data that will be received + * + * @return a long that represents bytes + */ + public long getTotalSize(){ + return expectedSize; + } + + /** + * Closes the connection + * + * @throws IOException + */ + public void close() throws IOException{ + socket.close(); + } +} diff --git a/src/zutil/net/update/UpdateConfigMessage.java b/src/zutil/net/update/UpdateConfigMessage.java new file mode 100644 index 0000000..649f3ce --- /dev/null +++ b/src/zutil/net/update/UpdateConfigMessage.java @@ -0,0 +1,15 @@ +package zutil.net.update; + +import java.io.Serializable; + +/** + * A class that contains configuration information + * + * @author Ziver + */ +class UpdateConfigMessage implements Serializable{ + private static final long serialVersionUID = 1L; + + protected String hashAlgorithm; + protected boolean compression; +} \ No newline at end of file diff --git a/src/zutil/net/update/UpdateServer.java b/src/zutil/net/update/UpdateServer.java new file mode 100644 index 0000000..a9d4413 --- /dev/null +++ b/src/zutil/net/update/UpdateServer.java @@ -0,0 +1,101 @@ +package zutil.net.update; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.Socket; +import java.util.logging.Level; +import java.util.logging.Logger; + +import zutil.io.MultiPrintStream; +import zutil.log.LogUtil; +import zutil.net.threaded.ThreadedTCPNetworkServer; +import zutil.net.threaded.ThreadedTCPNetworkServerThread; + +public class UpdateServer extends ThreadedTCPNetworkServer{ + public static final Logger logger = LogUtil.getLogger(); + + private FileListMessage fileList; + + /** + * Creates a UpdateServer Thread + * + * @param path The path to sync the clients with + */ + public UpdateServer(int port, String path) throws Exception{ + super(port); + fileList = new FileListMessage(path); + MultiPrintStream.out.dump(fileList); + + this.start(); + logger.info("Update Server Ready."); + } + + @Override + protected ThreadedTCPNetworkServerThread getThreadInstance(Socket s) { + return new UpdateServerThread(s); + } + + /** + * Handles all the connecting clients + * + * @author Ziver + */ + class UpdateServerThread implements ThreadedTCPNetworkServerThread{ + private ObjectOutputStream out; + private ObjectInputStream in; + private Socket socket; + + /** + * Creates a UpdateServerThread + * + * @param client is the socket to the client + */ + public UpdateServerThread(Socket c){ + socket = c; + try { + out = new ObjectOutputStream( socket.getOutputStream()); + in = new ObjectInputStream ( socket.getInputStream() ); + } catch (IOException e) { + logger.log(Level.SEVERE, null, e); + } + + } + + public void run(){ + try { + logger.info("Client["+socket.getInetAddress()+"] connectiong..."); + // receive the clients file list + FileListMessage clientFileList = (FileListMessage)in.readObject(); + MultiPrintStream.out.dump(clientFileList); + FileListMessage diff = fileList.getDiff( clientFileList ); + MultiPrintStream.out.dump(diff); + out.writeObject( diff ); + + logger.info("Updating client["+socket.getInetAddress()+"]..."); + for(FileInfo info : diff.getFileList()){ + // send file data + FileInputStream input = new FileInputStream( info.getFile() ); + byte[] nextBytes = new byte[ socket.getSendBufferSize() ]; + int bytesRead = 0; + while((bytesRead = input.read(nextBytes)) > 0){ + out.write(nextBytes,0,bytesRead); + } + out.flush(); + input.close(); + } + + out.flush(); + socket.close(); + logger.info("Client["+socket.getInetAddress()+"] update done."); + } catch (Exception e) { + logger.log(Level.SEVERE, "Update error Client["+socket.getInetAddress()+"].", e); + } finally { + logger.info("Client["+socket.getInetAddress()+"] disconnected."); + } + } + } +} + + diff --git a/src/zutil/net/update/Zupdater.java b/src/zutil/net/update/Zupdater.java new file mode 100644 index 0000000..4ab765c --- /dev/null +++ b/src/zutil/net/update/Zupdater.java @@ -0,0 +1,131 @@ +package zutil.net.update; + +import java.awt.EventQueue; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; +import javax.swing.GroupLayout; +import javax.swing.GroupLayout.Alignment; +import javax.swing.JLabel; +import javax.swing.JProgressBar; +import javax.swing.LayoutStyle.ComponentPlacement; +import javax.swing.SwingConstants; +import javax.swing.JSeparator; +import javax.swing.JButton; + +import zutil.ProgressListener; +import zutil.StringUtil; +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; +import java.awt.Dialog.ModalExclusionType; + + +public class Zupdater extends JFrame implements ProgressListener{ + private static final long serialVersionUID = 1L; + + private JPanel contentPane; + private JLabel lblSpeed; + private JLabel lblFile; + private JProgressBar progressBar; + + /** + * Launch the application. + */ + public static void main(String[] args) { + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + Zupdater frame = new Zupdater(); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + + public void progressUpdate(UpdateClient source, FileInfo info, double percent) { + lblFile.setText( info.getPath() ); + progressBar.setValue( (int)percent ); + progressBar.setString( StringUtil.formatBytesToString( source.getTotalReceived() ) + + " / "+StringUtil.formatBytesToString( source.getTotalSize() )); + + lblSpeed.setText( StringUtil.formatBytesToString(((UpdateClient)source).getSpeed())+"/s" ); + } + + + /** + * Create the frame. + */ + public Zupdater() { + setModalExclusionType(ModalExclusionType.APPLICATION_EXCLUDE); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setAlwaysOnTop(true); + setResizable(false); + setTitle("Updating..."); + setBounds(100, 100, 537, 124); + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + + progressBar = new JProgressBar(); + progressBar.setString("2.5 MB / 5 MB"); + progressBar.setValue(50); + progressBar.setStringPainted(true); + progressBar.setToolTipText(""); + + lblFile = new JLabel("apa.zip"); + + lblSpeed = new JLabel("200 kb/s"); + lblSpeed.setHorizontalAlignment(SwingConstants.RIGHT); + + JSeparator separator = new JSeparator(); + + JButton btnCancel = new JButton("Cancel"); + btnCancel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.exit(0); + } + }); + + JLabel lblFile_1 = new JLabel("File:"); + GroupLayout gl_contentPane = new GroupLayout(contentPane); + gl_contentPane.setHorizontalGroup( + gl_contentPane.createParallelGroup(Alignment.TRAILING) + .addGroup(gl_contentPane.createSequentialGroup() + .addGap(10) + .addComponent(progressBar, GroupLayout.DEFAULT_SIZE, 501, Short.MAX_VALUE) + .addGap(10)) + .addComponent(separator, GroupLayout.DEFAULT_SIZE, 521, Short.MAX_VALUE) + .addGroup(gl_contentPane.createSequentialGroup() + .addContainerGap() + .addComponent(lblFile_1) + .addPreferredGap(ComponentPlacement.RELATED) + .addComponent(lblFile, GroupLayout.PREFERRED_SIZE, 331, GroupLayout.PREFERRED_SIZE) + .addGap(60) + .addComponent(lblSpeed, GroupLayout.DEFAULT_SIZE, 84, Short.MAX_VALUE) + .addContainerGap()) + .addGroup(gl_contentPane.createSequentialGroup() + .addContainerGap() + .addComponent(btnCancel)) + ); + gl_contentPane.setVerticalGroup( + gl_contentPane.createParallelGroup(Alignment.LEADING) + .addGroup(gl_contentPane.createSequentialGroup() + .addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE) + .addComponent(lblSpeed) + .addComponent(lblFile) + .addComponent(lblFile_1)) + .addPreferredGap(ComponentPlacement.RELATED) + .addComponent(progressBar, GroupLayout.PREFERRED_SIZE, 25, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(ComponentPlacement.RELATED) + .addComponent(separator, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(ComponentPlacement.RELATED) + .addComponent(btnCancel) + .addContainerGap(14, Short.MAX_VALUE)) + ); + contentPane.setLayout(gl_contentPane); + } +} diff --git a/src/zutil/net/torrent/TorrentParser.java b/src/zutil/parser/BEncodedParser.java similarity index 68% rename from src/zutil/net/torrent/TorrentParser.java rename to src/zutil/parser/BEncodedParser.java index d566e3b..0c2bf2f 100644 --- a/src/zutil/net/torrent/TorrentParser.java +++ b/src/zutil/parser/BEncodedParser.java @@ -1,34 +1,13 @@ -package zutil.net.torrent; +package zutil.parser; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.HashMap; -import java.util.LinkedList; - -import zutil.io.MultiPrintStream; -import zutil.io.file.FileUtil; +import zutil.parser.DataNode.DataType; /** * http://wiki.theory.org/BitTorrentSpecification * @author Ziver * */ -public class TorrentParser { - /** - * Example use - */ - public static void main(String[] args){ - try { - String tmp = FileUtil.getFileContent(FileUtil.find("C:\\Users\\Ziver\\Desktop\\test.torrent")); - MultiPrintStream.out.dump(TorrentParser.decode(tmp)); - - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - +public class BEncodedParser { /** * Returns the representation of the data in the BEncoded string @@ -36,7 +15,7 @@ public class TorrentParser { * @param data The data to be decoded * @return */ - public static Object decode(String data){ + public static DataNode parse(String data){ return decode_BEncoded(new StringBuffer(data)); } @@ -47,7 +26,7 @@ public class TorrentParser { * @param index The index in data to start from * @return */ - private static Object decode_BEncoded(StringBuffer data){ + private static DataNode decode_BEncoded(StringBuffer data){ String tmp; char c = ' '; @@ -63,7 +42,7 @@ public class TorrentParser { tmp = data.substring(0, data.indexOf("e")); data.delete(0, tmp.length() + 1); //System.out.println(tmp); - return new Long(tmp); + return new DataNode( new Long(tmp)); /** * Lists are prefixed with a l and terminated by an e. The list * should contain a series of bEncoded elements. For example, the @@ -74,15 +53,15 @@ public class TorrentParser { case 'l': //System.out.println("Found List at "+index); data.deleteCharAt(0); - LinkedList list = new LinkedList(); + DataNode list = new DataNode( DataType.List ); c = data.charAt(0); while(c != 'e'){ - list.add(decode_BEncoded(data)); + list.add( decode_BEncoded(data) ); c = data.charAt(0); } data.deleteCharAt(0); //MultiPrintStream.out.dump(list); - if(list.size() == 1) return list.poll(); + if(list.size() == 1) return list.get(0); else return list; /** * Dictionaries are prefixed with a d and terminated by an e. They @@ -93,11 +72,11 @@ public class TorrentParser { case 'd': //System.out.println("Found Dictionary at "+index); data.deleteCharAt(0); - HashMap map = new HashMap(); + DataNode map = new DataNode( DataType.Map ); c = data.charAt(0); while(c != 'e'){ - Object tmp2 = decode_BEncoded(data); - map.put(tmp2, decode_BEncoded(data)); + DataNode tmp2 = decode_BEncoded(data); + map.set(tmp2.getString(), decode_BEncoded(data)); c = data.charAt(0); } data.deleteCharAt(0); @@ -116,7 +95,7 @@ public class TorrentParser { String ret = data.substring(0, length); data.delete(0, length); //System.out.println(data.substring(i, i+length)); - return ret; + return new DataNode( ret ); } } } diff --git a/src/zutil/parser/json/JSONNode.java b/src/zutil/parser/DataNode.java similarity index 53% rename from src/zutil/parser/json/JSONNode.java rename to src/zutil/parser/DataNode.java index efa3e39..9073dd2 100644 --- a/src/zutil/parser/json/JSONNode.java +++ b/src/zutil/parser/DataNode.java @@ -1,4 +1,4 @@ -package zutil.parser.json; +package zutil.parser; import java.util.HashMap; import java.util.Iterator; @@ -8,66 +8,65 @@ import java.util.Map; /** - * This is an node in an JSON tree, - * it may contain a Map, list or value + * This is a data node used in JSON and BEncoding and other types * * @author Ziver */ -public class JSONNode implements Iterable{ - public enum JSONType{ +public class DataNode implements Iterable{ + public enum DataType{ Map, List, String, Number, Boolean } - private Map map = null; - private List list = null; + private Map map = null; + private List list = null; private String value = null; - private JSONType type; + private DataType type; /** * Creates an instance with an Boolean value */ - public JSONNode(boolean value){ - this.type = JSONType.Boolean; + public DataNode(boolean value){ + this.type = DataType.Boolean; this.value = ""+value; } /** * Creates an instance with an int value */ - public JSONNode(int value){ - this.type = JSONType.Number; + public DataNode(int value){ + this.type = DataType.Number; this.value = ""+value; } /** * Creates an instance with an double value */ - public JSONNode(double value){ - this.type = JSONType.Number; + public DataNode(double value){ + this.type = DataType.Number; this.value = ""+value; } /** * Creates an instance with an long value */ - public JSONNode(long value){ - this.type = JSONType.Number; + public DataNode(long value){ + this.type = DataType.Number; this.value = ""+value; } /** * Creates an instance with an String value */ - public JSONNode(String value){ - this.type = JSONType.String; + public DataNode(String value){ + this.type = DataType.String; this.value = value; } /** * Creates an instance with a specific type */ - public JSONNode(JSONType type){ + public DataNode(DataType type){ this.type = type; switch(type){ case Map: - map = new HashMap(); break; + map = new HashMap(); break; case List: - list = new LinkedList(); break; + list = new LinkedList(); break; } } @@ -75,7 +74,7 @@ public class JSONNode implements Iterable{ * @param index is the index of the List or Map * @return an JSONNode that contains the next level of the List or Map */ - public JSONNode get(int index){ + public DataNode get(int index){ if(map != null) return map.get(""+index); else if(list != null) @@ -86,7 +85,7 @@ public class JSONNode implements Iterable{ * @param index is the key in the Map * @return an JSONNode that contains the next level of the Map */ - public JSONNode get(String index){ + public DataNode get(String index){ if(map != null) return map.get(index); return null; @@ -95,7 +94,7 @@ public class JSONNode implements Iterable{ /** * @return a iterator for the Map or List or null if the node contains a value */ - public Iterator iterator(){ + public Iterator iterator(){ if(map != null) return map.values().iterator(); else if(list != null) @@ -125,51 +124,51 @@ public class JSONNode implements Iterable{ /** * Adds a node to the List */ - public void add(JSONNode node){ + public void add(DataNode node){ list.add(node); } public void add(boolean value){ - list.add(new JSONNode( value )); + list.add(new DataNode( value )); } public void add(int value){ - list.add(new JSONNode( value )); + list.add(new DataNode( value )); } public void add(double value){ - list.add(new JSONNode( value )); + list.add(new DataNode( value )); } public void add(long value){ - list.add(new JSONNode( value )); + list.add(new DataNode( value )); } public void add(String value){ - list.add(new JSONNode( value )); + list.add(new DataNode( value )); } /** * Adds a node to the Map */ - public void add(String key, JSONNode node){ + public void set(String key, DataNode node){ map.put(key, node); } - public void add(String key, boolean value){ - map.put(key, new JSONNode(value)); + public void set(String key, boolean value){ + map.put(key, new DataNode(value)); } - public void add(String key, int value){ - map.put(key, new JSONNode(value)); + public void set(String key, int value){ + map.put(key, new DataNode(value)); } - public void add(String key, double value){ - map.put(key, new JSONNode(value)); + public void set(String key, double value){ + map.put(key, new DataNode(value)); } - public void add(String key, long value){ - map.put(key, new JSONNode(value)); + public void set(String key, long value){ + map.put(key, new DataNode(value)); } - public void add(String key, String value){ - map.put(key, new JSONNode(value)); + public void set(String key, String value){ + map.put(key, new DataNode(value)); } /** * Sets the value of the node, but only if it is setup as an JSONType.Value */ public void set(int value){ if( !this.isValue() ) throw new NullPointerException("The node is not setup as a value"); - type = JSONType.Number; + type = DataType.Number; this.value = ""+value; } /** @@ -177,7 +176,7 @@ public class JSONNode implements Iterable{ */ public void set(double value){ if( !this.isValue() ) throw new NullPointerException("The node is not setup as a value"); - type = JSONType.Number; + type = DataType.Number; this.value = ""+value; } /** @@ -185,7 +184,7 @@ public class JSONNode implements Iterable{ */ public void set(boolean value){ if( !this.isValue() ) throw new NullPointerException("The node is not setup as a value"); - type = JSONType.Boolean; + type = DataType.Boolean; this.value = ""+value; } /** @@ -193,7 +192,7 @@ public class JSONNode implements Iterable{ */ public void set(long value){ if( !this.isValue() ) throw new NullPointerException("The node is not setup as a value"); - type = JSONType.Number; + type = DataType.Number; this.value = ""+value; } /** @@ -201,7 +200,7 @@ public class JSONNode implements Iterable{ */ public void set(String value){ if( !this.isValue() ) throw new NullPointerException("The node is not setup as a value"); - type = JSONType.String; + type = DataType.String; this.value = value; } @@ -210,27 +209,70 @@ public class JSONNode implements Iterable{ * @return if this node contains an Map */ public boolean isMap(){ - return type == JSONType.Map; + return type == DataType.Map; } /** * @return if this node contains an List */ public boolean isList(){ - return type == JSONType.List; + return type == DataType.List; } /** * @return if this node contains an value */ public boolean isValue(){ - return type != JSONType.Map && type != JSONType.List; + return type != DataType.Map && type != DataType.List; } /** * @return the type of the node */ - public JSONType getType(){ + public DataType getType(){ return type; } + + /** + * @return the String value in this map + */ + public String getString(String key){ + if( !this.isMap() ) throw new NullPointerException("The node is not setup as a map"); + if( !this.map.containsKey(key) ) + return null; + return this.get(key).getString(); + } + /** + * @return the boolean value in this map + */ + public boolean getBoolean(String key){ + if( !this.isMap() ) throw new NullPointerException("The node is not setup as a map"); + if( !this.map.containsKey(key) ) throw new NullPointerException("No such key in map"); + return this.get(key).getBoolean(); + } + /** + * @return the integer value in this map + */ + public int getInt(String key){ + if( !this.isMap() ) throw new NullPointerException("The node is not setup as a map"); + if( !this.map.containsKey(key) ) throw new NullPointerException("No such key in map"); + return this.get(key).getInt(); + } + /** + * @return the double value in this map + */ + public double getDouble(String key){ + if( !this.isMap() ) throw new NullPointerException("The node is not setup as a map"); + if( !this.map.containsKey(key) ) throw new NullPointerException("No such key in map"); + return this.get(key).getDouble(); + } + /** + * @return the long value in this map + */ + public long getLong(String key){ + if( !this.isMap() ) throw new NullPointerException("The node is not setup as a map"); + if( !this.map.containsKey(key) ) throw new NullPointerException("No such key in map"); + return this.get(key).getLong(); + } + /** * @return the String value in this node, null if its a Map or List @@ -256,6 +298,12 @@ public class JSONNode implements Iterable{ public double getDouble(){ return Double.parseDouble(value); } + /** + * @return the long value in this node + */ + public long getLong(){ + return Long.parseLong(value); + } public String toString(){ diff --git a/src/zutil/parser/json/JSONParser.java b/src/zutil/parser/json/JSONParser.java index 46a30a6..38e2f2a 100644 --- a/src/zutil/parser/json/JSONParser.java +++ b/src/zutil/parser/json/JSONParser.java @@ -1,7 +1,8 @@ package zutil.parser.json; import zutil.io.MultiPrintStream; -import zutil.parser.json.JSONNode.JSONType; +import zutil.parser.DataNode; +import zutil.parser.DataNode.DataType; /** * This is a JSON parser class @@ -28,7 +29,7 @@ public class JSONParser{ " { \"type\": \"fax\", \"number\": \"646 555-4567\" }"+ " ]"+ "}"); - JSONNode node = parser.read(); + DataNode node = parser.read(); MultiPrintStream.out.dump( node ); JSONWriter writer = new JSONWriter( System.out ); writer.write(node); @@ -48,7 +49,7 @@ public class JSONParser{ * * @return a JSONNode object that is the root of the JSON */ - public JSONNode read(){ + public DataNode read(){ return parse(new StringBuffer(json)); } @@ -67,10 +68,10 @@ public class JSONParser{ * @param json * @return */ - protected static JSONNode parse(StringBuffer json){ - JSONNode root = null; - JSONNode key = null; - JSONNode node = null; + protected static DataNode parse(StringBuffer json){ + DataNode root = null; + DataNode key = null; + DataNode node = null; int next_index; while(Character.isWhitespace( json.charAt(0) ) || @@ -84,26 +85,26 @@ public class JSONParser{ case '}': return null; case '{': - root = new JSONNode(JSONType.Map); + root = new DataNode(DataType.Map); while((key = parse( json )) != null && (node = parse( json )) != null){ - root.add( key.toString(), node ); + root.set( key.toString(), node ); } break; case '[': - root = new JSONNode(JSONType.List); + root = new DataNode(DataType.List); while((node = parse( json )) != null){ root.add( node ); } break; // Parse String case '\"': - root = new JSONNode(JSONType.String); + root = new DataNode(DataType.String); next_index = json.indexOf("\""); root.set( json.substring(0, next_index) ); json.delete(0, next_index+1); break; default: - root = new JSONNode(JSONType.Number); + root = new DataNode(DataType.Number); for(next_index=0; next_index()); + System.out.println( s ); + + // Query 4 + PreparedStatement sql2 = db.getPreparedStatement("SELECT ?"); + sql2.setString(1, "hello"); + String s2 = DBConnection.exec(sql2, new SimpleSQLHandler()); + System.out.println( s2 ); + + db.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/zutil/test/HttpURLTest.java b/src/zutil/test/HttpURLTest.java new file mode 100644 index 0000000..1b05063 --- /dev/null +++ b/src/zutil/test/HttpURLTest.java @@ -0,0 +1,48 @@ +package zutil.test; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import zutil.net.http.HttpURL; + +public class HttpURLTest { + + @Test + public void fullURLTest() { + HttpURL url = new HttpURL(); + url.setProtocol("http"); + assertEquals( "http://127.0.0.1/", url.getURL() ); + + url.setHost("koc.se"); + assertEquals( "http://koc.se/", url.getURL() ); + + url.setPort( 80 ); + assertEquals( "http://koc.se:80/", url.getURL() ); + + url.setPath("test/index.html"); + assertEquals( "http://koc.se:80/test/index.html", url.getURL() ); + + url.setParameter("key", "value"); + assertEquals( "http://koc.se:80/test/index.html?key=value", url.getURL() ); + + url.setAnchor( "anch" ); + assertEquals( "http://koc.se:80/test/index.html?key=value#anch", url.getURL() ); + } + + @Test + public void urlParameterTest() { + HttpURL url = new HttpURL(); + url.setParameter("key1", "value1"); + assertEquals( "key1=value1", url.getParameterString() ); + + url.setParameter("key1", "value1"); + assertEquals( "key1=value1", url.getParameterString() ); + + url.setParameter("key2", "value2"); + assertEquals( "key2=value2&key1=value1", url.getParameterString() ); + + } + + +} diff --git a/src/zutil/test/SQLQueryTest.java b/src/zutil/test/SQLQueryTest.java new file mode 100644 index 0000000..e0d2411 --- /dev/null +++ b/src/zutil/test/SQLQueryTest.java @@ -0,0 +1,96 @@ +package zutil.test; + +import org.junit.*; +import static org.junit.Assert.*; + +import zutil.db.SQLQuery; + +public class SQLQueryTest { + + @Test + public void selectTest() { + assertEquals( "SELECT * FROM test1", + ""+SQLQuery.SELECT().FROM("test1") ); + assertEquals( "SELECT * FROM test1", + ""+SQLQuery.SELECT("*").FROM("test1") ); + assertEquals( "SELECT test1,test2 FROM test1", + ""+SQLQuery.SELECT("test1","test2").FROM("test1") ); + } + @Test + public void selectJoinTest() { + assertEquals( "SELECT * FROM test1 JOIN test2", + ""+SQLQuery.SELECT("*").FROM("test1").JOIN("test2") ); + assertEquals( "SELECT * FROM test1 NATURAL JOIN test2", + ""+SQLQuery.SELECT("*").FROM("test1").NATURAL_JOIN("test2") ); + assertEquals( "SELECT * FROM test1 UNION test2", + ""+SQLQuery.SELECT("*").FROM("test1").UNION("test2") ); + assertEquals( "SELECT * FROM test1 JOIN test2 NATURAL JOIN test3 UNION test4", + ""+SQLQuery.SELECT("*").FROM("test1").JOIN("test2").NATURAL_JOIN("test3").UNION("test4") ); + + assertEquals( "SELECT * FROM test1 NATURAL JOIN test2 NATURAL JOIN test3 NATURAL JOIN test4", + ""+SQLQuery.SELECT("*").FROM().NATURAL_JOIN("test1","test2","test3","test4") ); + assertEquals( "SELECT * FROM test1 JOIN test2 JOIN test3 JOIN test4", + ""+SQLQuery.SELECT("*").FROM().JOIN("test1","test2","test3","test4") ); + assertEquals( "SELECT * FROM test1 UNION test2 UNION test3 UNION test4", + ""+SQLQuery.SELECT("*").FROM().UNION("test1","test2","test3","test4") ); + } + @Test + public void selectWhereTest() { + assertEquals( "SELECT * FROM test1 WHERE arg=value", + ""+SQLQuery.SELECT("*").FROM("test1").WHERE().EQ("arg","value") ); + } + @Test + public void selectGroupByTest() { + assertEquals( "SELECT * FROM test1 GROUP BY col1", + ""+SQLQuery.SELECT("*").FROM("test1").GROUP_BY("col1") ); + assertEquals( "SELECT * FROM test1 WHERE arg=value GROUP BY col1", + ""+SQLQuery.SELECT("*").FROM("test1").WHERE().EQ("arg","value").GROUP_BY("col1") ); + assertEquals( "SELECT * FROM test1 WHERE arg=value GROUP BY col1 ASC", + ""+SQLQuery.SELECT("*").FROM("test1").WHERE().EQ("arg","value").GROUP_BY("col1").ASC() ); + assertEquals( "SELECT * FROM test1 WHERE arg=value GROUP BY col1 DESC", + ""+SQLQuery.SELECT("*").FROM("test1").WHERE().EQ("arg","value").GROUP_BY("col1").DESC() ); + } + @Test + public void selectOrderByTest() { + assertEquals( "SELECT * FROM test1 WHERE arg=value ORDER BY col1", + ""+SQLQuery.SELECT("*").FROM("test1").WHERE().EQ("arg","value").ORDER_BY("col1") ); + assertEquals( "SELECT * FROM test1 WHERE arg=value ORDER BY col1 ASC", + ""+SQLQuery.SELECT("*").FROM("test1").WHERE().EQ("arg","value").ORDER_BY("col1").ASC() ); + assertEquals( "SELECT * FROM test1 WHERE arg=value ORDER BY col1 DESC", + ""+SQLQuery.SELECT("*").FROM("test1").WHERE().EQ("arg","value").ORDER_BY("col1").DESC() ); + assertEquals( "SELECT * FROM test1 WHERE arg=value GROUP BY col1 ORDER BY col2 DESC", + ""+SQLQuery.SELECT("*").FROM("test1").WHERE().EQ("arg","value").GROUP_BY("col1").ORDER_BY("col2").DESC() ); + assertEquals( "SELECT * FROM test1 WHERE arg=value GROUP BY col1 ASC ORDER BY col2 DESC", + ""+SQLQuery.SELECT("*").FROM("test1").WHERE().EQ("arg","value").GROUP_BY("col1").ASC().ORDER_BY("col2").DESC() ); + } + @Test + public void selectLimitTest() { + assertEquals( "SELECT * FROM test1 LIMIT 1", + ""+SQLQuery.SELECT("*").FROM("test1").LIMIT(1) ); + assertEquals( "SELECT * FROM test1 LIMIT 1 4", + ""+SQLQuery.SELECT("*").FROM("test1").LIMIT(1).TO(4) ); + assertEquals( "SELECT * FROM test1 WHERE arg=value LIMIT 1", + ""+SQLQuery.SELECT("*").FROM("test1").WHERE().EQ("arg","value").LIMIT(1) ); + assertEquals( "SELECT * FROM test1 WHERE arg=value ORDER BY col1 DESC LIMIT 1", + ""+SQLQuery.SELECT("*").FROM("test1").WHERE().EQ("arg","value").ORDER_BY("col1").DESC().LIMIT(1) ); + assertEquals( "SELECT * FROM test1 WHERE arg=value GROUP BY col1 ORDER BY col2 DESC LIMIT 1", + ""+SQLQuery.SELECT("*").FROM("test1").WHERE().EQ("arg","value").GROUP_BY("col1").ORDER_BY("col2").DESC().LIMIT(1) ); + } + + + @Test + public void updateTest() { + + } + + + @Test + public void deleteTest() { + + } + + @Test + public void createTest() { + + } +} diff --git a/src/zutil/test/UpdateClientTest.java b/src/zutil/test/UpdateClientTest.java index 9208391..2d504a9 100644 --- a/src/zutil/test/UpdateClientTest.java +++ b/src/zutil/test/UpdateClientTest.java @@ -1,20 +1,43 @@ package zutil.test; -import zutil.ProgressListener; -import zutil.net.UpdateClient; -import zutil.net.Zupdater; +import java.awt.EventQueue; +import java.util.logging.Level; -public class UpdateClientTest implements ProgressListener{ +import zutil.ProgressListener; +import zutil.log.CompactLogFormatter; +import zutil.log.LogUtil; +import zutil.net.update.FileInfo; +import zutil.net.update.UpdateClient; +import zutil.net.update.Zupdater; + +public class UpdateClientTest implements ProgressListener{ public static void main(String[] args){ + LogUtil.setLevel("zutil", Level.FINEST); + LogUtil.setFormatter("zutil", new CompactLogFormatter()); + UpdateClientTest client = new UpdateClientTest(); client.start(); } public void start(){ try { - UpdateClient client = new UpdateClient("localhost", 2000, "client"); + final UpdateClient client = new UpdateClient("localhost", 2000, "C:\\Users\\Ziver\\Desktop\\client"); client.setProgressListener(new Zupdater()); + //client.setProgressListener(this); + + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + Zupdater gui = new Zupdater(); + client.setProgressListener(gui); + gui.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + client.update(); client.close(); } catch (Exception e) { @@ -22,7 +45,7 @@ public class UpdateClientTest implements ProgressListener{ } } - public void progressUpdate(Object source, Object info, double percent) { + public void progressUpdate(UpdateClient source, FileInfo info, double percent) { System.out.println(info+": "+percent+"%"); } } diff --git a/src/zutil/test/UpdateServerTest.java b/src/zutil/test/UpdateServerTest.java index b3d9fad..652380c 100644 --- a/src/zutil/test/UpdateServerTest.java +++ b/src/zutil/test/UpdateServerTest.java @@ -1,11 +1,18 @@ package zutil.test; -import zutil.net.UpdateServer; +import java.util.logging.Level; + +import zutil.log.CompactLogFormatter; +import zutil.log.LogUtil; +import zutil.net.update.UpdateServer; public class UpdateServerTest { public static void main(String[] args){ try { - new UpdateServer(2000, "server"); + LogUtil.setGlobalLevel(Level.FINEST); + LogUtil.setGlobalFormatter(new CompactLogFormatter()); + + new UpdateServer(2000, "C:\\Users\\Ziver\\Desktop\\server"); }catch (Exception e) { e.printStackTrace(); }