diff --git a/src/zutil/db/MySQLConnection.java b/src/zutil/db/MySQLConnection.java
new file mode 100644
index 0000000..e5f9885
--- /dev/null
+++ b/src/zutil/db/MySQLConnection.java
@@ -0,0 +1,108 @@
+package zutil.db;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+public class MySQLConnection {
+ Connection conn = null;
+
+ /**
+ * Connects to a MySQL server
+ *
+ * @param url is the URL of the MySQL server
+ * @param db is the database to connect to
+ * @param user is the user name
+ * @param password is the password
+ */
+ public MySQLConnection(String url, String db, String user, String password)
+ throws SQLException, InstantiationException, IllegalAccessException, ClassNotFoundException{
+ Class.forName ("com.mysql.jdbc.Driver").newInstance();
+ DriverManager.setLoginTimeout(10);
+ conn = DriverManager.getConnection ("jdbc:mysql://"+url+"/"+db, user, password);
+ }
+
+ /**
+ * Runs a query and returns the result.
+ * NOTE: Don't forget to close the ResultSet and the Statement or it
+ * can lead to memory leak: rows.getStatement().close();
+ *
+ * @param sql is the query to execute
+ * @return the data that the DB returned
+ */
+ public synchronized ResultSet query(String sql) throws SQLException{
+ Statement s = conn.createStatement ();
+ s.executeQuery(sql);
+ return s.getResultSet();
+ }
+
+ /**
+ * Returns the first cell of the first row of the query
+ *
+ * @param sql is the SQL query to run, preferably with the LIMIT 1 at the end
+ * @return A SQL row if it exists or else null
+ */
+ public synchronized String simpleQuery(String sql) throws SQLException{
+ Statement s = conn.createStatement ();
+ s.executeQuery(sql);
+ ResultSet result = s.getResultSet();
+ if(result.next()){
+ String tmp = result.getString(1);
+ result.close();
+ return tmp;
+ }
+ return null;
+ }
+
+ /**
+ * Runs a query in the MySQL server and returns effected rows
+ *
+ * @param sql is the query to execute
+ * @return the number of rows effected
+ */
+ public synchronized int updateQuery(String sql) throws SQLException{
+ Statement s = conn.createStatement ();
+ int ret = s.executeUpdate(sql);
+ s.close();
+ return ret;
+ }
+
+ /**
+ * @return the last inserted id or -1 if there was an error
+ * @throws SQLException
+ */
+ public int getLastInsertID() throws SQLException{
+ Statement s = conn.createStatement ();
+ s.executeQuery("SELECT LAST_INSERT_ID()");
+ ResultSet result = s.getResultSet();
+ if(result.next()){
+ int tmp = result.getInt(1);
+ result.close();
+ return tmp;
+ }
+ return -1;
+ }
+
+ /**
+ * Runs a Prepared Statement.
+ * NOTE: Don't forget to close the PreparedStatement or it can lead to memory leak
+ *
+ * @param sql is the SQL query to run
+ * @return The PreparedStatement
+ */
+ public synchronized PreparedStatement prepareStatement(String sql) throws SQLException{
+ return conn.prepareStatement(sql);
+ }
+
+ /**
+ * Disconnects from the database
+ */
+ public synchronized void close() throws SQLException{
+ if (conn != null){
+ conn.close ();
+ }
+ }
+}
diff --git a/src/zutil/db/MySQLQueue.java b/src/zutil/db/MySQLQueue.java
new file mode 100644
index 0000000..7ca1bf8
--- /dev/null
+++ b/src/zutil/db/MySQLQueue.java
@@ -0,0 +1,181 @@
+package zutil.db;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Queue;
+
+import zutil.MultiPrintStream;
+import zutil.converters.Converter;
+
+/**
+ * This class creates a queue that stors the
+ * data in a mysql table.
+ * The table should look like this:
+ * CREATE TABLE `queue` (
+ * `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
+ * `data` BINARY NOT NULL
+ * );
+ * @author Ziver
+ *
+ */
+public class MySQLQueue implements Queue{
+ // GO TO KNOW = SELECT LAST_INSERT_ID() as pos_id
+ private MySQLConnection db;
+ private String table;
+
+ /**
+ * Initiats the queue.
+ * WARNING!! this will erase all rows i the table
+ * @param db The connection to the db
+ * @param table The name of the table
+ * @throws SQLException
+ */
+ public MySQLQueue(MySQLConnection db, String table){
+ this.db = db;
+ this.table = table;
+ }
+
+ public boolean add(Object arg0){
+ try {
+ PreparedStatement sql = db.prepareStatement("INSERT INTO "+table+" (data) VALUES(?)");
+ sql.setObject(1, arg0);
+ sql.executeUpdate();
+ sql.close();
+ } catch (Exception e) {
+ e.printStackTrace(MultiPrintStream.out);
+ return false;
+ }
+ return true;
+ }
+
+ public E element() {
+ return peek();
+ }
+
+ public boolean offer(Object arg0) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ public synchronized E peek() {
+ try {
+ ResultSet rs = db.query("SELECT * FROM "+table+" LIMIT 1");
+ if (rs.next()) {
+ return (E) Converter.toObject(rs.getBytes("data"));
+ }
+ rs.getStatement().close();
+ } catch (Exception e) {
+ e.printStackTrace(MultiPrintStream.out);
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public synchronized E poll() {
+ try {
+ ResultSet rs = db.query("SELECT * FROM "+table+" LIMIT 1");
+ if (rs.next()) {
+ db.updateQuery("DELETE FROM "+table+" WHERE id="+rs.getInt("id")+" LIMIT 1");
+ return (E) Converter.toObject(rs.getBytes("data"));
+ }
+ rs.getStatement().close();
+ } catch (Exception e) {
+ e.printStackTrace(MultiPrintStream.out);
+ }
+ return null;
+ }
+
+ public E remove() {
+ return poll();
+ }
+
+ public boolean addAll(Collection extends E> arg0) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void clear() {
+ try {
+ db.updateQuery("TRUNCATE TABLE `"+table+"`");
+ } catch (SQLException e) {
+ e.printStackTrace(MultiPrintStream.out);
+ }
+ }
+
+ public boolean contains(Object arg0) {
+ try {
+ ResultSet rs = db.query("SELECT data FROM "+table+" WHERE data='"+Converter.toBytes(arg0)+"' LIMIT 1");
+ if (rs.next()) {
+ return true;
+ }
+ rs.getStatement().close();
+ } catch (Exception e) {
+ e.printStackTrace(MultiPrintStream.out);
+ }
+ return false;
+ }
+
+ public boolean containsAll(Collection> arg0) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isEmpty() {
+ return (peek() != null);
+ }
+
+ public Iterator iterator() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public synchronized boolean remove(Object arg0) {
+ try {
+ ResultSet rs = db.query("DELETE FROM "+table+" WHERE data='"+Converter.toBytes(arg0)+"' LIMIT 1");
+ rs.getStatement().close();
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace(MultiPrintStream.out);
+ }
+ return false;
+ }
+
+ public synchronized boolean removeAll(Collection> arg0) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean retainAll(Collection> arg0) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public int size() {
+ try {
+ ResultSet rs = db.query("SELECT count(*) FROM "+table);
+ if (rs.next()) {
+ return rs.getInt(1);
+ }
+ rs.getStatement().close();
+ } catch (Exception e) {
+ e.printStackTrace(MultiPrintStream.out);
+ }
+ return 0;
+ }
+
+ public E[] toArray() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public E[] toArray(Object[] arg0) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/zutil/math/parser/MathParser.java b/src/zutil/parser/MathParser.java
similarity index 95%
rename from src/zutil/math/parser/MathParser.java
rename to src/zutil/parser/MathParser.java
index 052c9ef..3a5903e 100644
--- a/src/zutil/math/parser/MathParser.java
+++ b/src/zutil/parser/MathParser.java
@@ -1,4 +1,4 @@
-package zutil.math.parser;
+package zutil.parser;
import java.io.BufferedReader;
import java.io.IOException;
diff --git a/src/zutil/parser/json/JSONNode.java b/src/zutil/parser/json/JSONNode.java
new file mode 100644
index 0000000..d032380
--- /dev/null
+++ b/src/zutil/parser/json/JSONNode.java
@@ -0,0 +1,247 @@
+package zutil.parser.json;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * This is an node in an JSON tree,
+ * it may contain a Map, list or value
+ *
+ * @author Ziver
+ */
+public class JSONNode implements Iterable{
+ public enum JSONType{
+ Map, List, String, Number, Boolean
+ }
+ private Map map = null;
+ private List list = null;
+ private String value = null;
+ private JSONType type;
+
+
+ /**
+ * Creates an instance with an Boolean value
+ */
+ public JSONNode(boolean value){
+ this.type = JSONType.Boolean;
+ this.value = ""+value;
+ }
+ /**
+ * Creates an instance with an int value
+ */
+ public JSONNode(int value){
+ this.type = JSONType.Number;
+ this.value = ""+value;
+ }
+ /**
+ * Creates an instance with an double value
+ */
+ public JSONNode(double value){
+ this.type = JSONType.Number;
+ this.value = ""+value;
+ }
+ /**
+ * Creates an instance with an String value
+ */
+ public JSONNode(String value){
+ this.type = JSONType.String;
+ this.value = value;
+ }
+ /**
+ * Creates an instance with a specific type
+ */
+ public JSONNode(JSONType type){
+ this.type = type;
+ switch(type){
+ case Map:
+ map = new HashMap(); break;
+ case List:
+ list = new LinkedList(); break;
+ }
+ }
+
+ /**
+ * @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){
+ if(map != null)
+ return map.get(""+index);
+ else if(list != null)
+ return list.get(index);
+ return null;
+ }
+ /**
+ * @param index is the key in the Map
+ * @return an JSONNode that contains the next level of the Map
+ */
+ public JSONNode get(String index){
+ if(map != null)
+ return map.get(index);
+ return null;
+ }
+
+ /**
+ * @return a iterator for the Map or List or null if the node contains a value
+ */
+ public Iterator iterator(){
+ if(map != null)
+ return map.values().iterator();
+ else if(list != null)
+ return list.iterator();
+ return null;
+ }
+ /**
+ * @return a iterator for the keys in the Map or null if the node contains a value or List
+ */
+ public Iterator keyIterator(){
+ if(map != null)
+ return map.keySet().iterator();
+ return null;
+ }
+ /**
+ * @return the size of the Map or List or -1 if it is a value
+ */
+ public int size(){
+ if(map != null)
+ return map.size();
+ else if(list != null)
+ return list.size();
+ return -1;
+ }
+
+
+ /**
+ * Adds a node to the List
+ */
+ public void add(JSONNode node){
+ list.add(node);
+ }
+ public void add(boolean value){
+ list.add(new JSONNode( value ));
+ }
+ public void add(int value){
+ list.add(new JSONNode( value ));
+ }
+ public void add(double value){
+ list.add(new JSONNode( value ));
+ }
+ public void add(String value){
+ list.add(new JSONNode( value ));
+ }
+ /**
+ * Adds a node to the Map
+ */
+ public void add(String key, JSONNode node){
+ map.put(key, node);
+ }
+ public void add(String key, boolean value){
+ map.put(key, new JSONNode(value));
+ }
+ public void add(String key, int value){
+ map.put(key, new JSONNode(value));
+ }
+ public void add(String key, double value){
+ map.put(key, new JSONNode(value));
+ }
+ public void add(String key, String value){
+ map.put(key, new JSONNode(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() ) return;
+ type = JSONType.Number;
+ this.value = ""+value;
+ }
+ /**
+ * Sets the value of the node, but only if it is setup as an JSONType.Value
+ */
+ public void set(double value){
+ if( !this.isValue() ) return;
+ type = JSONType.Number;
+ this.value = ""+value;
+ }
+ /**
+ * Sets the value of the node, but only if it is setup as an JSONType.Value
+ */
+ public void set(boolean value){
+ if( !this.isValue() ) return;
+ type = JSONType.Boolean;
+ this.value = ""+value;
+ }
+ /**
+ * Sets the value of the node, but only if it is setup as an JSONType.Value
+ */
+ public void set(String value){
+ if( !this.isValue() ) return;
+ type = JSONType.String;
+ this.value = value;
+ }
+
+
+ /**
+ * @return if this node contains an Map
+ */
+ public boolean isMap(){
+ return type == JSONType.Map;
+ }
+ /**
+ * @return if this node contains an List
+ */
+ public boolean isList(){
+ return type == JSONType.List;
+ }
+ /**
+ * @return if this node contains an value
+ */
+ public boolean isValue(){
+ return type != JSONType.Map && type != JSONType.List;
+ }
+ /**
+ * @return the type of the node
+ */
+ public JSONType getType(){
+ return type;
+ }
+
+
+ /**
+ * @return the String value in this node, null if its a Map or List
+ */
+ public String getString(){
+ return value;
+ }
+ /**
+ * @return the boolean value in this node
+ */
+ public boolean getBoolean(){
+ return Boolean.parseBoolean(value);
+ }
+ /**
+ * @return the integer value in this node
+ */
+ public int getInt(){
+ return Integer.parseInt(value);
+ }
+ /**
+ * @return the double value in this node
+ */
+ public double getDouble(){
+ return Double.parseDouble(value);
+ }
+
+
+ public String toString(){
+ if( this.isMap() )
+ return map.toString();
+ else if( this.isList() )
+ return list.toString();
+ return value;
+ }
+}
diff --git a/src/zutil/parser/json/JSONParser.java b/src/zutil/parser/json/JSONParser.java
new file mode 100644
index 0000000..c15f765
--- /dev/null
+++ b/src/zutil/parser/json/JSONParser.java
@@ -0,0 +1,162 @@
+package zutil.parser.json;
+
+import zutil.MultiPrintStream;
+import zutil.parser.json.JSONNode.JSONType;
+
+public class JSONParser {
+ private String json;
+ private int index;
+
+
+ public static void main(String[] args){
+ JSONParser parser = new JSONParser("" +
+ "{"+
+ " \"firstName\": \"John\","+
+ " \"lastName\": \"Smith\","+
+ " \"age\": 25,"+
+ " \"address\": {"+
+ " \"streetAddress\": \"21 2nd Street\","+
+ " \"city\": \"New York\","+
+ " \"state\": \"NY\","+
+ " \"postalCode\": \"10021\""+
+ " },"+
+ " \"phoneNumber\": ["+
+ " { \"type\": \"home\", \"number\": \"212 555-1234\" },"+
+ " { \"type\": \"fax\", \"number\": \"646 555-4567\" }"+
+ " ]"+
+ "}");
+ JSONNode node = parser.read();
+ MultiPrintStream.out.dump( node );
+ JSONWriter writer = new JSONWriter(System.out);
+ writer.write(node);
+ }
+
+ public JSONParser(String json){
+ this.json = json;
+ }
+
+ public JSONNode read(){
+ index = 0;
+ return parse(new StringBuffer(json));
+ }
+
+ protected JSONNode parse(StringBuffer json){
+ JSONNode root = null;
+ JSONNode key = null;
+ JSONNode node = null;
+ int next_index;
+
+ while(Character.isWhitespace( json.charAt(0) ) ||
+ json.charAt(0) == ',' || json.charAt(0) == ':')
+ json.deleteCharAt(0);
+ char c = json.charAt(0);
+ json.deleteCharAt(0);
+
+ switch( c ){
+ case ']':
+ case '}':
+ return null;
+ case '{':
+ root = new JSONNode(JSONType.Map);
+ while((key = parse( json )) != null && (node = parse( json )) != null){
+ root.add( key.toString(), node );
+ }
+ break;
+ case '[':
+ root = new JSONNode(JSONType.List);
+ while((node = parse( json )) != null){
+ root.add( node );
+ }
+ break;
+ // Parse String
+ case '\"':
+ root = new JSONNode(JSONType.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);
+ for(next_index=0; next_index it = root.keyIterator();
+ while(it.hasNext()){
+ if(!first)
+ out.print(", ");
+ String key = it.next();
+ try{
+ out.print( Integer.parseInt(key) );
+ }catch(Exception e){
+ out.print('\"');
+ out.print(key);
+ out.print('\"');
+ }
+ out.print(": ");
+ write( root.get(key) );
+ first = false;
+ }
+ out.print('}');
+ break;
+ // Write an list
+ case List:
+ out.print('[');
+ for(JSONNode node : root){
+ if(!first)
+ out.print(", ");
+ write( node );
+ first = false;
+ }
+ out.print(']');
+ break;
+ default:
+ if(root.getType() == JSONType.String){
+ out.print('\"');
+ out.print(root.toString());
+ out.print('\"');
+ } else
+ out.print(root.toString());
+ break;
+ }
+ out.flush();
+ }
+
+ /**
+ * Closes the internal stream
+ */
+ public void close(){
+ out.close();
+ }
+
+}