From 952a388cf1e257efca0cd3929a7349ac4dbe87e9 Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Thu, 15 Apr 2010 20:52:34 +0000 Subject: [PATCH] Allot of fixes --- src/zutil/FileFinder.java | 40 ++- src/zutil/db/DBConnection.java | 261 +++++++++++++++ src/zutil/db/DBConnectionPool.java | 174 ++++++++++ .../db/{MySQLQueue.java => DBQueue.java} | 87 +++-- src/zutil/db/MySQLConnection.java | 108 ------ src/zutil/db/SQLResultHandler.java | 15 + src/zutil/log/CompactLogFormatter.java | 126 +++++++ src/zutil/log/StandardLogFormatter.java | 67 ++-- src/zutil/network/http/HTTPHeaderParser.java | 2 + src/zutil/network/http/HttpServer.java | 15 +- src/zutil/network/http/soap/SOAPHttpPage.java | 315 +++++++++++------- .../network/http/soap/SOAPInterface.java | 12 +- .../http/soap/SOAPReturnObjectList.java | 51 +++ .../http/soap/SOAPReturnValueList.java | 57 ++++ .../{test => network/http/soap}/SOAPTest.java | 25 +- src/zutil/network/ssdp/SSDPClient.java | 24 +- src/zutil/network/ssdp/SSDPServer.java | 13 +- src/zutil/network/ssdp/SSDPServiceInfo.java | 68 +--- src/zutil/network/ssdp/StandardSSDPInfo.java | 98 ++++++ src/zutil/test/UPnPServerTest.java | 42 +++ src/zutil/ui/wizard/Wizard.java | 2 +- src/zutil/wrapper/StringOutputStream.java | 3 +- 22 files changed, 1197 insertions(+), 408 deletions(-) create mode 100644 src/zutil/db/DBConnection.java create mode 100644 src/zutil/db/DBConnectionPool.java rename src/zutil/db/{MySQLQueue.java => DBQueue.java} (56%) delete mode 100644 src/zutil/db/MySQLConnection.java create mode 100644 src/zutil/db/SQLResultHandler.java create mode 100644 src/zutil/log/CompactLogFormatter.java create mode 100644 src/zutil/network/http/soap/SOAPReturnObjectList.java create mode 100644 src/zutil/network/http/soap/SOAPReturnValueList.java rename src/zutil/{test => network/http/soap}/SOAPTest.java (79%) create mode 100644 src/zutil/network/ssdp/StandardSSDPInfo.java create mode 100644 src/zutil/test/UPnPServerTest.java diff --git a/src/zutil/FileFinder.java b/src/zutil/FileFinder.java index 494bf05..e7ebfb2 100644 --- a/src/zutil/FileFinder.java +++ b/src/zutil/FileFinder.java @@ -111,10 +111,10 @@ public class FileFinder { } /** - * Returns a ArrayList with all the files in a folder and sub folders + * Returns a List with all the files in a folder and sub folders * * @param dir is the directory to search in - * @return The ArrayList with the files + * @return The List with the files */ public static List search(File dir){ return search(dir, new LinkedList(), true); @@ -124,22 +124,42 @@ public class FileFinder { * Returns a ArrayList with all the files in a folder and sub folders * * @param dir is the directory to search in - * @param fileList is the ArrayList to add the files to - * @param recursice is if the method should search the sub directories to. - * @return The ArrayList with the files + * @param fileList is the List to add the files to + * @param recursive is if the method should search the sub directories to. + * @return A List with the files */ public static List search(File dir, List fileList, boolean recursive){ - String[] temp = dir.list(); - File file; + return search(dir, new LinkedList(), false, (recursive ? Integer.MAX_VALUE : 0)); + } + + /** + * Returns a ArrayList with all the files in a folder and sub folders + * + * @param dir is the directory to search in + * @param fileList is the List to add the files to + * @param folders is if the method should add the folders to the List + * @param recurse is how many times it should recurse into folders + * @return A List with the files and/or folders + */ + public static List search(File dir, List fileList, boolean folders, int recurse){ + if(recurse<0) + return fileList; + --recurse; + if(folders){ + MultiPrintStream.out.println("Dir Found : "+dir); + fileList.add( dir ); + } + File file; + String[] temp = dir.list(); if(temp != null){ for(int i=0; i + * NOTE: Don't forget to close the PreparedStatement or it can lead to memory leaks + * + * @param sql is the SQL query to run + * @return An PreparedStatement + */ + public PreparedStatement getPreparedStatement(String sql) throws SQLException{ + return conn.prepareStatement(sql); + } + + /** + * NOTE: Don't forget to close the Statement or it can lead to memory leaks + * + * @return an Statement for the DB + */ + public Statement getStatement() throws SQLException{ + return conn.createStatement(); + } + + /** + * Executes an query and cleans up after itself. + * + * @param query is the query + * @return update count or -1 if the query is not an update query + */ + public int exec(String query) throws SQLException { + PreparedStatement stmt = getPreparedStatement( query ); + return exec(stmt); + } + + /** + * Executes an query and cleans up after itself. + * + * @param stmt is the query + * @return update count or -1 if the query is not an update query + */ + public static int exec(PreparedStatement stmt) throws SQLException { + return exec(stmt, new SQLResultHandler(){ + public Integer handle(Statement stmt, ResultSet result) { + try { + return stmt.getUpdateCount(); + } catch (SQLException e) { + e.printStackTrace(); + } + return -1; + } + }); + } + + /** + * Executes an query and cleans up after itself. + * @param + * + * @param query is the query + * @param handler is the result handler + * @return update count or -1 if the query is not an update query + */ + public T exec(String query, SQLResultHandler handler) throws SQLException { + PreparedStatement stmt = getPreparedStatement( query ); + return exec(stmt, handler); + } + + /** + * Executes an query and cleans up after itself. + * + * @param stmt is the query + * @param handler is the result handler + * @return the object from the handler + */ + public static T exec(PreparedStatement stmt, SQLResultHandler handler) throws SQLException{ + try{ + // Execute + stmt.execute(); + + // Handle result + if( handler != null ){ + ResultSet result = null; + try{ + result = stmt.getResultSet(); + return handler.handle(stmt, result); + }finally{ + if(result != null){ + try { + result.close(); + } catch (SQLException e) { } + result = null; + } + } + } + // Cleanup + } finally { + if (stmt != null) { + try { + stmt.close(); + } catch (SQLException sqlex) { } + stmt = null; + } + } + return null; + } + + /** + * Sets the pool that this connection belongs to + * + * @param pool is the pool + */ + protected void setPool(DBConnectionPool pool){ + if( pool != null ) + pool.removeConnection(this); + this.pool = pool; + } + + /** + * Checks if the DB Connection is valid and functioning + * + * @return true or false depending on the validity of the connection + */ + public boolean valid(){ + boolean ret = true; + try { + conn.getMetaData(); + ret = ret && !conn.isClosed(); + }catch (Exception e) { + return false; + } + return ret; + } + + /** + * Disconnects from the database or releases the connection back to the pool + */ + public void close() throws SQLException{ + if(pool!=null){ + pool.releaseConnection(this); + } + else{ + forceClose(); + } + } + + /** + * Disconnects from the database + */ + public void forceClose(){ + if (conn != null) { + try { + conn.close(); + } catch (SQLException sqlex) { + sqlex.printStackTrace(); + } + conn = null; + } + } + + public boolean equals(Object o){ + return conn.equals(o); + } +} diff --git a/src/zutil/db/DBConnectionPool.java b/src/zutil/db/DBConnectionPool.java new file mode 100644 index 0000000..36106f4 --- /dev/null +++ b/src/zutil/db/DBConnectionPool.java @@ -0,0 +1,174 @@ +package zutil.db; + +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.Timer; +import java.util.TimerTask; + +import zutil.db.DBConnection.DBMS; + +/** + * This class is an connection pool + * + * @author Ziver + */ +public class DBConnectionPool extends TimerTask { + public static final long DEFAULT_TIMEOUT = 10*60*60*1000; // 10 minutes; + public static final int DEFAULT_MAX_SIZE = 5; + + // DB details + private DBMS dbms; + private String url; + private String db; + private String user; + private String password; + + // Pool details + private int max_conn; + private long timeout; + private Timer timeout_timer; + + protected class PoolItem{ + public DBConnection conn; + public long timestamp; + + public boolean equals(Object o){ + return conn.equals(o); + } + } + + // The pool + private LinkedList inusePool; + private LinkedList readyPool; + + /** + * Creates a new pool of DB connections + * + * @param dbms is the DB type + * @param url is the URL to the DB + * @param db is the name of the database + * @param user is the user name to the DB + * @param password is the password to the DB + */ + public DBConnectionPool(DBMS dbms, String url, String db, String user, String password) throws Exception{ + this.dbms = dbms; + this.url = url; + this.db = db; + this.user = user; + this.password = password; + + inusePool = new LinkedList(); + readyPool = new LinkedList(); + + this.setTimeout(DEFAULT_TIMEOUT); + this.setMaxSize(DEFAULT_MAX_SIZE); + } + + /** + * Registers a Connection to the pool + * + * @param conn is the Connection to register + */ + protected void addConnection(DBConnection conn){ + PoolItem item = new PoolItem(); + item.conn = conn; + readyPool.addLast(item); + } + + /** + * Removes an connection from the pool + * + * @param conn is the connection to remove + */ + protected void removeConnection(DBConnection conn){ + inusePool.remove(conn); + readyPool.remove(conn); + } + + /** + * Lease one connection from the pool + * + * @return an DB connection or null if the pool is empty + */ + public synchronized DBConnection getConnection() throws Exception{ + if(readyPool.isEmpty()){ + if( size() < max_conn ){ + DBConnection conn = new DBConnection(dbms, url, db, user, password); + conn.setPool( this ); + addConnection( conn ); + return conn; + } + return null; + } + else{ + PoolItem item = readyPool.poll(); + inusePool.addLast(item); + item.timestamp = System.currentTimeMillis(); + return item.conn; + } + } + + /** + * Registers the Connection as not used + * + * @param conn is the connection that is not used anymore + */ + protected synchronized void releaseConnection(DBConnection conn){ + int index = inusePool.indexOf(conn); + PoolItem item = inusePool.remove(index); + readyPool.addLast(item); + } + + /** + * @return the current size of the pool + */ + public int size(){ + return inusePool.size() + readyPool.size(); + } + + /** + * Closes all the connections + */ + public synchronized void close() throws SQLException{ + for( PoolItem item : inusePool ){ + item.conn.forceClose(); + } + inusePool.clear(); + for( PoolItem item : readyPool ){ + item.conn.forceClose(); + } + readyPool.clear(); + } + + /** + * Set the max size of the pool + */ + public void setMaxSize(int max){ + this.max_conn = max; + } + + /** + * Sets the timeout of the Connections + */ + public synchronized void setTimeout(long timeout){ + this.timeout = timeout; + if(timeout_timer!=null) + timeout_timer.cancel(); + timeout_timer = new Timer(); + timeout_timer.schedule(this, 0, timeout / 2); + } + + /** + * Checks every DB connection if they are valid and has not timed out + */ + public void run(){ + long stale = System.currentTimeMillis() - timeout; + + for(PoolItem item : inusePool){ + if( !item.conn.valid() && stale > item.timestamp ) { + removeConnection(item.conn); + item.conn.forceClose(); + } + } + } +} diff --git a/src/zutil/db/MySQLQueue.java b/src/zutil/db/DBQueue.java similarity index 56% rename from src/zutil/db/MySQLQueue.java rename to src/zutil/db/DBQueue.java index 7ca1bf8..6e623c2 100644 --- a/src/zutil/db/MySQLQueue.java +++ b/src/zutil/db/DBQueue.java @@ -3,6 +3,7 @@ package zutil.db; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; import java.util.Collection; import java.util.Iterator; import java.util.Queue; @@ -21,29 +22,28 @@ import zutil.converters.Converter; * @author Ziver * */ -public class MySQLQueue implements Queue{ +public class DBQueue implements Queue{ // GO TO KNOW = SELECT LAST_INSERT_ID() as pos_id - private MySQLConnection db; + private DBConnection 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 + * Initiates the queue.
+ * WARNING!! this will erase all rows in the table + * + * @param db is the connection to the DB + * @param table is the name of the table */ - public MySQLQueue(MySQLConnection db, String table){ + public DBQueue(DBConnection db, String table){ this.db = db; this.table = table; } public boolean add(Object arg0){ try { - PreparedStatement sql = db.prepareStatement("INSERT INTO "+table+" (data) VALUES(?)"); + PreparedStatement sql = db.getPreparedStatement("INSERT INTO "+table+" (data) VALUES(?)"); sql.setObject(1, arg0); - sql.executeUpdate(); - sql.close(); + DBConnection.exec(sql); } catch (Exception e) { e.printStackTrace(MultiPrintStream.out); return false; @@ -56,18 +56,23 @@ public class MySQLQueue implements Queue{ } public boolean offer(Object arg0) { - // TODO Auto-generated method stub - return false; + return add(arg0); } @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(); + return db.exec("SELECT * FROM "+table+" LIMIT 1", new SQLResultHandler(){ + public E handle(Statement stmt, ResultSet rs) throws SQLException{ + if (rs.next()) + try { + return (E) Converter.toObject(rs.getBytes("data")); + } catch (Exception e) { + e.printStackTrace(MultiPrintStream.out); + } + return null; + } + }); } catch (Exception e) { e.printStackTrace(MultiPrintStream.out); } @@ -77,12 +82,19 @@ public class MySQLQueue implements Queue{ @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(); + return db.exec("SELECT * FROM "+table+" LIMIT 1", new SQLResultHandler(){ + public E handle(Statement stmt, ResultSet rs) { + try{ + if (rs.next()) { + db.exec("DELETE FROM "+table+" WHERE id="+rs.getInt("id")+" LIMIT 1"); + return (E) Converter.toObject(rs.getBytes("data")); + } + }catch(Exception e){ + e.printStackTrace(MultiPrintStream.out); + } + return null; + } + }); } catch (Exception e) { e.printStackTrace(MultiPrintStream.out); } @@ -100,7 +112,7 @@ public class MySQLQueue implements Queue{ public void clear() { try { - db.updateQuery("TRUNCATE TABLE `"+table+"`"); + db.exec("TRUNCATE TABLE `"+table+"`"); } catch (SQLException e) { e.printStackTrace(MultiPrintStream.out); } @@ -108,11 +120,11 @@ public class MySQLQueue implements Queue{ 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(); + return db.exec("SELECT data FROM "+table+" WHERE data='"+Converter.toBytes(arg0)+"' LIMIT 1", new SQLResultHandler(){ + public Boolean handle(Statement stmt, ResultSet rs) throws SQLException{ + return rs.next(); + } + }); } catch (Exception e) { e.printStackTrace(MultiPrintStream.out); } @@ -135,8 +147,7 @@ public class MySQLQueue implements Queue{ public synchronized boolean remove(Object arg0) { try { - ResultSet rs = db.query("DELETE FROM "+table+" WHERE data='"+Converter.toBytes(arg0)+"' LIMIT 1"); - rs.getStatement().close(); + db.exec("DELETE FROM "+table+" WHERE data='"+Converter.toBytes(arg0)+"' LIMIT 1"); return true; } catch (Exception e) { e.printStackTrace(MultiPrintStream.out); @@ -156,11 +167,13 @@ public class MySQLQueue implements Queue{ public int size() { try { - ResultSet rs = db.query("SELECT count(*) FROM "+table); - if (rs.next()) { - return rs.getInt(1); - } - rs.getStatement().close(); + return db.exec("SELECT count(*) FROM "+table, new SQLResultHandler(){ + public Integer handle(Statement stmt, ResultSet rs) throws SQLException{ + if (rs.next()) + return rs.getInt(1); + return 0; + } + }); } catch (Exception e) { e.printStackTrace(MultiPrintStream.out); } diff --git a/src/zutil/db/MySQLConnection.java b/src/zutil/db/MySQLConnection.java deleted file mode 100644 index e5f9885..0000000 --- a/src/zutil/db/MySQLConnection.java +++ /dev/null @@ -1,108 +0,0 @@ -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/SQLResultHandler.java b/src/zutil/db/SQLResultHandler.java new file mode 100644 index 0000000..353f3ec --- /dev/null +++ b/src/zutil/db/SQLResultHandler.java @@ -0,0 +1,15 @@ +package zutil.db; + +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.ResultSet; + +public interface SQLResultHandler { + /** + * Is called to handle an result from an query. + * + * @param stmt is the query + * @param result is the ResultSet + */ + public T handle(Statement stmt, ResultSet result) throws SQLException; +} diff --git a/src/zutil/log/CompactLogFormatter.java b/src/zutil/log/CompactLogFormatter.java new file mode 100644 index 0000000..0057d83 --- /dev/null +++ b/src/zutil/log/CompactLogFormatter.java @@ -0,0 +1,126 @@ +package zutil.log; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.logging.Formatter; +import java.util.logging.LogRecord; +import java.util.regex.Pattern; + +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 "); + // If displaying class names are enabled + private boolean className = true; + // If displaying method names are enabled + private boolean methodName = false; + // Specifies the max length of the longest class name + private int max_class_name = 0; + // Cache for the class padding + 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) ); + } + + 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; + } + + if( className ){ + data.append( paddClassName(record.getSourceClassName()) ); + } + if(methodName){ + 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] ); + } + ret.append( '\n' ); + return ret.toString(); + } + + /** + * If the formatter should add a time stamp in front of the log message + * + * @param enable set to True to activate time stamp + */ + public void enableTimeStamp(boolean enable){ + timeStamp = enable; + } + + /** + * The DateFormat to print in the time stamp + * + * @param ts is the String to send to SimpleDateFormat + */ + public void setTimeStamp(String ts){ + dateFormatter = new SimpleDateFormat(ts); + } + + /** + * If the formatter should add the class/source name in front of the log message + * + * @param enable set to True to activate class/source name + */ + public void enableClassName(boolean enable){ + className = enable; + } + + /** + * If the formatter should add the class/source name in front of the log message + * + * @param enable set to True to activate class/source name + */ + public void enableMethodName(boolean enable){ + methodName = enable; + } + + /** + * @return the Class name + */ + private String paddClassName(String source){ + 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 padd_cache = new HashMap(); + // Date temp file + private Date date = new Date(); public String format(String source, Level level, String msg) { StringBuilder data = new StringBuilder(); - switch(level.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; + if( timeStamp ){ + date.setTime( System.currentTimeMillis() ); + data.append( dateFormatter.format(date) ); } - if( timeStamp && className ){ - data.append( getTime() ); - data.append( " " ); - data.append( paddSourceName(source) ); - data.append( ": " ); - } - else if( timeStamp ){ - data.append( getTime() ); - data.append( " " ); - } - else if( className ){ - data.append( paddSourceName(source) ); - data.append( ": " ); + switch( level.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; } - StringBuilder ret = new StringBuilder(); + if( className ){ + data.append( paddSourceName(source) ); + } + data.append( ": " ); + + StringBuffer ret = new StringBuffer(); String[] array = splitter.split( msg ); for( int i=0; i max_class_name ) max_class_name = source.length(); @@ -102,7 +101,9 @@ public class StandardLogFormatter implements LogFormatter{ for( int i=source.length(); i client_info = new HashMap(); HashMap cookie = new HashMap(); HashMap request = new HashMap(); @@ -212,7 +210,7 @@ public class HttpServer extends ThreadedTCPNetworkServer{ } // Debug if(DEBUG){ - MultiPrintStream.out.println( "# page_url: "+page_url ); + MultiPrintStream.out.println( "# page_url: "+parser.getRequestURL() ); MultiPrintStream.out.println( "# cookie: "+cookie ); MultiPrintStream.out.println( "# client_session: "+client_session ); MultiPrintStream.out.println( "# client_info: "+client_info ); @@ -225,15 +223,16 @@ public class HttpServer extends ThreadedTCPNetworkServer{ out.setHeader( "Content-Type", "text/html" ); out.setCookie( "session_id", ""+client_session.get("session_id") ); - if( !page_url.isEmpty() && pages.containsKey(page_url) ){ - pages.get(page_url).respond(out, client_info, client_session, cookie, request); + if( !parser.getRequestURL().isEmpty() && pages.containsKey(parser.getRequestURL()) ){ + pages.get(parser.getRequestURL()).respond(out, client_info, client_session, cookie, request); } else if( defaultPage != null ){ defaultPage.respond(out, client_info, client_session, cookie, request); } else{ out.setStatusCode( 404 ); - out.println( "404 Page Not Found" ); + out.println( "404 Page Not Found" ); + if(DEBUG) MultiPrintStream.out.println("404 Page Not Found"); } //******************************************************************************** diff --git a/src/zutil/network/http/soap/SOAPHttpPage.java b/src/zutil/network/http/soap/SOAPHttpPage.java index f569785..a52d7c3 100644 --- a/src/zutil/network/http/soap/SOAPHttpPage.java +++ b/src/zutil/network/http/soap/SOAPHttpPage.java @@ -60,6 +60,7 @@ import com.sun.org.apache.xerces.internal.dom.DocumentImpl; * This is an HTTPPage for the HTTPServer that * handles soap messages. * + * TODO: Header should be variables not methods * TODO: Read SOAPObjects as input parameter * TODO: Ability to have multiple arrays of same SOAPObject * @@ -75,6 +76,7 @@ import com.sun.org.apache.xerces.internal.dom.DocumentImpl; * * Output: *
-SOAPObjects + *
-SOAPReturnObjectList *
-byte[] *
-int *
-double @@ -93,7 +95,8 @@ public class SOAPHttpPage implements HttpPage{ private class MethodCache{ String[] paramName; boolean[] paramOptional; - String returnName; + String[] returnName; + Class[] returnClass; Method method; boolean header; @@ -102,6 +105,20 @@ public class SOAPHttpPage implements HttpPage{ paramName = new String[method.getParameterTypes().length]; paramOptional = new boolean[method.getParameterTypes().length]; header = false; + + Class tmp = m.getReturnType(); + if( SOAPReturnValueList.class.isAssignableFrom( tmp )){ + returnName = new String[ tmp.getFields().length ]; + returnClass = new Class[ tmp.getFields().length ]; + } + else if( !tmp.isAssignableFrom( void.class )){ + returnName = new String[1]; + returnClass = new Class[1]; + } + else{ + returnName = new String[0]; + returnClass = new Class[0]; + } } } // The object that the functions will be invoked from @@ -148,12 +165,28 @@ public class SOAPHttpPage implements HttpPage{ tmp.append(m.getParameterTypes()[i].getSimpleName()+" "+chasch.paramName[i]); if( i "); - // the return param name + // the return parameter name SOAPInterface.SOAPReturnName returnName = m.getAnnotation(SOAPInterface.SOAPReturnName.class); - if(returnName != null) chasch.returnName = returnName.value(); - else chasch.returnName = "return"; + if( SOAPReturnValueList.class.isAssignableFrom( m.getReturnType() ) ){ + Class retClass = m.getReturnType(); + for(int i=0; i0 ){ + if(returnName != null) chasch.returnName[0] = returnName.value(); + else chasch.returnName[0] = "return"; + chasch.returnClass[0] = m.getReturnType(); + tmp.append(chasch.returnClass[0].getSimpleName()+" "+chasch.returnName[0]); + } // SOAP header? if(m.getAnnotation(SOAPInterface.SOAPHeader.class) != null) @@ -184,6 +217,13 @@ public class SOAPHttpPage implements HttpPage{ } } + /** + * Enables session support, if enabled then a new instance + * of the SOAPInterface will be created, if disabled then + * only the given object will be used as an static interface + * + * @param enabled is if session should be enabled + */ public void enableSession(boolean enabled){ this.session_enabled = enabled; } @@ -210,27 +250,33 @@ public class SOAPHttpPage implements HttpPage{ } else{ SOAPInterface obj = null; - if(session_enabled && session.containsKey("SOAPInterface")) - obj = (SOAPInterface)session.get("SOAPInterface"); + if(session_enabled){ + if( session.containsKey("SOAPInterface")) + obj = (SOAPInterface)session.get("SOAPInterface"); + else{ + obj = interf.getClass().newInstance(); + session.put("SOAPInterface", obj); + } + } else{ - obj = interf.getClass().newInstance(); - if(session_enabled) session.put("SOAPInterface", obj); + obj = interf; } - Document document = soapResponse( request.get(""), obj); + Document document = genSOAPResponse( request.get(""), obj); - OutputFormat format = OutputFormat.createPrettyPrint(); + OutputFormat format = OutputFormat.createCompactFormat(); XMLWriter writer = new XMLWriter( out, format ); writer.write( document ); - /* + // DEBUG - System.err.println("Request"); + OutputFormat format2 = OutputFormat.createPrettyPrint(); + System.err.println("********** Request"); System.err.println(request); - System.out.println("Response"); - writer = new XMLWriter( System.out, format ); + System.out.println("********** Response"); + writer = new XMLWriter( System.out, format2 ); writer.write( document ); - */ + } } catch (Exception e) { e.printStackTrace(MultiPrintStream.out); @@ -238,20 +284,24 @@ public class SOAPHttpPage implements HttpPage{ } /** - * Generates a soap response for the given + * Generates a soap response for the given XML * @param xml is the XML request * @return a Document with the response */ - public Document soapResponse(String xml){ + public Document genSOAPResponse(String xml){ try { - return soapResponse(xml, interf.getClass().newInstance()); + SOAPInterface o = null; + if(session_enabled) o = interf.getClass().newInstance(); + else o = interf; + + return genSOAPResponse(xml, o ); } catch (Exception e) { e.printStackTrace(MultiPrintStream.out); } return null; } - protected Document soapResponse(String xml, SOAPInterface obj){ + protected Document genSOAPResponse(String xml, SOAPInterface obj){ Document document = DocumentHelper.createDocument(); Element envelope = document.addElement("soap:Envelope"); try { @@ -294,17 +344,31 @@ public class SOAPHttpPage implements HttpPage{ return document; } + + /** + * Converts an String XML to an Element + * + * @param msg is the string XML + * @return the XML root Element + */ + private Element getXMLRoot(String xml) throws Exception { + if(xml != null && !xml.isEmpty()){ + Document document = DocumentHelper.parseText(xml); + return document.getRootElement(); + } + return null; + } /** * Takes an XML Element and invokes all the - * chide Elements as methods. + * Child Elements as methods. * * @param obj is the object that the methods will be called from * @param requestRoot is the Element where the children lies * @param responseRoot is the root element of the response */ @SuppressWarnings("unchecked") - private void prepareInvoke(Object obj, Element requestRoot, Element responseRoot) throws Throwable{ + private void prepareInvoke(SOAPInterface obj, Element requestRoot, Element responseRoot) throws Throwable{ Iterator it = requestRoot.elementIterator(); while( it.hasNext() ){ Element e = it.next(); @@ -312,7 +376,7 @@ public class SOAPHttpPage implements HttpPage{ MethodCache m = methods.get(e.getQName().getName()); Object[] params = new Object[m.paramName.length]; - // Get the param values + // Get the parameter values for(int i=0; i0 ){ + SOAPInterface.SOAPNameSpace namespace = m.method.getAnnotation(SOAPInterface.SOAPNameSpace.class); + Element response = responseRoot.addElement(""); + if( namespace != null ) + response.addNamespace("m", namespace.value()); + else + response.addNamespace("m", url+""+m.method.getName()); + response.setName("m:"+m.method.getName()+"Response"); + if( ret instanceof SOAPReturnValueList ){ + Field[] f = ret.getClass().getFields(); + for(int i=0; i c){ Class cTmp = getClass(c); @@ -465,6 +528,9 @@ public class SOAPHttpPage implements HttpPage{ } } + //******************************************************** + //********* WSDL Generation ************************* + /** * Generates an WSDL document for the class * @@ -516,7 +582,7 @@ public class SOAPHttpPage implements HttpPage{ imp.setLocationURI(td); wsdl.addImport(imp); - // PrtType + // PortType PortType portType = wsdl.createPortType(); portType.setQName(new QName(tns, portTypeName)); portType.setUndefined(false); @@ -559,38 +625,43 @@ public class SOAPHttpPage implements HttpPage{ operation.setInput(input); } //********** Response Message - if(!m.method.getReturnType().equals( void.class )){ + if( m.returnName.length>0 ){ Message msgOut = wsdl.createMessage(); msgOut.setQName(new QName(tns, m.method.getName()+"Response")); msgOut.setUndefined(false); - - // Parts - Part part = wsdl.createPart(); - part.setName(m.returnName); - msgOut.addPart(part); - - // Generate new type if the object is an SOAPObject - Class cTmp = getClass(m.method.getReturnType()); - if(byte[].class.isAssignableFrom(m.method.getReturnType())){ - part.setTypeName(new QName(xsd, "base64Binary")); - } - // is an array? - else if(m.method.getReturnType().isArray()){ - part.setTypeName(new QName(td, - "ArrayOf"+getClassSOAPName(m.method.getReturnType()).replaceAll("[\\[\\]]", ""))); - // add to type generation list - if(!types.contains(m.method.getReturnType())) - types.add(m.method.getReturnType()); - } - else if( SOAPObject.class.isAssignableFrom(cTmp) ){ - // its an SOAPObject - part.setTypeName(new QName(td, getClassSOAPName(m.method.getReturnType()))); - // add to type generation list - if(!types.contains(cTmp)) - types.add(cTmp); - } - else{// its an Object - part.setTypeName(new QName(xsd, getClassSOAPName(m.method.getReturnType()))); + + for( int i=0; i retClass = m.returnClass[i]; + //MultiPrintStream.out.println(m.method.getName()+"=>"+m.returnName[i]+"="+retClass); + + // Parts + Part part = wsdl.createPart(); + part.setName( m.returnName[i] ); + msgOut.addPart(part); + + Class cTmp = getClass( retClass ); + // is an binary array + if(byte[].class.isAssignableFrom( retClass )){ + part.setTypeName(new QName(xsd, "base64Binary")); + } + // is an array? + else if( retClass.isArray()){ + part.setTypeName(new QName(td, + "ArrayOf"+getClassSOAPName( retClass ).replaceAll("[\\[\\]]", ""))); + // add to type generation list + if(!types.contains( retClass )) + types.add( retClass ); + } + else if( SOAPObject.class.isAssignableFrom(cTmp) ){ + // its an SOAPObject + part.setTypeName(new QName(td, getClassSOAPName( retClass ))); + // add to type generation list + if(!types.contains(cTmp)) + types.add(cTmp); + } + else{// its an Object + part.setTypeName(new QName(xsd, getClassSOAPName( retClass ))); + } } wsdl.addMessage(msgOut); @@ -794,7 +865,7 @@ public class SOAPHttpPage implements HttpPage{ } private Class getClass(Class c){ - if(c.isArray()){ + if(c!=null && c.isArray()){ return getClass(c.getComponentType()); } return c; diff --git a/src/zutil/network/http/soap/SOAPInterface.java b/src/zutil/network/http/soap/SOAPInterface.java index 65f3b9f..56974e8 100644 --- a/src/zutil/network/http/soap/SOAPInterface.java +++ b/src/zutil/network/http/soap/SOAPInterface.java @@ -1,7 +1,6 @@ package zutil.network.http.soap; import java.lang.annotation.*; - /** * * Specifies SOAP parameters names an other things. @@ -99,4 +98,15 @@ public interface SOAPInterface { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface SOAPHeader { } + + /** + * Specifies the namespace for the method. + * + * @author Ziver + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface SOAPNameSpace { + String value(); + } } diff --git a/src/zutil/network/http/soap/SOAPReturnObjectList.java b/src/zutil/network/http/soap/SOAPReturnObjectList.java new file mode 100644 index 0000000..84b0335 --- /dev/null +++ b/src/zutil/network/http/soap/SOAPReturnObjectList.java @@ -0,0 +1,51 @@ +package zutil.network.http.soap; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This interface is for returning multiple object. + * All the public fields in the class that implements + * this class will be set as return values. And the + * implementing class will be transparent. + * + * @author Ziver + * + */ +public interface SOAPReturnObjectList { + + /** + * Method comments for the WSDL. + * These comments are put in the operation part of the WSDL + * + * @author Ziver + */ + @Retention(RetentionPolicy.RUNTIME) + public @interface WSDLDocumentation{ + String value(); + } + + /** + * Disables SOAP publication of the given field. + * + * @author Ziver + */ + /*@Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface SOAPDisabledValue { }*/ + + /** + * Annotation that assigns a name to the return value + * to the field. + * + * @author Ziver + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface SOAPValueName { + String value(); + } +} + diff --git a/src/zutil/network/http/soap/SOAPReturnValueList.java b/src/zutil/network/http/soap/SOAPReturnValueList.java new file mode 100644 index 0000000..83abb1b --- /dev/null +++ b/src/zutil/network/http/soap/SOAPReturnValueList.java @@ -0,0 +1,57 @@ +package zutil.network.http.soap; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Field; + +/** + * This interface is for returning multiple object. + * All the public fields in the class that implements + * this class will be set as return values. And the + * implementing class will be transparent. + * + * @author Ziver + * + */ +public class SOAPReturnValueList { + + /** + * Method comments for the WSDL. + * These comments are put in the operation part of the WSDL + * + * @author Ziver + */ + @Retention(RetentionPolicy.RUNTIME) + public @interface WSDLDocumentation{ + String value(); + } + + /** + * Disables SOAP publication of the given field. + * + * @author Ziver + */ + /*@Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface SOAPDisabledValue { }*/ + + /** + * Annotation that assigns a name to the return value + * to the field. + * + * @author Ziver + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface SOAPValueName { + String value(); + } + + + protected Object getValue(Field field) throws IllegalArgumentException, IllegalAccessException{ + return field.get(this); + } +} + diff --git a/src/zutil/test/SOAPTest.java b/src/zutil/network/http/soap/SOAPTest.java similarity index 79% rename from src/zutil/test/SOAPTest.java rename to src/zutil/network/http/soap/SOAPTest.java index 3d65aba..9f48a1a 100644 --- a/src/zutil/test/SOAPTest.java +++ b/src/zutil/network/http/soap/SOAPTest.java @@ -1,4 +1,4 @@ -package zutil.test; +package zutil.network.http.soap; import javax.wsdl.WSDLException; @@ -6,9 +6,6 @@ import org.dom4j.Document; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; -import zutil.network.http.soap.SOAPHttpPage; -import zutil.network.http.soap.SOAPInterface; -import zutil.network.http.soap.SOAPObject; public class SOAPTest { //******************************************************************************************* @@ -20,7 +17,7 @@ public class SOAPTest { // Response try { - Document document = soap.soapResponse( + Document document = soap.genSOAPResponse( "" + "\n" + " \n" + @@ -35,7 +32,7 @@ public class SOAPTest { " \n" + " \n" + ""); - System.out.println(); + System.out.println( "****************** RESPONSE *********************" ); OutputFormat format = OutputFormat.createPrettyPrint(); XMLWriter writer = new XMLWriter( System.out, format ); @@ -65,13 +62,20 @@ class SOAPTestClass2 implements SOAPObject{ public SOAPTestClass3 l = new SOAPTestClass3(); } +class SOAPTestRetClass implements SOAPReturnObjectList{ + @SOAPValueName("retTest") + public String lol = "lol1"; + public String lol2 = "lol2"; +} + class SOAPTestClass implements SOAPInterface{ public SOAPTestClass(){} @SOAPHeader() @WSDLDocumentation("hello") public void pubZ( - @SOAPParamName(value="olle", optional=true) int lol) throws Exception{ + @SOAPParamName(value="olle", optional=true) int lol, + @SOAPParamName(value="olle2", optional=true) int lol2) throws Exception{ //System.out.println("Param: "+lol); throw new Exception("Ziver is the fizle"); } @@ -93,9 +97,12 @@ class SOAPTestClass implements SOAPInterface{ @SOAPReturnName("zivarray") @WSDLParamDocumentation("null is the shizzle") - public byte[] pubB ( + public SOAPTestRetClass pubB ( @SOAPParamName("byte") String lol) throws Exception{ - return new byte[]{0x12, 0x23}; + SOAPTestRetClass tmp = new SOAPTestRetClass(); + tmp.lol = "test"; + tmp.lol2 = "test2"; + return tmp; } @SOAPDisabled() diff --git a/src/zutil/network/ssdp/SSDPClient.java b/src/zutil/network/ssdp/SSDPClient.java index f7732c8..1afa622 100644 --- a/src/zutil/network/ssdp/SSDPClient.java +++ b/src/zutil/network/ssdp/SSDPClient.java @@ -5,8 +5,9 @@ import java.net.DatagramPacket; import java.net.InetAddress; import java.util.HashMap; import java.util.LinkedList; +import java.util.logging.Level; -import zutil.MultiPrintStream; +import zutil.log.Logger; import zutil.network.http.HTTPHeaderParser; import zutil.network.http.HttpPrintStream; import zutil.network.threaded.ThreadedUDPNetwork; @@ -20,20 +21,22 @@ import zutil.wrapper.StringOutputStream; * @author Ziver */ public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetworkThread{ + public static final Logger logger = new Logger(); // Contains all the received services private HashMap> services_st; private HashMap services_usn; public static void main(String[] args) throws IOException{ + Logger.setGlobalLogLevel(Level.FINEST); SSDPClient ssdp = new SSDPClient(); ssdp.requestService("upnp:rootdevice"); ssdp.start(); - + for(int i=0; true ;++i){ while( i==ssdp.getServicesCount("upnp:rootdevice") ){ try{Thread.sleep(100);}catch(Exception e){} } - MultiPrintStream.out.println( "************************" ); - MultiPrintStream.out.println( ssdp.getServices("upnp:rootdevice").get(i) ); + logger.log(Level.FINEST, "************************" ); + logger.log(Level.FINEST, ""+ssdp.getServices("upnp:rootdevice").get(i) ); } } @@ -79,14 +82,13 @@ public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetwork http.setHeader("MX", "3" ); http.close(); - //MultiPrintStream.out.println("***** REQUEST: \n"+msg); + logger.log(Level.FINEST, "***** REQUEST: \n"+msg); byte[] data = msg.toString().getBytes(); DatagramPacket packet = new DatagramPacket( data, data.length, InetAddress.getByName( SSDPServer.SSDP_MULTICAST_ADDR ), SSDPServer.SSDP_PORT ); super.send( packet ); - } catch (Exception e) { e.printStackTrace(); } @@ -147,18 +149,18 @@ public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetwork */ public void receivedPacket(DatagramPacket packet, ThreadedUDPNetwork network) { HTTPHeaderParser header = new HTTPHeaderParser( new String( packet.getData() ) ); - //MultiPrintStream.out.println("*********** Recived\n"+header); + logger.log(Level.FINEST, "*********** Recived\n"+header); String usn = header.getHTTPAttribute("USN"); String st = header.getHTTPAttribute("ST"); - SSDPServiceInfo service; + StandardSSDPInfo service; // Get existing service if( services_usn.containsKey( usn )){ - service = services_usn.get( usn ); + service = (StandardSSDPInfo)services_usn.get( usn ); } // Add new service else{ - service = new SSDPServiceInfo(); + service = new StandardSSDPInfo(); services_usn.put( usn, service); if( !services_st.containsKey(st) ) services_st.put( st, new LinkedList() ); @@ -171,7 +173,7 @@ public class SSDPClient extends ThreadedUDPNetwork implements ThreadedUDPNetwork service.setExpirationTime( System.currentTimeMillis() + 1000 * getCacheTime(header.getHTTPAttribute("Cache-Control")) ); - //MultiPrintStream.out.println("*********** Recived\n"+service); + logger.log(Level.FINEST, "*********** Recived\n"+service); } private long getCacheTime(String cache_control){ diff --git a/src/zutil/network/ssdp/SSDPServer.java b/src/zutil/network/ssdp/SSDPServer.java index 45b948f..5199505 100644 --- a/src/zutil/network/ssdp/SSDPServer.java +++ b/src/zutil/network/ssdp/SSDPServer.java @@ -6,8 +6,10 @@ import java.net.InetAddress; import java.util.HashMap; import java.util.Timer; import java.util.TimerTask; +import java.util.logging.Level; import zutil.MultiPrintStream; +import zutil.log.Logger; import zutil.network.http.HTTPHeaderParser; import zutil.network.http.HttpPrintStream; import zutil.network.threaded.ThreadedUDPNetworkThread; @@ -39,6 +41,7 @@ import zutil.wrapper.StringOutputStream; * NTS: same as Man but for Notify messages */ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetworkThread{ + public static final Logger logger = new Logger(); public static final String SERVER_INFO = "SSDP Java Server by Ziver Koc"; public static final int DEFAULT_CACHE_TIME = 60*30; // 30 min public static final int BUFFER_SIZE = 512; @@ -54,7 +57,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork public static void main(String[] args) throws IOException{ SSDPServer ssdp = new SSDPServer(); - SSDPServiceInfo service = new SSDPServiceInfo(); + StandardSSDPInfo service = new StandardSSDPInfo(); service.setLocation("nowhere"); service.setST("upnp:rootdevice"); ssdp.addService(service); @@ -152,7 +155,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork String msg = new String( packet.getData() ); HTTPHeaderParser header = new HTTPHeaderParser( msg ); - //MultiPrintStream.out.println("**** Received:\n"+header); + logger.log(Level.FINEST, "**** Received:\n"+header); // ******* Respond // Check that the message is an ssdp discovery message @@ -175,7 +178,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork http.setHeader("USN", services.get(st).getUSN() ); http.close(); - //MultiPrintStream.out.println("********** Response:\n"+response); + logger.log(Level.FINEST, "********** Response:\n"+response); byte[] data = response.toString().getBytes(); packet = new DatagramPacket( data, data.length, @@ -241,7 +244,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork http.setHeader("USN", services.get(searchTarget).getUSN() ); http.close(); - //MultiPrintStream.out.println("******** Notification:\n"+msg); + logger.log(Level.FINEST, "******** Notification:\n"+msg); byte[] data = msg.toString().getBytes(); DatagramPacket packet = new DatagramPacket( data, data.length, @@ -290,7 +293,7 @@ public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetwork http.setHeader("USN", services.get(searchTarget).getUSN() ); http.close(); - //MultiPrintStream.out.println("******** ByeBye:\n"+msg); + logger.log(Level.FINEST, "******** ByeBye:\n"+msg); byte[] data = msg.toString().getBytes(); DatagramPacket packet = new DatagramPacket( data, data.length, diff --git a/src/zutil/network/ssdp/SSDPServiceInfo.java b/src/zutil/network/ssdp/SSDPServiceInfo.java index ab25b1d..7b6bc90 100644 --- a/src/zutil/network/ssdp/SSDPServiceInfo.java +++ b/src/zutil/network/ssdp/SSDPServiceInfo.java @@ -1,89 +1,35 @@ package zutil.network.ssdp; -import java.util.Date; -import java.util.UUID; - /** * This class contains information about a service from * or through the SSDP protocol * * @author Ziver */ -public class SSDPServiceInfo { - private String location; - private String st; - private String usn; - private long expiration_time; - - /** - * @param l is the value to set the Location variable - */ - public void setLocation(String l) { - location = l; - } - - /** - * @param st is the value to set the SearchTarget variable - */ - public void setST(String st) { - this.st = st; - } - - /** - * @param usn is the value to set the USN variable - */ - protected void setUSN(String usn) { - this.usn = usn; - } - - /** - * @param time sets the expiration time of values in this object - */ - protected void setExpirationTime(long time) { - expiration_time = time; - } +public interface SSDPServiceInfo { /** * @return The URL to the Service, e.g. "http://192.168.0.1:80/index.html" */ - public String getLocation(){ - return location; - } + public String getLocation(); /** * @return the Search Target, e.g. "upnp:rootdevice" */ - public String getSearchTarget(){ - return st; - } + public String getSearchTarget(); /** * @return the expiration time for the values in this object */ - public long getExpirationTime(){ - return expiration_time; - } + public long getExpirationTime(); /** * @return the USN value, e.g. "uuid:abcdefgh-7dec-11d0-a765-00a0c91e6bf6 " */ - public String getUSN(){ - if( usn==null ) - usn = genUSN(); - return usn; - } + public String getUSN(); /** - * Generates an unique USN for the service - * - * @param searchTarget is the service ST name - * @return an unique string that corresponds to the service + * @return only the USN UUID String */ - private String genUSN(){ - return "uuid:" + UUID.nameUUIDFromBytes( (st+location).getBytes() ) +"::"+st; - } - - public String toString(){ - return "USN: "+usn+"\nLocation: "+location+"\nST: "+st+"\nExpiration-Time: "+new Date(expiration_time); - } + public String getUUID(); } diff --git a/src/zutil/network/ssdp/StandardSSDPInfo.java b/src/zutil/network/ssdp/StandardSSDPInfo.java new file mode 100644 index 0000000..e07d840 --- /dev/null +++ b/src/zutil/network/ssdp/StandardSSDPInfo.java @@ -0,0 +1,98 @@ +package zutil.network.ssdp; + +import java.util.Date; +import java.util.UUID; + +/** + * This class contains information about a service from + * or through the SSDP protocol + * + * @author Ziver + */ +public class StandardSSDPInfo implements SSDPServiceInfo{ + private String location; + private String st; + private String usn; + private long expiration_time; + + /** + * @param l is the value to set the Location variable + */ + public void setLocation(String l) { + location = l; + } + + /** + * @param st is the value to set the SearchTarget variable + */ + public void setST(String st) { + this.st = st; + } + + /** + * @param usn is the value to set the USN variable + */ + protected void setUSN(String usn) { + this.usn = usn; + } + + /** + * @param time sets the expiration time of values in this object + */ + protected void setExpirationTime(long time) { + expiration_time = time; + } + + /** + * @return The URL to the Service, e.g. "http://192.168.0.1:80/index.html" + */ + public String getLocation(){ + return location; + } + + /** + * @return the Search Target, e.g. "upnp:rootdevice" + */ + public String getSearchTarget(){ + return st; + } + + /** + * @return the expiration time for the values in this object + */ + public long getExpirationTime(){ + return expiration_time; + } + + /** + * @return the USN value, e.g. "uuid:abcdefgh-7dec-11d0-a765-00a0c91e6bf6 " + */ + public String getUSN(){ + if( usn==null ) + usn = genUSN(); + return usn+"::"+st; + } + + /** + * @return only the USN UUID String + */ + public String getUUID(){ + if( usn==null ) + usn = genUSN(); + return usn; + } + + /** + * Generates an unique USN for the service + * + * @param searchTarget is the service ST name + * @return an unique string that corresponds to the service + */ + private String genUSN(){ + return "uuid:" + UUID.nameUUIDFromBytes( (st+location+Math.random()).getBytes() ); + } + + public String toString(){ + return "USN: "+usn+"\nLocation: "+location+"\nST: "+st+"\nExpiration-Time: "+new Date(expiration_time); + } +} diff --git a/src/zutil/test/UPnPServerTest.java b/src/zutil/test/UPnPServerTest.java new file mode 100644 index 0000000..57a9d42 --- /dev/null +++ b/src/zutil/test/UPnPServerTest.java @@ -0,0 +1,42 @@ +package zutil.test; + +import java.io.File; +import java.io.IOException; +import java.util.logging.Level; + +import javax.wsdl.WSDLException; + +import zutil.MultiPrintStream; +import zutil.log.Logger; +import zutil.network.http.HttpServer; +import zutil.network.http.soap.SOAPHttpPage; +import zutil.network.ssdp.SSDPServer; +import zutil.network.upnp.UPnPMediaServer; +import zutil.network.upnp.services.UPnPContentDirectory; + +public class UPnPServerTest { + + public static void main(String[] args) throws IOException, WSDLException{ + //Logger.setGlobalLogLevel(Level.FINEST); + + UPnPMediaServer upnp = new UPnPMediaServer("http://192.168.0.60:8080/"); + MultiPrintStream.out.println("UPNP Server running"); + + UPnPContentDirectory cds = new UPnPContentDirectory(new File("C:\\Users\\Ziver\\Desktop\\lan")); + + HttpServer http = new HttpServer("http://192.168.0.60/", 8080); + //http.setDefaultPage(upnp); + http.setPage("/RootDesc", upnp ); + http.setPage("/SCP/ContentDir", cds ); + SOAPHttpPage soap = new SOAPHttpPage("Action/ContentDir", cds); + soap.enableSession(false); + http.setPage("/Action/ContentDir", soap ); + http.start(); + MultiPrintStream.out.println("HTTP Server running"); + + SSDPServer ssdp = new SSDPServer(); + ssdp.addService( upnp ); + ssdp.start(); + MultiPrintStream.out.println("SSDP Server running"); + } +} diff --git a/src/zutil/ui/wizard/Wizard.java b/src/zutil/ui/wizard/Wizard.java index 705e339..bcdbd3f 100644 --- a/src/zutil/ui/wizard/Wizard.java +++ b/src/zutil/ui/wizard/Wizard.java @@ -32,7 +32,7 @@ import zutil.ui.wizard.listener.BlockingWizardListener; * @author Ziver */ public class Wizard implements ActionListener{ - public static final boolean DEBUG = true; + public static final boolean DEBUG = false; private static final long serialVersionUID = 1L; /** Some defoult backgrounds for the sidebar */ diff --git a/src/zutil/wrapper/StringOutputStream.java b/src/zutil/wrapper/StringOutputStream.java index 3e2737e..7a3bbc9 100644 --- a/src/zutil/wrapper/StringOutputStream.java +++ b/src/zutil/wrapper/StringOutputStream.java @@ -1,6 +1,5 @@ package zutil.wrapper; -import java.io.IOException; import java.io.OutputStream; /** @@ -21,7 +20,7 @@ public class StringOutputStream extends OutputStream{ } @Override - public void write(int b) throws IOException { + public void write(int b) { buffer.append( b ); }