diff options
author | Matthew Newhook <matthew@zeroc.com> | 2008-08-15 14:47:14 -0230 |
---|---|---|
committer | Matthew Newhook <matthew@zeroc.com> | 2008-08-15 14:47:14 -0230 |
commit | 7b735386b10c464a39d4e0298c99a33f6ae038fe (patch) | |
tree | 7f2e9ee218038b3b3883e3827b82ec70533aff8f /java/demo | |
parent | Fix more conflicts. (diff) | |
download | ice-7b735386b10c464a39d4e0298c99a33f6ae038fe.tar.bz2 ice-7b735386b10c464a39d4e0298c99a33f6ae038fe.tar.xz ice-7b735386b10c464a39d4e0298c99a33f6ae038fe.zip |
added first cut at JDBC demo.
Diffstat (limited to 'java/demo')
21 files changed, 2961 insertions, 0 deletions
diff --git a/java/demo/Database/.DS_Store b/java/demo/Database/.DS_Store Binary files differnew file mode 100644 index 00000000000..ca6143d6f15 --- /dev/null +++ b/java/demo/Database/.DS_Store diff --git a/java/demo/Database/library/BookI.java b/java/demo/Database/library/BookI.java new file mode 100644 index 00000000000..ef9df529608 --- /dev/null +++ b/java/demo/Database/library/BookI.java @@ -0,0 +1,435 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +import Demo.*; + +// This servant is a default servant. The book identity is retreived +// from Ice.Current object. +class BookI extends _BookDisp +{ + public void + ice_ping(Ice.Current current) + { + Integer id = new Integer(current.id.name); + + java.sql.Connection conn = _pool.acquire(); + try + { + java.sql.PreparedStatement stmt = null; + try + { + stmt = conn.prepareStatement("SELECT * FROM books WHERE id = ?"); + stmt.setInt(1, id); + java.sql.ResultSet rs = stmt.executeQuery(); + if(!rs.next()) + { + throw new Ice.ObjectNotExistException(); + } + } + finally + { + if(stmt != null) + { + stmt.close(); + } + } + } + catch(java.sql.SQLException e) + { + // Log the error, and raise an UnknownException. + error(e); + Ice.UnknownException ex = new Ice.UnknownException(); + ex.initCause(e); + throw ex; + } + finally + { + _pool.release(conn); + } + } + + public BookDescription + describe(Ice.Current current) + { + Integer id = new Integer(current.id.name); + + java.sql.Connection conn = _pool.acquire(); + try + { + java.sql.PreparedStatement stmt = null; + try + { + stmt = conn.prepareStatement("SELECT * FROM books WHERE id = ?"); + stmt.setInt(1, id); + java.sql.ResultSet rs = stmt.executeQuery(); + if(!rs.next()) + { + throw new Ice.ObjectNotExistException(); + } + return extractDescription(conn, rs, current.adapter); + } + finally + { + if(stmt != null) + { + stmt.close(); + } + } + } + catch(java.sql.SQLException e) + { + // Log the error, and raise an UnknownException. + error(e); + Ice.UnknownException ex = new Ice.UnknownException(); + ex.initCause(e); + throw ex; + } + finally + { + _pool.release(conn); + } + } + + public void + destroy(Ice.Current current) + { + Integer id = new Integer(current.id.name); + java.sql.Connection conn = _pool.acquire(); + try + { + java.sql.PreparedStatement stmt = null; + try + { + stmt = conn.prepareStatement("DELETE FROM books WHERE id = ?"); + stmt.setInt(1, id); + int count = stmt.executeUpdate(); + if(count == 0) + { + throw new Ice.ObjectNotExistException(); + } + } + finally + { + if(stmt != null) + { + stmt.close(); + } + } + } + catch(java.sql.SQLException e) + { + // Log the error, and raise an UnknownException. + error(e); + Ice.UnknownException ex = new Ice.UnknownException(); + ex.initCause(e); + throw ex; + } + finally + { + _pool.release(conn); + } + } + + public String + getRenter(Ice.Current current) + throws BookNotRentedException + { + Integer id = new Integer(current.id.name); + java.sql.Connection conn = _pool.acquire(); + try + { + java.sql.PreparedStatement stmt = null; + try + { + stmt = conn.prepareStatement("SELECT * FROM books WHERE id = ?"); + stmt.setInt(1, id); + java.sql.ResultSet rs = stmt.executeQuery(); + if(!rs.next()) + { + throw new Ice.ObjectNotExistException(); + } + + int renterId = rs.getInt("renter_id"); + if(rs.wasNull()) + { + throw new BookNotRentedException(); + } + stmt.close(); + stmt = null; + + stmt = conn.prepareStatement("SELECT * FROM customers WHERE id = ?"); + stmt.setInt(1, renterId); + rs = stmt.executeQuery(); + boolean next = rs.next(); + assert next; + return rs.getString("name"); + } + finally + { + if(stmt != null) + { + stmt.close(); + } + } + } + catch(java.sql.SQLException e) + { + // Log the error, and raise an UnknownException. + error(e); + Ice.UnknownException ex = new Ice.UnknownException(); + ex.initCause(e); + throw ex; + } + finally + { + _pool.release(conn); + } + } + + public void + rentBook(String name, Ice.Current current) + throws BookRentedException + { + java.sql.Connection conn = _pool.acquire(); + Integer id = new Integer(current.id.name); + try + { + conn.setAutoCommit(false); + java.sql.PreparedStatement stmt = null; + try + { + stmt = conn.prepareStatement("SELECT * FROM books WHERE id = ?"); + stmt.setInt(1, id); + java.sql.ResultSet rs = stmt.executeQuery(); + if(!rs.next()) + { + throw new Ice.ObjectNotExistException(); + } + + rs.getInt("renter_id"); + if(!rs.wasNull()) + { + throw new BookRentedException(); + } + stmt.close(); + stmt = null; + + stmt = conn.prepareStatement("SELECT * FROM customers WHERE name = ?"); + stmt.setString(1, name); + rs = stmt.executeQuery(); + + Integer renterId = null; + if(rs.next()) + { + renterId = rs.getInt("id"); + assert !rs.next(); + } + else + { + stmt.close(); + stmt = null; + + stmt = conn.prepareStatement("INSERT into customers (name) VALUES(?)", + java.sql.Statement.RETURN_GENERATED_KEYS); + stmt.setString(1, name); + int count = stmt.executeUpdate(); + assert count == 1; + rs = stmt.getGeneratedKeys(); + if(!rs.next()) + { + // ERROR: + } + renterId = rs.getInt(1); + } + stmt.close(); + stmt = null; + + stmt = conn.prepareStatement("UPDATE books SET renter_id = ? WHERE id = ?"); + stmt.setInt(1, renterId); + stmt.setInt(2, id); + int count = stmt.executeUpdate(); + assert count == 1; + + // Commit the transaction. + conn.commit(); + } + catch(RuntimeException e) + { + // Rollback any updates. + conn.rollback(); + throw e; + } + catch(java.sql.SQLException e) + { + // Rollback any updates. + conn.rollback(); + throw e; + } + finally + { + if(stmt != null) + { + stmt.close(); + } + } + } + catch(java.sql.SQLException e) + { + // Log the error, and raise an UnknownException. + error(e); + Ice.UnknownException ex = new Ice.UnknownException(); + ex.initCause(e); + throw ex; + } + finally + { + try + { + conn.setAutoCommit(true); + } + catch(java.sql.SQLException e) + { + // Ignore + } + _pool.release(conn); + } + } + + public void + returnBook(Ice.Current current) + throws BookNotRentedException + { + Integer id = new Integer(current.id.name); + java.sql.Connection conn = _pool.acquire(); + try + { + java.sql.PreparedStatement stmt = null; + try + { + stmt = conn.prepareStatement("SELECT * FROM books WHERE id = ?"); + stmt.setInt(1, id); + java.sql.ResultSet rs = stmt.executeQuery(); + if(!rs.next()) + { + throw new Ice.ObjectNotExistException(); + } + Integer renterId = rs.getInt("renter_id"); + if(rs.wasNull()) + { + throw new BookNotRentedException(); + } + stmt.close(); + stmt = null; + + stmt = conn.prepareStatement("UPDATE books SET renter_id = NULL WHERE id = ?"); + stmt.setInt(1, id); + int count = stmt.executeUpdate(); + assert count == 1; + } + finally + { + if(stmt != null) + { + stmt.close(); + } + } + } + catch(java.sql.SQLException e) + { + // Log the error, and raise an UnknownException. + error(e); + Ice.UnknownException ex = new Ice.UnknownException(); + ex.initCause(e); + throw ex; + } + finally + { + _pool.release(conn); + } + } + + BookI(Ice.Logger logger, ConnectionPool pool) + { + _logger = logger; + _pool = pool; + } + + static Ice.Identity + createIdentity(Integer bookId) + { + Ice.Identity id = new Ice.Identity(); + id.category = "book"; + id.name = bookId.toString(); + return id; + } + + static BookDescription + extractDescription(java.sql.Connection conn, java.sql.ResultSet rs, Ice.ObjectAdapter adapter) + throws java.sql.SQLException + { + Integer id = rs.getInt("id"); + + BookDescription desc = new BookDescription(); + desc.isbn = rs.getString("isbn"); + desc.title = rs.getString("title"); + desc.authors = new java.util.LinkedList<String>(); + desc.proxy = BookPrxHelper.uncheckedCast(adapter.createProxy(createIdentity(id))); + + java.sql.PreparedStatement stmt = null; + try + { + // Query for the rentedBy. + Integer renterId = rs.getInt("renter_id"); + if(!rs.wasNull()) + { + stmt = conn.prepareStatement("SELECT * FROM customers WHERE id = ?"); + stmt.setInt(1, renterId); + java.sql.ResultSet customerRS = stmt.executeQuery(); + boolean next = customerRS.next(); + assert next; + desc.rentedBy = customerRS.getString(2); + + stmt.close(); + stmt = null; + } + + // Query for the authors. + stmt = conn.prepareStatement("SELECT * FROM authors INNER JOIN authors_books ON " + + "authors.id=authors_books.author_id AND authors_books.book_id = ?"); + stmt.setInt(1, id); + java.sql.ResultSet authorRS = stmt.executeQuery(); + while(authorRS.next()) + { + desc.authors.add(authorRS.getString("name")); + } + } + finally + { + if(stmt != null) + { + stmt.close(); + } + } + + return desc; + } + + private void + error(Exception ex) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + _logger.error("BookI: error:\n" + sw.toString()); + } + + private Ice.Logger _logger; + private ConnectionPool _pool; +} diff --git a/java/demo/Database/library/Client.java b/java/demo/Database/library/Client.java new file mode 100644 index 00000000000..8a181ef1519 --- /dev/null +++ b/java/demo/Database/library/Client.java @@ -0,0 +1,47 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +public class Client extends Ice.Application +{ + class ShutdownHook extends Thread + { + public void + run() + { + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + + public int + run(String[] args) + { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + + return RunParser.runParser(appName(), args, communicator()); + } + + static public void + main(String[] args) + { + Client app = new Client(); + app.main("demo.Freeze.library.Client", args, "config.client"); + } +} diff --git a/java/demo/Database/library/ConnectionPool.java b/java/demo/Database/library/ConnectionPool.java new file mode 100644 index 00000000000..38eed101095 --- /dev/null +++ b/java/demo/Database/library/ConnectionPool.java @@ -0,0 +1,133 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +class ConnectionPool +{ + public + ConnectionPool(Ice.Logger logger, String url, String username, String password, int numConnections) + throws java.sql.SQLException + { + _logger = logger; + _url = url; + _username = username; + _password = password; + + _nconnections = numConnections; + while(numConnections-- > 0) + { + _connections.add(java.sql.DriverManager.getConnection (url, username, password)); + } + } + + public synchronized void + destroy() + { + _destroyed = true; + while(_connections.size() != _nconnections) + { + try + { + wait(); + } + catch(InterruptedException e) + { + } + } + + while(_connections.isEmpty()) + { + java.sql.Connection conn = _connections.removeFirst(); + try + { + conn.close(); + } + catch(java.sql.SQLException e) + { + } + } + } + + public synchronized java.sql.Connection + acquire() + { + while(_connections.isEmpty() && !_destroyed) + { + try + { + wait(); + } + catch(InterruptedException e) + { + } + } + if(_destroyed) + { + return null; + } + java.sql.Connection conn = _connections.removeFirst(); + + try + { + boolean closed = conn.isClosed(); + if(closed) + { + _logger.warning("ConnectionPool: lost connection to database"); + conn = null; + } + } + catch(java.sql.SQLException e) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); + _logger.warning("ConnectionPool: lost connection to database:\n" + sw.toString()); + + conn = null; + } + + // If the connection has been closed, or is otherwise invalid + // re-establish the connection. + while(conn == null) + { + _logger.trace("ConnectionPool", "establishing new database connection"); + try + { + conn = java.sql.DriverManager.getConnection (_url, _username, _password); + } + catch(java.sql.SQLException e) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); + _logger.warning("ConnectionPool: database connection failed:\n" + sw.toString()); + } + } + return conn; + } + + public synchronized void + release(java.sql.Connection connection) + { + if(connection != null) + { + _connections.add(connection); + notifyAll(); + } + } + + Ice.Logger _logger; + private String _url; + private String _username; + private String _password; + private java.util.LinkedList<java.sql.Connection> _connections = new java.util.LinkedList<java.sql.Connection>(); + private boolean _destroyed = false; + private int _nconnections; +} diff --git a/java/demo/Database/library/Grammar.java b/java/demo/Database/library/Grammar.java new file mode 100644 index 00000000000..2b180cf139e --- /dev/null +++ b/java/demo/Database/library/Grammar.java @@ -0,0 +1,167 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +class Grammar +{ + Grammar(Parser p) + { + _parser = p; + _scanner = new Scanner(_parser); + } + + void + parse() + { + while(true) + { + try + { + _token = _scanner.nextToken(); + if(_token == null) + { + return; + } + else if(_token.type == Token.TOK_SEMI) + { + // Continue + } + else if(_token.type == Token.TOK_HELP) + { + _token = _scanner.nextToken(); + if(_token.type != Token.TOK_SEMI) + { + throw new ParseError("Expected ';'"); + } + + _parser.usage(); + } + else if(_token.type == Token.TOK_EXIT) + { + _token = _scanner.nextToken(); + if(_token.type != Token.TOK_SEMI) + { + throw new ParseError("Expected ';'"); + } + + return; + } + else if(_token.type == Token.TOK_ADD_BOOK) + { + java.util.List s = strings(); + if(_token.type != Token.TOK_SEMI) + { + throw new ParseError("Expected ';'"); + } + _parser.addBook(s); + } + else if(_token.type == Token.TOK_FIND_ISBN) + { + java.util.List s = strings(); + if(_token.type != Token.TOK_SEMI) + { + throw new ParseError("Expected ';'"); + } + _parser.findIsbn(s); + } + else if(_token.type == Token.TOK_FIND_AUTHORS) + { + java.util.List s = strings(); + if(_token.type != Token.TOK_SEMI) + { + throw new ParseError("Expected ';'"); + } + _parser.findAuthors(s); + } + else if(_token.type == Token.TOK_NEXT_FOUND_BOOK) + { + _token = _scanner.nextToken(); + if(_token.type != Token.TOK_SEMI) + { + throw new ParseError("Expected ';'"); + } + + _parser.nextFoundBook(); + } + else if(_token.type == Token.TOK_PRINT_CURRENT) + { + _token = _scanner.nextToken(); + if(_token.type != Token.TOK_SEMI) + { + throw new ParseError("Expected ';'"); + } + + _parser.printCurrent(); + } + else if(_token.type == Token.TOK_RENT_BOOK) + { + java.util.List s = strings(); + if(_token.type != Token.TOK_SEMI) + { + throw new ParseError("Expected ';'"); + } + _parser.rentCurrent(s); + } + else if(_token.type == Token.TOK_RETURN_BOOK) + { + _token = _scanner.nextToken(); + if(_token.type != Token.TOK_SEMI) + { + throw new ParseError("Expected ';'"); + } + _parser.returnCurrent(); + } + else if(_token.type == Token.TOK_REMOVE_CURRENT) + { + _token = _scanner.nextToken(); + if(_token.type != Token.TOK_SEMI) + { + throw new ParseError("Expected ';'"); + } + + _parser.removeCurrent(); + } + else + { + _parser.error("parse error"); + } + } + catch(ParseError e) + { + _parser.error("Parse error: " + e.getMessage()); + } + } + } + + private java.util.List + strings() + { + java.util.List l = new java.util.ArrayList(); + while(true) + { + _token = _scanner.nextToken(); + if(_token.type != Token.TOK_STRING) + { + return l; + } + l.add(_token.value); + } + } + + static private class ParseError extends RuntimeException + { + ParseError(String msg) + { + super(msg); + } + } + + private Parser _parser; + private Scanner _scanner; + private Token _token; +} diff --git a/java/demo/Database/library/Library.ice b/java/demo/Database/library/Library.ice new file mode 100644 index 00000000000..ba4b5a9b7dc --- /dev/null +++ b/java/demo/Database/library/Library.ice @@ -0,0 +1,300 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#ifndef LIBRARY_ICE +#define LIBRARY_ICE + +#include <Ice/BuiltinSequences.ice> + +module Demo +{ + +/** + * + * This exception is raised if the book already exists. + * + **/ +exception BookExistsException +{ +}; + +/** + * + * This exception is raised if a book has already been rented. + * + **/ +exception BookRentedException +{ +}; + +/** + * + * This exception is raised if the book has not been rented. + * + **/ +exception BookNotRentedException +{ +}; + +/** + * + * This exception is raised if a query has no results. + * + **/ +exception NoResultsException +{ +}; + +/** + * + * This exception is raised if a query is already active. + * + **/ +exception QueryActiveException +{ +}; + +/** Forward declaration for the interface Book. */ +interface Book; + +/** + * + * A description of a book. + * + **/ +struct BookDescription +{ + /** The ISBN number of the book. */ + string isbn; + + /** The title of the book. */ + string title; + + /** The authors of the book. */ + ["java:type:java.util.LinkedList<String>:java.util.List<String>"] Ice::StringSeq authors; + + /** The customer name of the renter. */ + string rentedBy; + + /** A proxy to the associated book. */ + Book* proxy; +}; + +/** A sequence of book descriptions. */ +["java:type:java.util.LinkedList<BookDescription>:java.util.List<BookDescription>"] +sequence<BookDescription> BookDescriptionSeq; + +/** + * + * This interface represents a book. + * + **/ +interface Book +{ + /** + * + * Get a description of the book. + * + * @return The book description. + * + **/ + idempotent BookDescription describe(); + + /** + * + * Rent the book to the specified customer. + * + * @param customer The customer. + * + * @throws BookRentedException Raised if the book has already been + * rented. + * + **/ + void rentBook(string name) + throws BookRentedException; + + /** + * + * Get the renter. + * + * @return The current rental customer. + * + * @throws BookNotRentedException Raised if the book is not + * currently rented. + * + **/ + idempotent string getRenter() + throws BookNotRentedException; + + /** + * + * Return the book. + * + * @throws BookNotRentedException Raised if the book is not + * currently rented. + * + **/ + void returnBook() + throws BookNotRentedException; + + /** + * + * Destroy the book. + * + **/ + void destroy(); +}; + +/** + * + * Interface to get query results. + * + **/ +interface BookQueryResult +{ + /** + * + * Get more query results. + * + * @param n The maximum number of results to return. + * + * @param destroyed There are no more results, and the query has + * been destroyed. + * + * @returns A sequence of up to n results. + * + **/ + BookDescriptionSeq next(int n, out bool destroyed); + + /** + * + * Destroy the query result. + * + **/ + void destroy(); +}; + +/** + * + * An interface to the library. + * + **/ +interface Library +{ + /** + * + * Query based on isbn number. The query is a partial match of the + * isbn number. + * + * @param isbn The ISBN number. + * + * @param first The first book description. + * + * @param result The remainder of the results. If there are no + * further results, a null proxy is returned. + + * @throws NoResultsException Raised if there are no results. + * + * @throws QueryActiveException Raised if an existing query is active. + * + **/ + void queryByIsbn(string isbn, out BookDescription first, out BookQueryResult* result) + throws QueryActiveException, NoResultsException; + + /** + * + * Query based on the author name. The query is a partial match of + * the authors name. + * + * @param author The authors name. + * + * @param first The first book description. + * + * @param result The remainder of the results. If there are no + * further results, a null proxy is returned. + + * @throws NoResultsException Raised if there are no results. + * + * @throws QueryActiveException Raised if an existing query is active. + * + **/ + void queryByAuthor(string author, out BookDescription first, out BookQueryResult* result) + throws QueryActiveException, NoResultsException; + + /** + * + * Create a book with the given description. + * + * @param description The book description. + * + * @return A proxy for the new book. + * + * @throws BookExistsException Raised if a book with the same ISBN + * number already exists. + * + **/ + Book* createBook(string isbn, string title, + ["java:type:java.util.LinkedList<String>:java.util.List<String>"] Ice::StringSeq authors) + throws BookExistsException; +}; + +/** + * + * The session object. This is used to retrieve a per-session library + * on behalf of the client. If the session is not refreshed on a + * periodic basis, it will be automatically destroyed. + * + */ +interface Session +{ + /** + * + * Get the library object. + * + * @return A proxy for the new library. + * + **/ + Library* getLibrary(); + + /** + * + * Refresh a session. If a session is not refreshed on a regular + * basis by the client, it will be automatically destroyed. + * + **/ + idempotent void refresh(); + + /** + * + * Destroy the session. + * + **/ + void destroy(); +}; + +/** + * + * Interface to create new sessions. + * + **/ +interface SessionFactory +{ + /** + * + * Create a session. + * + * @return A proxy to the session. + * + **/ + Session* create(); +}; + +}; + +#endif diff --git a/java/demo/Database/library/LibraryI.java b/java/demo/Database/library/LibraryI.java new file mode 100644 index 00000000000..99c2f7fddc8 --- /dev/null +++ b/java/demo/Database/library/LibraryI.java @@ -0,0 +1,488 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +import Demo.*; + +// Per-session library object. +class LibraryI extends _LibraryDisp +{ + class BookQueryResultI extends _BookQueryResultDisp + { + // The query result owns the java.sql.Connection object until + // destroyed. + BookQueryResultI(java.sql.Connection conn, java.sql.PreparedStatement stmt, java.sql.ResultSet rs) + { + _conn = conn; + _stmt = stmt; + _rs = rs; + } + + synchronized public java.util.List<BookDescription> + next(int n, Ice.BooleanHolder destroyed, Ice.Current current) + { + if(_destroyed) + { + throw new Ice.ObjectNotExistException(); + } + destroyed.value = false; + java.util.List<BookDescription> l = new java.util.LinkedList<BookDescription>(); + if(n <= 0) + { + return l; + } + boolean next = true; + try + { + for(int i = 0; i < n && next; ++i) + { + l.add(BookI.extractDescription(_conn, _rs, current.adapter)); + next = _rs.next(); + } + } + catch(java.sql.SQLException e) + { + // Log the error, and raise an UnknownException. + error(e); + Ice.UnknownException ex = new Ice.UnknownException(); + ex.initCause(e); + throw ex; + } + + if(!next) + { + try + { + destroyed.value = true; + destroy(current); + } + catch(Exception e) + { + // Ignore. + } + } + + return l; + } + + synchronized public void + destroy(Ice.Current current) + { + if(_destroyed) + { + throw new Ice.ObjectNotExistException(); + } + _destroyed = true; + + try + { + // Closing a statement closes the associated + // java.sql.ResultSet. + _stmt.close(); + } + catch(java.sql.SQLException e) + { + // Log the error, but otherwise ignore the exception. + error(e); + } + _pool.release(_conn); + + current.adapter.remove(current.id); + } + + // Called on application shutdown by the Library. + synchronized private void + shutdown() + { + if(!_destroyed) + { + _destroyed = true; + + try + { + // Closing a statement closes the associated + // java.sql.ResultSet. + _stmt.close(); + } + catch(java.sql.SQLException e) + { + // Log the error, but otherwise ignore the + // exception. + error(e); + } + _pool.release(_conn); + } + } + + private java.sql.Connection _conn; + private java.sql.PreparedStatement _stmt; + private java.sql.ResultSet _rs; + private boolean _destroyed = false; + } + + synchronized public void + queryByIsbn(String isbn, BookDescriptionHolder first, BookQueryResultPrxHolder result, Ice.Current current) + throws QueryActiveException, NoResultsException + { + reapQuery(); + + java.sql.Connection conn = _pool.acquire(); + try + { + java.sql.PreparedStatement stmt = null; + try + { + stmt = conn.prepareStatement("SELECT * FROM books WHERE isbn LIKE ?"); + stmt.setString(1, "%" + isbn + "%"); + java.sql.ResultSet rs = stmt.executeQuery(); + if(!rs.next()) + { + throw new NoResultsException(); + } + + first.value = BookI.extractDescription(conn, rs, current.adapter); + if(rs.next()) + { + _queryImpl = new BookQueryResultI(conn, stmt, rs); + result.value = BookQueryResultPrxHelper.uncheckedCast(current.adapter.addWithUUID(_queryImpl)); + _query = result.value; + // The java.sql.Connection, result set and + // statement are now owned by the book query. Set + // to null so they are not prematurely released. + conn = null; + stmt = null; + } + } + finally + { + if(stmt != null) + { + // Closing a statement closes the associated + // java.sql.ResultSet. + stmt.close(); + } + } + } + catch(java.sql.SQLException e) + { + // Log the error, and raise an UnknownException. + error(e); + Ice.UnknownException ex = new Ice.UnknownException(); + ex.initCause(e); + throw ex; + } + finally + { + _pool.release(conn); + } + } + + synchronized public void + queryByAuthor(String author, BookDescriptionHolder first, BookQueryResultPrxHolder result, Ice.Current current) + throws QueryActiveException, NoResultsException + { + reapQuery(); + + java.sql.Connection conn = _pool.acquire(); + try + { + java.sql.PreparedStatement stmt = null; + try + { + // Find each of the authors. + stmt = conn.prepareStatement("SELECT * FROM authors WHERE name LIKE ?"); + stmt.setString(1, "%" + author + "%"); + java.sql.ResultSet rs = stmt.executeQuery(); + if(!rs.next()) + { + throw new NoResultsException(); + } + + // Build a query that finds all books by these set of + // authors. + StringBuffer sb = new StringBuffer("SELECT * FROM books INNER JOIN authors_books ON " + + "books.id=authors_books.book_id AND ("); + boolean front = true; + do + { + if(!front) + { + sb.append(" OR "); + } + front = false; + sb.append("authors_books.author_id="); + sb.append(rs.getInt("id")); + } + while(rs.next()); + sb.append(")"); + + stmt.close(); + stmt = null; + + // Execute the query. + stmt = conn.prepareStatement(sb.toString()); + rs = stmt.executeQuery(); + if(!rs.next()) + { + throw new NoResultsException(); + } + + first.value = BookI.extractDescription(conn, rs, current.adapter); + if(rs.next()) + { + _queryImpl = new BookQueryResultI(conn, stmt, rs); + result.value = BookQueryResultPrxHelper.uncheckedCast(current.adapter.addWithUUID(_queryImpl)); + _query = result.value; + // The java.sql.Connection, result set and + // statement are now owned by the book query. Set + // to null so they are not prematurely released. + stmt = null; + conn = null; + } + } + finally + { + // Closing a statement closes the associated + // java.sql.ResultSet. + if(stmt != null) + { + stmt.close(); + } + } + } + catch(java.sql.SQLException e) + { + // Log the error, and raise an UnknownException. + error(e); + Ice.UnknownException ex = new Ice.UnknownException(); + ex.initCause(e); + throw ex; + } + finally + { + _pool.release(conn); + } + } + + synchronized public BookPrx + createBook(String isbn, String title, java.util.List<String> authors, Ice.Current current) + throws BookExistsException + { + java.sql.Connection conn = _pool.acquire(); + try + { + conn.setAutoCommit(false); + java.sql.PreparedStatement stmt = null; + try + { + stmt = conn.prepareStatement("SELECT * FROM books WHERE isbn = ?"); + stmt.setString(1, isbn); + java.sql.ResultSet rs = stmt.executeQuery(); + if(rs.next()) + { + throw new BookExistsException(); + } + + stmt.close(); + stmt = null; + + // + // First convert the authors string to an id set. + // + java.util.List<Integer> authIds = new java.util.LinkedList<Integer>(); + java.util.Iterator<String> p = authors.iterator(); + while(p.hasNext()) + { + String author = p.next(); + + Integer id; + stmt = conn.prepareStatement("SELECT * FROM authors WHERE name = ?"); + stmt.setString(1, author); + rs = stmt.executeQuery(); + if(rs.next()) + { + // If there is a result, then the database + // already contains this author. + id = rs.getInt(1); + assert !rs.next(); + } + else + { + stmt.close(); + stmt = null; + + // Otherwise, create a new author record. + stmt = conn.prepareStatement("INSERT INTO authors (name) VALUES(?)", + java.sql.Statement.RETURN_GENERATED_KEYS); + stmt.setString(1, author); + int count = stmt.executeUpdate(); + assert count == 1; + rs = stmt.getGeneratedKeys(); + boolean next = rs.next(); + assert next; + id = rs.getInt(1); + } + + stmt.close(); + stmt = null; + + // Add the new id to the list of ids. + authIds.add(id); + } + + // Create the new book. + stmt = conn.prepareStatement("INSERT INTO books (isbn, title) VALUES(?, ?)", + java.sql.Statement.RETURN_GENERATED_KEYS); + stmt.setString(1, isbn); + stmt.setString(2, title); + int count = stmt.executeUpdate(); + assert count == 1; + + rs = stmt.getGeneratedKeys(); + boolean next = rs.next(); + assert next; + Integer bookId = rs.getInt(1); + + stmt.close(); + stmt = null; + + // Create new authors_books records. + java.util.Iterator<Integer> q = authIds.iterator(); + while(q.hasNext()) + { + stmt = conn.prepareStatement("INSERT INTO authors_books (book_id, author_id) VALUES(?, ?)"); + stmt.setInt(1, bookId); + stmt.setInt(2, q.next()); + count = stmt.executeUpdate(); + assert count == 1; + + stmt.close(); + stmt = null; + } + + // Commit the transaction. + conn.commit(); + + return BookPrxHelper.uncheckedCast(current.adapter.createProxy(BookI.createIdentity(bookId))); + } + catch(RuntimeException e) + { + // Rollback any updates. + conn.rollback(); + throw e; + } + catch(java.sql.SQLException e) + { + // Rollback any updates. + conn.rollback(); + throw e; + } + finally + { + if(stmt != null) + { + stmt.close(); + } + } + } + catch(java.sql.SQLException e) + { + // Log the error, and raise an UnknownException. + error(e); + Ice.UnknownException ex = new Ice.UnknownException(); + ex.initCause(e); + throw ex; + } + finally + { + try + { + conn.setAutoCommit(true); + } + catch(java.sql.SQLException e) + { + // Ignore + } + _pool.release(conn); + } + } + + LibraryI(Ice.Logger logger, ConnectionPool pool) + { + _logger = logger; + _pool = pool; + } + + // Called when the session is destroyed. + synchronized void + destroy() + { + if(_query != null) + { + try + { + _query.destroy(); + } + catch(Ice.ObjectNotExistException e) + { + } + _query = null; + _queryImpl = null; + } + } + + // Called on application shutdown. + synchronized void + shutdown() + { + if(_queryImpl != null) + { + _queryImpl.shutdown(); + _queryImpl = null; + _query = null; + } + } + + private void + error(Exception ex) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + _logger.error("LibraryI: error:\n" + sw.toString()); + } + + private void + reapQuery() + throws QueryActiveException + { + if(_query != null) + { + try + { + _query.ice_ping(); + } + catch(Ice.ObjectNotExistException e) + { + _query = null; + _queryImpl = null; + } + + if(_query != null) + { + throw new QueryActiveException(); + } + } + } + + private Ice.Logger _logger; + private ConnectionPool _pool; + private BookQueryResultPrx _query = null; + private BookQueryResultI _queryImpl = null; +} diff --git a/java/demo/Database/library/Parser.java b/java/demo/Database/library/Parser.java new file mode 100644 index 00000000000..be4f19ec6fe --- /dev/null +++ b/java/demo/Database/library/Parser.java @@ -0,0 +1,354 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +import Demo.*; + +class Parser +{ + Parser(Ice.Communicator communicator, LibraryPrx library) + { + _library = library; + } + + void + usage() + { + System.err.print( + "help Print this message.\n" + + "exit, quit Exit this program.\n" + + "add isbn title authors Create new book.\n" + + "isbn NUMBER Find the book with given ISBN number.\n" + + "authors NAME Find all books by the given authors.\n" + + "next Set the current book to the next one that was found.\n" + + "current Display the current book.\n" + + "rent NAME Rent the current book for customer NAME.\n" + + "return Return the currently rented book.\n" + + "remove Permanently remove the current book from the library.\n"); + } + + void + addBook(java.util.List args) + { + if(args.size() != 3) + { + error("`add' requires at exactly three arguments (type `help' for more info)"); + return; + } + + try + { + String isbn = (String)args.get(0); + String title = (String)args.get(1); + + java.util.List<String> authors = new java.util.LinkedList<String>(); + java.util.StringTokenizer st = new java.util.StringTokenizer((String)args.get(2), ","); + while(st.hasMoreTokens()) + { + authors.add(st.nextToken().trim()); + } + + BookPrx book = _library.createBook(isbn, title, authors); + System.out.println("added new book with isbn " + isbn); + } + catch(BookExistsException ex) + { + error("the book already exists."); + } + catch(Ice.LocalException ex) + { + error(ex.toString()); + } + } + + void + findIsbn(java.util.List args) + { + if(args.size() != 1) + { + error("`isbn' requires exactly one argument (type `help' for more info)"); + return; + } + + try + { + if(_query != null) + { + try + { + _query.destroy(); + } + catch(Exception e) + { + // Ignore + } + } + _query = null; + _current = null; + + BookDescriptionHolder first = new BookDescriptionHolder(); + BookQueryResultPrxHolder result = new BookQueryResultPrxHolder(); + + _library.queryByIsbn((String)args.get(0), first, result); + _current = first.value; + _query = result.value; + printCurrent(); + } + catch(QueryActiveException ex) + { + error(ex.toString()); + } + catch(NoResultsException ex) + { + error(ex.toString()); + } + catch(Ice.LocalException ex) + { + error(ex.toString()); + } + } + + void + findAuthors(java.util.List args) + { + if(args.size() != 1) + { + error("`authors' requires exactly one argument (type `help' for more info)"); + return; + } + + try + { + if(_query != null) + { + try + { + _query.destroy(); + } + catch(Exception e) + { + // Ignore + } + } + _query = null; + _current = null; + + BookDescriptionHolder first = new BookDescriptionHolder(); + BookQueryResultPrxHolder result = new BookQueryResultPrxHolder(); + + _library.queryByAuthor((String)args.get(0), first, result); + _current = first.value; + _query = result.value; + printCurrent(); + } + catch(QueryActiveException ex) + { + error(ex.toString()); + } + catch(NoResultsException ex) + { + error(ex.toString()); + } + catch(Ice.LocalException ex) + { + error(ex.toString()); + } + } + + void + nextFoundBook() + { + if(_query != null) + { + Ice.IntHolder remaining = new Ice.IntHolder(); + Ice.BooleanHolder destroyed = new Ice.BooleanHolder(); + java.util.List<BookDescription> next = _query.next(1, destroyed); + if(destroyed.value) + { + _query = null; + _current = null; + } + else + { + _current = next.get(0); + } + } + printCurrent(); + } + + void + printCurrent() + { + try + { + if(_current != null) + { + System.out.println("current book is:" ); + System.out.println("isbn: " + _current.isbn); + System.out.println("title: " + _current.title); + System.out.println("authors: " + _current.authors); + if(_current.rentedBy.length() > 0) + { + System.out.println("rented: " + _current.rentedBy); + } + } + else + { + System.out.println("no current book"); + } + } + catch(Ice.ObjectNotExistException ex) + { + System.out.println("current book no longer exists"); + } + catch(Ice.LocalException ex) + { + error(ex.toString()); + } + } + + void + rentCurrent(java.util.List args) + { + if(args.size() != 1) + { + error("`rent' requires exactly one argument (type `help' for more info)"); + return; + } + + try + { + if(_current != null) + { + _current.proxy.rentBook((String)args.get(0)); + System.out.println("the book is now rented by `" + (String)args.get(0) + "'"); + } + else + { + System.out.println("no current book"); + } + } + catch(BookRentedException ex) + { + System.out.println("the book has already been rented."); + } + catch(Ice.ObjectNotExistException ex) + { + System.out.println("current book no longer exists"); + } + catch(Ice.LocalException ex) + { + error(ex.toString()); + } + } + + void + returnCurrent() + { + try + { + if(_current != null) + { + _current.proxy.returnBook(); + System.out.println( "the book has been returned."); + } + else + { + System.out.println("no current book"); + } + } + catch(BookNotRentedException ex) + { + System.out.println("the book is not currently rented."); + } + catch(Ice.ObjectNotExistException ex) + { + System.out.println("current book no longer exists"); + } + catch(Ice.LocalException ex) + { + error(ex.toString()); + } + } + + void + removeCurrent() + { + try + { + if(_current != null) + { + _current.proxy.destroy(); + _current = null; + System.out.println("removed current book" ); + } + else + { + System.out.println("no current book" ); + } + } + catch(Ice.ObjectNotExistException ex) + { + System.out.println("current book no longer exists"); + } + catch(Ice.LocalException ex) + { + error(ex.toString()); + } + } + + void + error(String s) + { + System.err.println("error: " + s); + } + + void + warning(String s) + { + System.err.println("warning: " + s); + } + + String + getInput() + { + System.out.print(">>> "); + System.out.flush(); + + try + { + return _in.readLine(); + } + catch(java.io.IOException e) + { + return null; + } + } + + int + parse() + { + _query = null; + _current = null; + + _in = new java.io.BufferedReader(new java.io.InputStreamReader(System.in)); + + Grammar g = new Grammar(this); + g.parse(); + + return 0; + } + + private BookQueryResultPrx _query; + private BookDescription _current; + + private LibraryPrx _library; + + private java.io.BufferedReader _in; + private boolean _interactive; +} diff --git a/java/demo/Database/library/README b/java/demo/Database/library/README new file mode 100644 index 00000000000..f7340d80620 --- /dev/null +++ b/java/demo/Database/library/README @@ -0,0 +1,51 @@ +MySQL JDBC Demo +=============== + +This demo shows how to implement an Ice server that uses mysql +through a JDBC API. + +It is a fairly simple demo that illustrates how to: + + - Map relational data to Ice objects, in particular convert between + Ice and JDBC types. + - Use an JDBC connection pool to provide JDBC connections to Ice + requests. + - Use an Ice servant locator. + + +Building the demo +----------------- + +- Install mysql. + +- Download version 5.0.8 of the mysql JDBC connector. Ensure that + mysql-connector-java-5.0.8-bin.jar is in your CLASSPATH. + +- Ensure that your user (by default, matthew) has appropriate + privileges. + +- Create the SQL tables using the provided createTypes.sql + script. For example: + + $ mysql --user=matthew --pass=foo library < initialize.mysql + +Running the demo +---------------- + +Review the JDBC properties in the config.server file. You may need to +change them to connect to your mysql server. + +To run the demo, first start the server: + + $ java Server + +In another window, populate the server's database by starting the +client and redirecting its input from the file "books": + +$ java Client < books + +Then start the client again to use the demo interactively: + +$ java Client + +Type "help" to get a list of valid commands. diff --git a/java/demo/Database/library/ReapThread.java b/java/demo/Database/library/ReapThread.java new file mode 100644 index 00000000000..5bef3cd3c50 --- /dev/null +++ b/java/demo/Database/library/ReapThread.java @@ -0,0 +1,102 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +import Demo.*; + +class ReapThread extends Thread +{ + static class SessionProxyPair + { + SessionProxyPair(Demo.SessionPrx p, SessionI s) + { + proxy = p; + session = s; + } + + Demo.SessionPrx proxy; + SessionI session; + } + + ReapThread(Ice.Logger logger) + { + _logger = logger; + } + + synchronized public void + run() + { + while(!_terminated) + { + try + { + wait(1000); + } + catch(InterruptedException e) + { + } + + if(!_terminated) + { + java.util.Iterator<SessionProxyPair> p = _sessions.iterator(); + while(p.hasNext()) + { + SessionProxyPair s = p.next(); + try + { + // + // Session destruction may take time in a + // real-world example. Therefore the current time + // is computed for each iteration. + // + if((System.currentTimeMillis() - s.session.timestamp()) > _timeout) + { + _logger.trace("ReapThread", "The session " + s.proxy.ice_getIdentity() + " has timed out."); + s.proxy.destroy(); + p.remove(); + } + } + catch(Ice.ObjectNotExistException e) + { + p.remove(); + } + } + } + } + } + + synchronized public void + terminate() + { + _terminated = true; + notify(); + + // Destroy each of the sessions, releasing any resources they + // may hold. This calls directly on the session, not via the + // proxy since terminate() is called after the communicator is + // shutdown, which means calls on collocated objects is not + // permitted. + java.util.Iterator<SessionProxyPair> p = _sessions.iterator(); + while(p.hasNext()) + { + p.next().session.shutdown(); + } + _sessions.clear(); + } + + synchronized public void + add(SessionPrx proxy, SessionI session) + { + _sessions.add(new SessionProxyPair(proxy, session)); + } + + private final long _timeout = 10 * 1000; // 10 seconds. + private Ice.Logger _logger; + private boolean _terminated = false; + private java.util.List<SessionProxyPair> _sessions = new java.util.LinkedList<SessionProxyPair>(); +} diff --git a/java/demo/Database/library/RunParser.java b/java/demo/Database/library/RunParser.java new file mode 100644 index 00000000000..42b10910861 --- /dev/null +++ b/java/demo/Database/library/RunParser.java @@ -0,0 +1,100 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +import Demo.*; + +class RunParser +{ + static private class SessionRefreshThread extends Thread + { + SessionRefreshThread(Ice.Logger logger, long timeout, SessionPrx session) + { + _logger = logger; + _session = session; + _timeout = timeout; + } + + synchronized public void + run() + { + while(!_terminated) + { + try + { + wait(_timeout); + } + catch(InterruptedException e) + { + } + if(!_terminated) + { + try + { + _session.refresh(); + } + catch(Ice.LocalException ex) + { + _logger.warning("SessionRefreshThread: " + ex); + _terminated = true; + } + } + } + } + + synchronized private void + terminate() + { + _terminated = true; + notify(); + } + + final private Ice.Logger _logger; + final private SessionPrx _session; + final private long _timeout; + private boolean _terminated = false; + } + + static int + runParser(String appName, String[] args, Ice.Communicator communicator) + { + SessionFactoryPrx factory = SessionFactoryPrxHelper.checkedCast( + communicator.propertyToProxy("SessionFactory.Proxy")); + if(factory == null) + { + System.err.println(appName + ": invalid object reference"); + return 1; + } + + SessionPrx session = factory.create(); + SessionRefreshThread refresh = new SessionRefreshThread(communicator.getLogger(), 5000, session); + refresh.start(); + + LibraryPrx library = session.getLibrary(); + + Parser parser = new Parser(communicator, library); + int rc = parser.parse(); + + if(refresh != null) + { + refresh.terminate(); + try + { + refresh.join(); + } + catch(InterruptedException e) + { + } + refresh = null; + } + + session.destroy(); + + return rc; + } +} diff --git a/java/demo/Database/library/Scanner.java b/java/demo/Database/library/Scanner.java new file mode 100644 index 00000000000..f5ee752de84 --- /dev/null +++ b/java/demo/Database/library/Scanner.java @@ -0,0 +1,279 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +class Scanner +{ + Scanner(Parser p) + { + _parser = p; + } + + Token + nextToken() + { + String s = next(); + if(s == null) + { + return null; + } + + if(s.equals(";")) + { + return new Token(Token.TOK_SEMI); + } + else if(s.equals("help")) + { + return new Token(Token.TOK_HELP); + } + else if(s.equals("exit") || s.equals("quit")) + { + return new Token(Token.TOK_EXIT); + } + else if(s.equals("add")) + { + return new Token(Token.TOK_ADD_BOOK); + } + else if(s.equals("isbn")) + { + return new Token(Token.TOK_FIND_ISBN); + } + else if(s.equals("authors")) + { + return new Token(Token.TOK_FIND_AUTHORS); + } + else if(s.equals("next")) + { + return new Token(Token.TOK_NEXT_FOUND_BOOK); + } + else if(s.equals("current")) + { + return new Token(Token.TOK_PRINT_CURRENT); + } + else if(s.equals("rent")) + { + return new Token(Token.TOK_RENT_BOOK); + } + else if(s.equals("return")) + { + return new Token(Token.TOK_RETURN_BOOK); + } + else if(s.equals("remove")) + { + return new Token(Token.TOK_REMOVE_CURRENT); + } + else + { + return new Token(Token.TOK_STRING, s); + } + } + + static private class EndOfInput extends Exception + { + } + + private char + get() + throws EndOfInput + { + // + // If there is an character in the unget buffer, return it. + // + if(_unget) + { + _unget = false; + return _ungetChar; + } + + // + // No current buffer? + // + if(_buf == null) + { + _buf = _parser.getInput(); + _pos = 0; + if(_buf == null) + { + throw new EndOfInput(); + } + } + + // + // At the end-of-buffer? + // + while(_pos >= _buf.length()) + { + _buf = null; + _pos = 0; + return '\n'; + } + + return _buf.charAt(_pos++); + } + + // + // unget only works with one character. + // + private void + unget(char c) + { + assert(!_unget); + _unget = true; + _ungetChar = c; + } + + private String + next() + { + // + // Eat any whitespace. + // + char c; + try + { + do + { + c = get(); + } + while(Character.isWhitespace(c) && c != '\n'); + } + catch(EndOfInput ignore) + { + return null; + } + + StringBuffer buf = new StringBuffer(); + + if(c == ';' || c == '\n') + { + buf.append(';'); + } + else if(c == '\'') + { + try + { + while(true) + { + c = get(); + if(c == '\'') + { + break; + } + else + { + buf.append(c); + } + } + } + catch(EndOfInput e) + { + _parser.warning("EOF in string"); + } + } + else if(c == '\"') + { + try + { + while(true) + { + c = get(); + if(c == '\"') + { + break; + } + else if(c == '\\') + { + try + { + char next = get(); + switch(next) + { + case '\\': + case '"': + { + buf.append(next); + break; + } + + case 'n': + { + buf.append('\n'); + break; + } + + case 'r': + { + buf.append('\r'); + break; + } + + case 't': + { + buf.append('\t'); + break; + } + + case 'f': + { + buf.append('\f'); + break; + } + + default: + { + buf.append(c); + unget(next); + } + } + } + catch(EndOfInput e) + { + buf.append(c); + } + } + else + { + buf.append(c); + } + } + } + catch(EndOfInput e) + { + _parser.warning("EOF in string"); + } + } + else + { + // + // Otherwise it's a string. + // + try + { + do + { + buf.append(c); + c = get(); + } + while(!Character.isWhitespace(c) && c != ';' && c != '\n'); + + unget(c); + } + catch(EndOfInput ignore) + { + } + } + + return buf.toString(); + } + + private Parser _parser; + private boolean _unget = false; + private char _ungetChar; + private String _buf = null; + private int _pos; +} diff --git a/java/demo/Database/library/Server.java b/java/demo/Database/library/Server.java new file mode 100644 index 00000000000..0ba4f08d036 --- /dev/null +++ b/java/demo/Database/library/Server.java @@ -0,0 +1,130 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +import Demo.*; + +class LibraryServer extends Ice.Application +{ + static class BookLocator implements Ice.ServantLocator + { + BookLocator(Ice.Object servant) + { + _servant = servant; + } + + public Ice.Object locate(Ice.Current c, Ice.LocalObjectHolder cookie) + { + return _servant; + } + + public void finished(Ice.Current c, Ice.Object servant, Object cookie) + { + } + + public void deactivate(String category) + { + } + + private Ice.Object _servant; + } + + public int + run(String[] args) + { + if(args.length > 0) + { + System.err.println(appName() + ": too many arguments"); + return 1; + } + + Ice.Properties properties = communicator().getProperties(); + + String username = properties.getProperty("JDBC.Username"); + String password = properties.getProperty("JDBC.Password"); + String url = properties.getProperty("JDBC.Url"); + int nConnections = properties.getPropertyAsIntWithDefault("JDBC.NumConnections", 5); + if(nConnections < 1) + { + nConnections = 1; + } + ConnectionPool pool = null; + Ice.Logger logger = communicator().getLogger(); + + try + { + Class.forName ("com.mysql.jdbc.Driver").newInstance (); + } + catch(Exception e) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); + System.err.println("failed to initialize mysql driver:\n" + sw.toString()); + return 1; + } + + try + { + pool = new ConnectionPool(logger, url, username, password, nConnections); + } + catch(java.sql.SQLException e) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); + System.err.println("failed to create connection pool: SQLException:\n" + sw.toString()); + return 1; + } + + ReapThread reaper = new ReapThread(logger); + reaper.start(); + + // + // Create an object adapter + // + Ice.ObjectAdapter adapter = communicator().createObjectAdapter("SessionFactory"); + adapter.add(new SessionFactoryI(logger, pool, reaper), communicator().stringToIdentity("SessionFactory")); + BookI book = new BookI(logger, pool); + adapter.addServantLocator(new BookLocator(book), "book"); + + // + // Everything ok, let's go. + // + adapter.activate(); + + shutdownOnInterrupt(); + communicator().waitForShutdown(); + defaultInterrupt(); + + reaper.terminate(); + try + { + reaper.join(); + } + catch(InterruptedException e) + { + } + + pool.destroy(); + + return 0; + } +} + +public class Server +{ + static public void + main(String[] args) + { + LibraryServer app = new LibraryServer(); + app.main("demo.Database.library.Server", args, "config.server"); + } +} diff --git a/java/demo/Database/library/SessionFactoryI.java b/java/demo/Database/library/SessionFactoryI.java new file mode 100644 index 00000000000..677a92078f2 --- /dev/null +++ b/java/demo/Database/library/SessionFactoryI.java @@ -0,0 +1,34 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +import Demo.*; + +class SessionFactoryI extends _SessionFactoryDisp +{ + SessionFactoryI(Ice.Logger logger, ConnectionPool pool, ReapThread reaper) + { + _logger = logger; + _pool = pool; + _reaper = reaper; + } + + public synchronized SessionPrx + create(Ice.Current c) + { + SessionI session = new SessionI(_pool, _logger, c.adapter); + SessionPrx proxy = SessionPrxHelper.uncheckedCast(c.adapter.addWithUUID(session)); + _logger.trace("SessionFactory", "create new session: " + proxy.ice_getIdentity()); + _reaper.add(proxy, session); + return proxy; + } + + private Ice.Logger _logger; + private ConnectionPool _pool; + private ReapThread _reaper; +} diff --git a/java/demo/Database/library/SessionI.java b/java/demo/Database/library/SessionI.java new file mode 100644 index 00000000000..610cb8e4201 --- /dev/null +++ b/java/demo/Database/library/SessionI.java @@ -0,0 +1,97 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +import Demo.*; + +class SessionI extends _SessionDisp +{ + public + SessionI(ConnectionPool pool, Ice.Logger logger, Ice.ObjectAdapter adapter) + { + _pool = pool; + _logger = logger; + _timestamp = System.currentTimeMillis(); + _libraryImpl = new LibraryI(_logger, _pool); + _library = LibraryPrxHelper.uncheckedCast(adapter.addWithUUID(_libraryImpl)); + } + + synchronized public LibraryPrx + getLibrary(Ice.Current c) + { + if(_destroyed) + { + throw new Ice.ObjectNotExistException(); + } + return _library; + } + + synchronized public void + refresh(Ice.Current c) + { + if(_destroyed) + { + throw new Ice.ObjectNotExistException(); + } + _timestamp = System.currentTimeMillis(); + } + + synchronized public void + destroy(Ice.Current c) + { + if(_destroyed) + { + throw new Ice.ObjectNotExistException(); + } + + _destroyed = true; + _logger.trace("Session", "The session " + c.id + " is now destroyed."); + _libraryImpl.destroy(); + try + { + if(c != null) + { + c.adapter.remove(c.id); + c.adapter.remove(_library.ice_getIdentity()); + } + } + catch(Ice.ObjectAdapterDeactivatedException e) + { + // This method is called on shutdown of the server, in + // which case this exception is expected. + } + } + + // Called on application shutdown. + synchronized public void + shutdown() + { + if(!_destroyed) + { + _destroyed = true; + _libraryImpl.shutdown(); + } + } + + synchronized public long + timestamp() + { + if(_destroyed) + { + throw new Ice.ObjectNotExistException(); + } + return _timestamp; + } + + private Ice.Logger _logger; + private ConnectionPool _pool; + private boolean _destroyed = false; // true if destroy() was called, false otherwise. + private long _timestamp; // The last time the session was refreshed. + private LibraryPrx _library; + private LibraryI _libraryImpl; +} diff --git a/java/demo/Database/library/Token.java b/java/demo/Database/library/Token.java new file mode 100644 index 00000000000..656630f40c9 --- /dev/null +++ b/java/demo/Database/library/Token.java @@ -0,0 +1,39 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +class Token +{ + public static final int TOK_HELP = 0; + public static final int TOK_EXIT = 1; + public static final int TOK_ADD_BOOK = 2; + public static final int TOK_FIND_ISBN = 3; + public static final int TOK_FIND_AUTHORS = 4; + public static final int TOK_NEXT_FOUND_BOOK = 5; + public static final int TOK_PRINT_CURRENT = 6; + public static final int TOK_RENT_BOOK = 7; + public static final int TOK_RETURN_BOOK = 8; + public static final int TOK_REMOVE_CURRENT = 9; + public static final int TOK_STRING = 12; + public static final int TOK_SEMI = 13; + + int type; + String value; + + Token(int t) + { + type = t; + value = null; + } + + Token(int t, String v) + { + type = t; + value = v; + } +} diff --git a/java/demo/Database/library/books b/java/demo/Database/library/books new file mode 100644 index 00000000000..18836dbdba6 --- /dev/null +++ b/java/demo/Database/library/books @@ -0,0 +1,30 @@ +add '096447963X' 'The Dragon Style (Learn to Play Go, Volume III)' 'Janice Kim, Jeong Soo-Hyun' ; +add '0964479613' "Learn to Play Go: A Master's Guide to the Ultimate Game (Volume I)" 'Janice Kim, Jeong Soo-Hyun' ; +add '0964479621' 'The Way of the Moving Horse (Learn to Play Go, Volume II)' 'Janice Kim, Jeong Soo-Hyun' ; +add '0964479648' 'Battle Strategies (Learn to Play Go Series)' 'Janice Kim, Jeong Soo-Hyun' ; +add '0201889544' 'The C++ Programming Language' 'Bjarne Stroustrup' ; +add '0201543303' 'The Design and Evolution of C++' 'Bjarne Stroustrup' ; +add '0201700735' 'The C++ Programming Language Special Edition' 'Bjarne Stroustrup' ; +add '0201379260' 'The C++ Standard Library : A Tutorial and Reference' 'Nicolai M. Josuttis' ; +add '0201749629' 'Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template Library' 'Scott Meyers' ; +add '0201924889' 'Effective C++: 50 Specific Ways to Improve Your Programs and Design' 'Scott Meyers' ; +add '020163371X' 'More Effective C++: 35 New Ways to Improve Your Programs and Designs' 'Scott Meyers' ; +add '0201615622' 'Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions' 'Herb Sutter' ; +add '020170434X' 'More Exceptional C++' 'Herb Sutter' ; +add '0201704315' 'Modern C++ Design: Generic Programming and Design Patterns Applied' 'Andrei Alexandrescu' ; +add '0735616353' 'Microsoft Visual C++ .NET Deluxe Learning Edition' 'Microsoft Corporation' ; +add '0735615497' 'Programming with Microsoft Visual C++ .NET, Sixth Edition (Core Reference)' 'George Shepherd, David Kruglinski' ; +add '0735614229' 'Applied Microsoft .NET Framework Programming' 'Jeffrey Richter' ; +add '0201824701' 'C++ Primer' 'Stanley B. Lippman, Josee Lajoie' ; +add '0201485184' 'Essential C++' 'Stanley B. Lippman' ; +add '020170353X' 'Accelerated C++: Practical Programming by Example' 'Andrew Koenig, Barbara E. Moo' ; +add '0201423391' 'Ruminations on C++ : A Decade of Programming Insight and Experience' 'Andrew Koenig, Barbara E. Moo' ; +add '0201179288' 'C Traps and Pitfalls' 'Andrew Koenig' ; +add '0131103628' 'The C Programming Language' 'Brian W. Kernighan, Dennis M. Ritchie' ; +add '020161586X' 'The Practice of Programming' 'Brian W. Kernighan, Rob Pike' ; +add '013937681X' 'UNIX Programming Environment, The' 'Brian W. Kernighan, Rob Pike' ; +add '0201563177' 'Advanced Programming in the UNIX(R) Environment' 'W. Richard Stevens' ; +add '0201633469' 'The Protocols (TCP/IP Illustrated, Volume 1)' 'W. Richard Stevens' ; +add '0201634953' 'TCP for Transactions, HTTP, NNTP, and the UNIX(R) Domain Protocols (TCP/IP Illustrated, Volume 3)' 'W. Richard Stevens' ; +add '013490012X' 'UNIX Network Programming, Volume 1: Networking APIs - Sockets and XTI' 'W. Richard Stevens' ; +add '0130810819' 'UNIX Network Programming: Interprocess Communications' 'W. Richard Stevens' ; diff --git a/java/demo/Database/library/build.xml b/java/demo/Database/library/build.xml new file mode 100644 index 00000000000..cd874693901 --- /dev/null +++ b/java/demo/Database/library/build.xml @@ -0,0 +1,64 @@ +<!-- + ********************************************************************** + + Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. + + This copy of Ice is licensed to you under the terms described in the + ICE_LICENSE file included in this distribution. + + ********************************************************************** +--> + +<project name="demo_Freeze_library" default="all" basedir="."> + + <!-- set global properties for this build --> + <property name="top.dir" value="../../.."/> + + <!-- import common definitions --> + <import file="${top.dir}/config/common.xml"/> + + <target name="generate" depends="init"> + <!-- Create the output directory for generated code --> + <mkdir dir="${generated.dir}"/> + <slice2java outputdir="${generated.dir}"> + <meta value="${java2metadata}"/> + <includepath> + <pathelement path="${slice.dir}" /> + </includepath> + <fileset dir="." includes="Library.ice"/> + </slice2java> + <slice2freezej ice="on" outputdir="${generated.dir}"> + <meta value="${java2metadata}"/> + <includepath> + <pathelement path="${slice.dir}" /> + </includepath> + <fileset dir="${slice.dir}/Ice"> + <include name="BuiltinSequences.ice" /> + </fileset> + <fileset dir="." includes="Library.ice"/> + <dict name="StringIsbnSeqDict" key="string" value="Ice::StringSeq"/> + </slice2freezej> + </target> + + <target name="compile" depends="generate"> + <mkdir dir="${class.dir}"/> + <javac srcdir="${generated.dir}" destdir="${class.dir}" + debug="${debug}"> + <classpath refid="ice.classpath"/> + <compilerarg value="${javac.lint}"/> + </javac> + <javac srcdir="." destdir="${class.dir}" + excludes="generated/**" debug="${debug}"> + <classpath refid="ice.classpath"/> + <compilerarg value="${javac.lint}"/> + </javac> + </target> + + <target name="all" depends="compile"/> + + <target name="clean"> + <delete dir="${generated.dir}"/> + <delete dir="${class.dir}"/> + </target> + +</project> diff --git a/java/demo/Database/library/config.client b/java/demo/Database/library/config.client new file mode 100644 index 00000000000..93ae62d757e --- /dev/null +++ b/java/demo/Database/library/config.client @@ -0,0 +1,28 @@ +# +# The client reads this property to create the reference to the +# "SessionFactory" object in the server. +# +SessionFactory.Proxy=SessionFactory:default -p 10000 + +# +# Warn about connection exceptions +# +Ice.Warn.Connections=1 + +# +# Network Tracing +# +# 0 = no network tracing +# 1 = trace connection establishment and closure +# 2 = like 1, but more detailed +# 3 = like 2, but also trace data transfer +# +#Ice.Trace.Network=1 + +# +# Protocol Tracing +# +# 0 = no protocol tracing +# 1 = trace protocol messages +# +#Ice.Trace.Protocol=1 diff --git a/java/demo/Database/library/config.server b/java/demo/Database/library/config.server new file mode 100644 index 00000000000..4cbefb70ffc --- /dev/null +++ b/java/demo/Database/library/config.server @@ -0,0 +1,40 @@ +# +# Configure the server endpoints. +# +SessionFactory.Endpoints=default -p 10000 + +# JDBC configuration. +JDBC.Username=matthew +JDBC.Password=foo +JDBC.Url=jdbc:mysql://localhost/library + +# The number of connections in the JDBC connection pool. This number +# should be at least as big as the number of the threads in the server +# thread pool. +JDBC.NumConnections=5 + +# Number of threads in the server-side dispatch thread pool. +Ice.ThreadPool.Server.Size=1 + +# +# Warn about connection exceptions +# +Ice.Warn.Connections=1 + +# +# Network Tracing +# +# 0 = no network tracing +# 1 = trace connection establishment and closure +# 2 = like 1, but more detailed +# 3 = like 2, but also trace data transfer +# +#Ice.Trace.Network=1 + +# +# Protocol Tracing +# +# 0 = no protocol tracing +# 1 = trace protocol messages +# +#Ice.Trace.Protocol=1 diff --git a/java/demo/Database/library/createTypes.sql b/java/demo/Database/library/createTypes.sql new file mode 100644 index 00000000000..cd07546b83f --- /dev/null +++ b/java/demo/Database/library/createTypes.sql @@ -0,0 +1,43 @@ +# ********************************************************************** +# +# Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved. +# +# This copy of Ice is licensed to you under the terms described in the +# ICE_LICENSE file included in this distribution. +# +# ********************************************************************** +# +# Initialize SQL tables. +# +DROP TABLE IF EXISTS books; +CREATE TABLE books +( + id INT UNSIGNED AUTO_INCREMENT NOT NULL, + PRIMARY KEY (id), + isbn CHAR(10), + title VARCHAR(255), + renter_id INT +); + +DROP TABLE IF EXISTS authors_books; +CREATE TABLE authors_books +( + book_id INT, + author_id INT +); + +DROP TABLE IF EXISTS authors; +CREATE TABLE authors +( + id INT UNSIGNED NOT NULL AUTO_INCREMENT, + PRIMARY KEY(id), + name VARCHAR(255) +); + +DROP TABLE IF EXISTS customers; +CREATE TABLE customers +( + id INT UNSIGNED NOT NULL AUTO_INCREMENT, + PRIMARY KEY(id), + name VARCHAR(255) +); |