summaryrefslogtreecommitdiff
path: root/java/demo
diff options
context:
space:
mode:
Diffstat (limited to 'java/demo')
-rw-r--r--java/demo/Database/library/BookI.java382
-rw-r--r--java/demo/Database/library/BookQueryResultI.java97
-rw-r--r--java/demo/Database/library/Client.java53
-rw-r--r--java/demo/Database/library/ConnectionPool.java156
-rw-r--r--java/demo/Database/library/DispatchInterceptorI.java58
-rw-r--r--java/demo/Database/library/Glacier2Session.ice50
-rw-r--r--java/demo/Database/library/Glacier2SessionManagerI.java38
-rw-r--r--java/demo/Database/library/Grammar.java176
-rw-r--r--java/demo/Database/library/Library.ice288
-rw-r--r--java/demo/Database/library/LibraryI.java387
-rw-r--r--java/demo/Database/library/Parser.java443
-rw-r--r--java/demo/Database/library/README103
-rw-r--r--java/demo/Database/library/ReapThread.java127
-rw-r--r--java/demo/Database/library/RunParser.java220
-rw-r--r--java/demo/Database/library/SQLRequestContext.java181
-rw-r--r--java/demo/Database/library/Scanner.java283
-rw-r--r--java/demo/Database/library/Server.java142
-rw-r--r--java/demo/Database/library/Session.ice82
-rw-r--r--java/demo/Database/library/SessionFactoryI.java46
-rw-r--r--java/demo/Database/library/SessionI.java96
-rw-r--r--java/demo/Database/library/Token.java40
-rw-r--r--java/demo/Database/library/books30
-rw-r--r--java/demo/Database/library/build.xml55
-rw-r--r--java/demo/Database/library/config.client62
-rw-r--r--java/demo/Database/library/config.glacier255
-rw-r--r--java/demo/Database/library/config.server64
-rw-r--r--java/demo/Database/library/createTypes.sql43
27 files changed, 3757 insertions, 0 deletions
diff --git a/java/demo/Database/library/BookI.java b/java/demo/Database/library/BookI.java
new file mode 100644
index 00000000000..5176584b3cf
--- /dev/null
+++ b/java/demo/Database/library/BookI.java
@@ -0,0 +1,382 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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 retrieved
+// from the Ice.Current object.
+//
+class BookI extends _BookDisp
+{
+ public void
+ ice_ping(Ice.Current current)
+ {
+ SQLRequestContext context = SQLRequestContext.getCurrentContext();
+ assert context != null;
+ Integer id = new Integer(current.id.name);
+
+ try
+ {
+ java.sql.PreparedStatement stmt = context.prepareStatement("SELECT * FROM books WHERE id = ?");
+ stmt.setInt(1, id);
+ java.sql.ResultSet rs = stmt.executeQuery();
+ if(!rs.next())
+ {
+ throw new Ice.ObjectNotExistException();
+ }
+ }
+ catch(java.sql.SQLException e)
+ {
+ JDBCException ex = new JDBCException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ public BookDescription
+ describe(Ice.Current current)
+ {
+ SQLRequestContext context = SQLRequestContext.getCurrentContext();
+ assert context != null;
+ Integer id = new Integer(current.id.name);
+
+ try
+ {
+ java.sql.PreparedStatement stmt = context.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(context, rs, current.adapter);
+ }
+ catch(java.sql.SQLException e)
+ {
+ JDBCException ex = new JDBCException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ public void
+ setTitle(String title, Ice.Current current)
+ {
+ SQLRequestContext context = SQLRequestContext.getCurrentContext();
+ assert context != null;
+ Integer id = new Integer(current.id.name);
+
+ try
+ {
+ java.sql.PreparedStatement stmt = context.prepareStatement("UPDATE books SET title = ? WHERE id = ?");
+ stmt.setString(1, title);
+ stmt.setInt(2, id);
+ int count = stmt.executeUpdate();
+ assert count == 1;
+ }
+ catch(java.sql.SQLException e)
+ {
+ JDBCException ex = new JDBCException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ public void
+ setAuthors(java.util.List<String> authors, Ice.Current current)
+ {
+ SQLRequestContext context = SQLRequestContext.getCurrentContext();
+ assert context != null;
+ Integer id = new Integer(current.id.name);
+
+ try
+ {
+ // First destroy each of the authors_books records.
+ java.sql.PreparedStatement stmt = context.prepareStatement("DELETE FROM authors_books WHERE book_id = ?");
+ stmt.setInt(1, id);
+ stmt.executeUpdate();
+
+ //
+ // 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 authid;
+ stmt = context.prepareStatement("SELECT * FROM authors WHERE name = ?");
+ stmt.setString(1, author);
+ java.sql.ResultSet rs = stmt.executeQuery();
+ if(rs.next())
+ {
+ // If there is a result, then the database
+ // already contains this author.
+ authid = rs.getInt(1);
+ assert !rs.next();
+ }
+ else
+ {
+ // Otherwise, create a new author record.
+ stmt = context.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;
+ authid = rs.getInt(1);
+ }
+
+ // Add the new id to the list of ids.
+ authIds.add(authid);
+ }
+
+ // Create new authors_books records.
+ java.util.Iterator<Integer> q = authIds.iterator();
+ while(q.hasNext())
+ {
+ stmt = context.prepareStatement("INSERT INTO authors_books (book_id, author_id) VALUES(?, ?)");
+ stmt.setInt(1, id);
+ stmt.setInt(2, q.next());
+ int count = stmt.executeUpdate();
+ assert count == 1;
+ }
+ }
+ catch(java.sql.SQLException e)
+ {
+ JDBCException ex = new JDBCException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ public void
+ destroy(Ice.Current current)
+ {
+ SQLRequestContext context = SQLRequestContext.getCurrentContext();
+ assert context != null;
+ Integer id = new Integer(current.id.name);
+
+ try
+ {
+ java.sql.PreparedStatement stmt = context.prepareStatement("DELETE FROM books WHERE id = ?");
+ stmt.setInt(1, id);
+ int count = stmt.executeUpdate();
+ if(count == 0)
+ {
+ throw new Ice.ObjectNotExistException();
+ }
+ }
+ catch(java.sql.SQLException e)
+ {
+ JDBCException ex = new JDBCException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ public String
+ getRenter(Ice.Current current)
+ throws BookNotRentedException
+ {
+ SQLRequestContext context = SQLRequestContext.getCurrentContext();
+ assert context != null;
+ Integer id = new Integer(current.id.name);
+
+ try
+ {
+ java.sql.PreparedStatement stmt = context.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 = context.prepareStatement("SELECT * FROM customers WHERE id = ?");
+ stmt.setInt(1, renterId);
+ rs = stmt.executeQuery();
+ boolean next = rs.next();
+ assert next;
+ return rs.getString("name");
+ }
+ catch(java.sql.SQLException e)
+ {
+ JDBCException ex = new JDBCException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ public void
+ rentBook(String name, Ice.Current current)
+ throws InvalidCustomerException, BookRentedException
+ {
+ SQLRequestContext context = SQLRequestContext.getCurrentContext();
+ assert context != null;
+ Integer id = new Integer(current.id.name);
+ name = name.trim();
+ if(name.length() == 0)
+ {
+ throw new InvalidCustomerException();
+ }
+
+ try
+ {
+ java.sql.PreparedStatement stmt = context.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())
+ {
+ stmt = context.prepareStatement("SELECT * FROM customers WHERE id = ?");
+ stmt.setInt(1, renterId);
+ rs = stmt.executeQuery();
+ boolean next = rs.next();
+ assert next;
+ throw new BookRentedException(rs.getString("name"));
+ }
+
+ stmt = context.prepareStatement("SELECT * FROM customers WHERE name = ?");
+ stmt.setString(1, name);
+ rs = stmt.executeQuery();
+
+ if(rs.next())
+ {
+ renterId = rs.getInt("id");
+ assert !rs.next();
+ }
+ else
+ {
+ stmt = context.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();
+ boolean next = rs.next();
+ assert next;
+ renterId = rs.getInt(1);
+ }
+
+ stmt = context.prepareStatement("UPDATE books SET renter_id = ? WHERE id = ?");
+ stmt.setInt(1, renterId);
+ stmt.setInt(2, id);
+ int count = stmt.executeUpdate();
+ assert count == 1;
+ }
+ catch(java.sql.SQLException e)
+ {
+ JDBCException ex = new JDBCException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ public void
+ returnBook(Ice.Current current)
+ throws BookNotRentedException
+ {
+ SQLRequestContext context = SQLRequestContext.getCurrentContext();
+ assert context != null;
+ Integer id = new Integer(current.id.name);
+ try
+ {
+ java.sql.PreparedStatement stmt = context.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 = context.prepareStatement("UPDATE books SET renter_id = NULL WHERE id = ?");
+ stmt.setInt(1, id);
+ int count = stmt.executeUpdate();
+ assert count == 1;
+ }
+ catch(java.sql.SQLException e)
+ {
+ JDBCException ex = new JDBCException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ BookI()
+ {
+ }
+
+ static Ice.Identity
+ createIdentity(Integer bookId)
+ {
+ Ice.Identity id = new Ice.Identity();
+ id.category = "book";
+ id.name = bookId.toString();
+ return id;
+ }
+
+ static BookDescription
+ extractDescription(SQLRequestContext context, 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;
+ // Query for the rentedBy.
+ Integer renterId = rs.getInt("renter_id");
+ if(!rs.wasNull())
+ {
+ stmt = context.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);
+ }
+
+ // Query for the authors.
+ stmt = context.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"));
+ }
+
+ return desc;
+ }
+}
diff --git a/java/demo/Database/library/BookQueryResultI.java b/java/demo/Database/library/BookQueryResultI.java
new file mode 100644
index 00000000000..28316ecfd5a
--- /dev/null
+++ b/java/demo/Database/library/BookQueryResultI.java
@@ -0,0 +1,97 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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 BookQueryResultI extends _BookQueryResultDisp
+{
+ // The query result owns the SQLRequestContext object until
+ // destroyed.
+ BookQueryResultI(SQLRequestContext context, java.sql.ResultSet rs)
+ {
+ _context = context;
+ _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(_context, _rs, current.adapter));
+ next = _rs.next();
+ }
+ }
+ catch(java.sql.SQLException e)
+ {
+ // Log the error, and raise an UnknownException.
+ _context.error("BookQueryResultI", 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;
+ _context.destroy(false);
+
+ current.adapter.remove(current.id);
+ }
+
+ // Called on application shutdown by the Library.
+ synchronized public void
+ shutdown()
+ {
+ if(!_destroyed)
+ {
+ _destroyed = true;
+ _context.destroy(false);
+ }
+ }
+
+ private SQLRequestContext _context;
+ private java.sql.ResultSet _rs;
+ private boolean _destroyed = false;
+}
+
diff --git a/java/demo/Database/library/Client.java b/java/demo/Database/library/Client.java
new file mode 100644
index 00000000000..531acd00f4a
--- /dev/null
+++ b/java/demo/Database/library/Client.java
@@ -0,0 +1,53 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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)
+ {
+ if(args.length > 1)
+ {
+ System.err.println("Usage: " + appName() + " [file]");
+ return 1;
+ }
+
+ //
+ // 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.Database.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..852f6388115
--- /dev/null
+++ b/java/demo/Database/library/ConnectionPool.java
@@ -0,0 +1,156 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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 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;
+ }
+ else
+ {
+ // Probe the connection with the database.
+ java.sql.PreparedStatement stmt = conn.prepareStatement("SELECT 1");
+ java.sql.ResultSet rs = stmt.executeQuery();
+ stmt.close();
+ }
+ }
+ 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,
+ // we need to re-establish the connection.
+ while(conn == null)
+ {
+ if(_trace)
+ {
+ _logger.trace("ConnectionPool", "establishing new database connection");
+ }
+ try
+ {
+ conn = java.sql.DriverManager.getConnection(_url, _username, _password);
+ conn.setAutoCommit(false);
+ }
+ 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());
+ }
+ }
+ if(_trace)
+ {
+ _logger.trace("ConnectionPool", "returning connection: " + conn + " " +
+ _connections.size() + "/" + _nconnections + " remaining");
+ }
+ return conn;
+ }
+
+ public synchronized void
+ release(java.sql.Connection connection)
+ {
+ if(connection != null)
+ {
+ _connections.add(connection);
+ notifyAll();
+ }
+ }
+
+ 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;
+ if(_trace)
+ {
+ _logger.trace("ConnectionPool", "establishing " + numConnections + " connections to " + url);
+ }
+ while(numConnections-- > 0)
+ {
+ java.sql.Connection connection = java.sql.DriverManager.getConnection(url, username, password);
+ connection.setAutoCommit(false);
+ _connections.add(connection);
+ }
+ }
+
+
+ private Ice.Logger _logger;
+ private boolean _trace = true;
+ 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/DispatchInterceptorI.java b/java/demo/Database/library/DispatchInterceptorI.java
new file mode 100644
index 00000000000..e92c9e6e73e
--- /dev/null
+++ b/java/demo/Database/library/DispatchInterceptorI.java
@@ -0,0 +1,58 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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 DispatchInterceptorI extends Ice.DispatchInterceptor
+{
+ public Ice.DispatchStatus
+ dispatch(Ice.Request request)
+ {
+ // Allocate a new SQLRequestContext associated with this
+ // request thread.
+ SQLRequestContext context = new SQLRequestContext();
+ try
+ {
+ Ice.DispatchStatus status = _servant.ice_dispatch(request, null);
+
+ // An exception causes the current transaction to rollback.
+ context.destroyFromDispatch(status == Ice.DispatchStatus.DispatchOK);
+
+ return status;
+ }
+ catch(JDBCException ex)
+ {
+ // Log the error.
+ Ice.Current c = request.getCurrent();
+ context.error("call of `" + c.operation + "' on id `" + c.id.category + "/" + c.id.name + "' failed", ex);
+
+ // A JDBCException causes the current transaction to
+ // rollback.
+ context.destroyFromDispatch(false);
+
+ // Translate the exception to UnknownException.
+ Ice.UnknownException e = new Ice.UnknownException();
+ e.initCause(ex);
+ throw e;
+ }
+ catch(RuntimeException ex)
+ {
+ // Any other exception causes the transaction to rollback.
+ context.destroyFromDispatch(false);
+ throw ex;
+ }
+ }
+
+ DispatchInterceptorI(Ice.Object servant)
+ {
+ _servant = servant;
+ }
+
+ private Ice.Object _servant;
+}
diff --git a/java/demo/Database/library/Glacier2Session.ice b/java/demo/Database/library/Glacier2Session.ice
new file mode 100644
index 00000000000..5a9ab2dd252
--- /dev/null
+++ b/java/demo/Database/library/Glacier2Session.ice
@@ -0,0 +1,50 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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_GLACIER2_SESSION_ICE
+#define LIBRARY_GLACIER2_SESSION_ICE
+
+#include <Glacier2/Session.ice>
+
+module Demo
+{
+
+/* Forward declaration. */
+interface Library;
+
+/**
+ *
+ * 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 Glacier2Session extends Glacier2::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();
+};
+
+};
+
+#endif
diff --git a/java/demo/Database/library/Glacier2SessionManagerI.java b/java/demo/Database/library/Glacier2SessionManagerI.java
new file mode 100644
index 00000000000..059d923de54
--- /dev/null
+++ b/java/demo/Database/library/Glacier2SessionManagerI.java
@@ -0,0 +1,38 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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 Glacier2SessionManagerI extends Glacier2._SessionManagerDisp
+{
+ public Glacier2.SessionPrx
+ create(String userId, Glacier2.SessionControlPrx control, Ice.Current c)
+ {
+ SessionI session = new SessionI(_logger, c.adapter);
+ _Glacier2SessionTie servant = new _Glacier2SessionTie(session);
+
+ Glacier2.SessionPrx proxy = Glacier2.SessionPrxHelper.uncheckedCast(c.adapter.addWithUUID(servant));
+
+ _logger.trace("SessionFactory", "create new session: " +
+ c.adapter.getCommunicator().identityToString(proxy.ice_getIdentity()));
+
+ _reaper.add(proxy, session);
+
+ return proxy;
+ }
+
+ Glacier2SessionManagerI(Ice.Logger logger, ReapThread reaper)
+ {
+ _logger = logger;
+ _reaper = reaper;
+ }
+
+ private Ice.Logger _logger;
+ private ReapThread _reaper;
+}
diff --git a/java/demo/Database/library/Grammar.java b/java/demo/Database/library/Grammar.java
new file mode 100644
index 00000000000..5bf6a22cf95
--- /dev/null
+++ b/java/demo/Database/library/Grammar.java
@@ -0,0 +1,176 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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_FIND_TITLE)
+ {
+ java.util.List s = strings();
+ if(_token.type != Token.TOK_SEMI)
+ {
+ throw new ParseError("Expected ';'");
+ }
+ _parser.findTitle(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..a26dbe20b01
--- /dev/null
+++ b/java/demo/Database/library/Library.ice
@@ -0,0 +1,288 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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 local exception is used internally if a java.sql.SQLException
+ * is raised.
+ *
+ **/
+local exception JDBCException
+{
+};
+
+/**
+ *
+ * This exception is raised if the book already exists.
+ *
+ **/
+exception BookExistsException
+{
+};
+
+/**
+ *
+ * This exception is raised if a book has already been rented.
+ *
+ **/
+exception BookRentedException
+{
+ string renter;
+};
+
+/**
+ *
+ * This exception is raised if a customer name is invalid.
+ *
+ **/
+exception InvalidCustomerException
+{
+};
+
+/**
+ *
+ * This exception is raised if the book has not been rented.
+ *
+ **/
+exception BookNotRentedException
+{
+};
+
+/** 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();
+
+ /**
+ *
+ * Set the title of a book.
+ *
+ * @param title The book title.
+ *
+ **/
+ void setTitle(string title);
+
+ /**
+ *
+ * Set the book authors.
+ *
+ * @param authors The book authors.
+ *
+ **/
+ void setAuthors(["java:type:java.util.LinkedList<String>:java.util.List<String>"] Ice::StringSeq authors);
+
+ /**
+ *
+ * Rent the book to the specified customer.
+ *
+ * @param customer The customer.
+ *
+ * @throws BookRentedException Raised if the book has already been
+ * rented.
+ *
+ * @throws InvalidCustomerException Raised if the customer is invalid.
+ *
+ **/
+ void rentBook(string name)
+ throws InvalidCustomerException, 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 at the
+ * start of the isbn number.
+ *
+ * @param isbn The ISBN number.
+ *
+ * @param n The number of rows to retrieve in the initial request.
+
+ * @param first The first set of results, up to n results.
+ *
+ * @param nrows The total number of rows.
+ *
+ * @param result The remainder of the results. If there are no
+ * further results, a null proxy is returned.
+ *
+ **/
+ void queryByIsbn(string isbn, int n, out BookDescriptionSeq first, out int nrows, out BookQueryResult* result);
+
+ /**
+ *
+ * Query based on the author name. The query is a partial match of
+ * the author's name.
+ *
+ * @param author The authors name.
+ *
+ * @param n The number of rows to retrieve in the initial request.
+
+ * @param first The first set of results, up to n results.
+ *
+ * @param nrows The total number of rows.
+ *
+ * @param result The remainder of the results. If there are no
+ * further results, a null proxy is returned.
+ *
+ **/
+ void queryByAuthor(string author, int n, out BookDescriptionSeq first, out int nrows, out BookQueryResult* result);
+
+ /**
+ *
+ * Query based on the book title. The query is a partial match of
+ * the book title.
+ *
+ * @param author The authors name.
+ *
+ * @param n The number of rows to retrieve in the initial request.
+
+ * @param first The first set of results, up to n results.
+ *
+ * @param nrows The total number of rows.
+ *
+ * @param result The remainder of the results. If there are no
+ * further results, a null proxy is returned.
+ *
+ **/
+ void queryByTitle(string title, int n, out BookDescriptionSeq first, out int nrows, out BookQueryResult* result);
+
+ /**
+ *
+ * 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;
+};
+
+};
+
+#endif
diff --git a/java/demo/Database/library/LibraryI.java b/java/demo/Database/library/LibraryI.java
new file mode 100644
index 00000000000..81bae5c6de7
--- /dev/null
+++ b/java/demo/Database/library/LibraryI.java
@@ -0,0 +1,387 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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 is a per-session library object.
+//
+class LibraryI extends _LibraryDisp
+{
+ public void
+ queryByIsbn(String isbn, int n, BookDescriptionSeqHolder first, Ice.IntHolder nrows,
+ BookQueryResultPrxHolder result, Ice.Current current)
+ {
+ SQLRequestContext context = SQLRequestContext.getCurrentContext();
+ assert context != null;
+
+ reapQueries();
+
+ try
+ {
+ java.sql.PreparedStatement stmt = context.prepareStatement("SELECT COUNT(*) FROM books WHERE isbn LIKE ?");
+ stmt.setString(1, isbn + "%");
+ java.sql.ResultSet rs = stmt.executeQuery();
+ boolean next = rs.next();
+ assert next;
+ nrows.value = rs.getInt(1);
+ if(nrows.value == 0)
+ {
+ return;
+ }
+
+ stmt = context.prepareStatement("SELECT * FROM books WHERE isbn LIKE ?");
+ stmt.setString(1, isbn + "%");
+ rs = stmt.executeQuery();
+ next = rs.next();
+ assert next;
+
+ first.value = new java.util.LinkedList<BookDescription>();
+ next = true;
+ for(int i = 0; i < n && next; ++i)
+ {
+ first.value.add(BookI.extractDescription(context, rs, current.adapter));
+ next = rs.next();
+ }
+ if(next)
+ {
+ // The SQLRequestContext is now owned by the query
+ // implementation.
+ context.obtain();
+ BookQueryResultI impl = new BookQueryResultI(context, rs);
+ result.value = BookQueryResultPrxHelper.uncheckedCast(current.adapter.addWithUUID(impl));
+ add(result.value, impl);
+ }
+ }
+ catch(java.sql.SQLException e)
+ {
+ JDBCException ex = new JDBCException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ public void
+ queryByAuthor(String author, int n, BookDescriptionSeqHolder first, Ice.IntHolder nrows,
+ BookQueryResultPrxHolder result, Ice.Current current)
+ {
+ SQLRequestContext context = SQLRequestContext.getCurrentContext();
+ assert context != null;
+
+ reapQueries();
+
+ try
+ {
+ // Find each of the authors.
+ java.sql.PreparedStatement stmt = context.prepareStatement("SELECT * FROM authors WHERE name LIKE ?");
+ stmt.setString(1, "%" + author + "%");
+ java.sql.ResultSet rs = stmt.executeQuery();
+ if(!rs.next())
+ {
+ // No results are available.
+ nrows.value = 0;
+ return;
+ }
+
+ // Build a query that finds all books by these authors.
+ StringBuffer sb = new StringBuffer("(");
+ 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 = context.prepareStatement(
+ "SELECT COUNT(DISTINCT ID) FROM books INNER JOIN authors_books ON books.id=authors_books.book_id AND "
+ + sb.toString());
+ rs = stmt.executeQuery();
+ boolean next = rs.next();
+ assert next;
+ nrows.value = rs.getInt(1);
+ if(nrows.value == 0)
+ {
+ return;
+ }
+
+ // Execute the query.
+ stmt = context.prepareStatement(
+ "SELECT DISTINCT ID, ISBN, TITLE, RENTER_ID FROM books INNER JOIN authors_books ON " +
+ "books.id=authors_books.book_id AND " + sb.toString());
+ rs = stmt.executeQuery();
+ next = rs.next();
+ assert next;
+
+ next = true;
+ first.value = new java.util.LinkedList<BookDescription>();
+ for(int i = 0; i < n && next; ++i)
+ {
+ first.value.add(BookI.extractDescription(context, rs, current.adapter));
+ next = rs.next();
+ }
+ if(next)
+ {
+ // The SQLRequestContext is now owned by the query
+ // implementation.
+ context.obtain();
+ BookQueryResultI impl = new BookQueryResultI(context, rs);
+ result.value = BookQueryResultPrxHelper.uncheckedCast(current.adapter.addWithUUID(impl));
+ add(result.value, impl);
+ }
+ }
+ catch(java.sql.SQLException e)
+ {
+ JDBCException ex = new JDBCException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ public void
+ queryByTitle(String title, int n, BookDescriptionSeqHolder first, Ice.IntHolder nrows,
+ BookQueryResultPrxHolder result, Ice.Current current)
+ {
+ SQLRequestContext context = SQLRequestContext.getCurrentContext();
+ assert context != null;
+
+ reapQueries();
+
+ try
+ {
+ java.sql.PreparedStatement stmt = context.prepareStatement("SELECT COUNT(*) FROM books WHERE title LIKE ?");
+ stmt.setString(1, "%" + title + "%");
+ java.sql.ResultSet rs = stmt.executeQuery();
+ boolean next = rs.next();
+ assert next;
+ nrows.value = rs.getInt(1);
+ if(nrows.value == 0)
+ {
+ return;
+ }
+
+ stmt = context.prepareStatement("SELECT * FROM books WHERE title LIKE ?");
+ stmt.setString(1, "%" + title + "%");
+ rs = stmt.executeQuery();
+ next = rs.next();
+ assert next;
+
+ first.value = new java.util.LinkedList<BookDescription>();
+ next = true;
+ for(int i = 0; i < n && next; ++i)
+ {
+ first.value.add(BookI.extractDescription(context, rs, current.adapter));
+ next = rs.next();
+ }
+ if(next)
+ {
+ // The SQLRequestContext is now owned by the query
+ // implementation.
+ context.obtain();
+ BookQueryResultI impl = new BookQueryResultI(context, rs);
+ result.value = BookQueryResultPrxHelper.uncheckedCast(current.adapter.addWithUUID(impl));
+ add(result.value, impl);
+ }
+ }
+ catch(java.sql.SQLException e)
+ {
+ JDBCException ex = new JDBCException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ public BookPrx
+ createBook(String isbn, String title, java.util.List<String> authors, Ice.Current current)
+ throws BookExistsException
+ {
+ SQLRequestContext context = SQLRequestContext.getCurrentContext();
+ assert context != null;
+ try
+ {
+ java.sql.PreparedStatement stmt = context.prepareStatement("SELECT * FROM books WHERE isbn = ?");
+ stmt.setString(1, isbn);
+ java.sql.ResultSet rs = stmt.executeQuery();
+ if(rs.next())
+ {
+ throw new BookExistsException();
+ }
+
+ //
+ // 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 = context.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
+ {
+ // Otherwise, create a new author record.
+ stmt = context.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);
+ }
+
+ // Add the new id to the list of ids.
+ authIds.add(id);
+ }
+
+ // Create the new book.
+ stmt = context.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);
+
+ // Create new authors_books records.
+ java.util.Iterator<Integer> q = authIds.iterator();
+ while(q.hasNext())
+ {
+ stmt = context.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;
+ }
+
+ return BookPrxHelper.uncheckedCast(current.adapter.createProxy(BookI.createIdentity(bookId)));
+ }
+ catch(java.sql.SQLException e)
+ {
+ JDBCException ex = new JDBCException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ LibraryI()
+ {
+ }
+
+ synchronized public void
+ destroy()
+ {
+ if(_destroyed)
+ {
+ return;
+ }
+ _destroyed = true;
+ java.util.Iterator<QueryProxyPair> p = _queries.iterator();
+ while(p.hasNext())
+ {
+ try
+ {
+ p.next().proxy.destroy();
+ }
+ catch(Ice.ObjectNotExistException e)
+ {
+ // Ignore, it could have already been destroyed.
+ }
+ }
+ }
+
+ synchronized public void
+ shutdown()
+ {
+ if(_destroyed)
+ {
+ return;
+ }
+ _destroyed = true;
+
+ // Shutdown each of the associated query objects.
+ java.util.Iterator<QueryProxyPair> p = _queries.iterator();
+ while(p.hasNext())
+ {
+ p.next().impl.shutdown();
+ }
+ }
+
+ synchronized private void
+ add(BookQueryResultPrx proxy, BookQueryResultI impl)
+ {
+ // If the session has been destroyed, then destroy the book
+ // result, and raise an ObjectNotExistException.
+ if(_destroyed)
+ {
+ proxy.destroy();
+ throw new Ice.ObjectNotExistException();
+ }
+ _queries.add(new QueryProxyPair(proxy, impl));
+ }
+
+ synchronized private void
+ reapQueries()
+ {
+ if(_destroyed)
+ {
+ throw new Ice.ObjectNotExistException();
+ }
+
+ java.util.Iterator<QueryProxyPair> p = _queries.iterator();
+ while(p.hasNext())
+ {
+ QueryProxyPair pair = p.next();
+ try
+ {
+ pair.proxy.ice_ping();
+ }
+ catch(Ice.ObjectNotExistException e)
+ {
+ p.remove();
+ }
+ }
+ }
+
+ static class QueryProxyPair
+ {
+ QueryProxyPair(BookQueryResultPrx p, BookQueryResultI i)
+ {
+ proxy = p;
+ impl = i;
+ }
+
+ BookQueryResultPrx proxy;
+ BookQueryResultI impl;
+ }
+
+ private java.util.List<QueryProxyPair> _queries = new java.util.LinkedList<QueryProxyPair>();
+ private boolean _destroyed = false;
+}
diff --git a/java/demo/Database/library/Parser.java b/java/demo/Database/library/Parser.java
new file mode 100644
index 00000000000..2b2b8cb71fd
--- /dev/null
+++ b/java/demo/Database/library/Parser.java
@@ -0,0 +1,443 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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 all books that start with the given ISBN number.\n" +
+ "authors NAME Find all books by the given authors.\n" +
+ "title NAME Find all books which have the given title.\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 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;
+ }
+
+ BookDescriptionSeqHolder first = new BookDescriptionSeqHolder();
+ Ice.IntHolder nrows = new Ice.IntHolder();
+ BookQueryResultPrxHolder result = new BookQueryResultPrxHolder();
+ _library.queryByIsbn((String)args.get(0), 1, first, nrows, result);
+
+ System.out.println(nrows.value + " results");
+ if(nrows.value == 0)
+ {
+ return;
+ }
+
+ _current = first.value.get(0);
+ _query = result.value;
+ printCurrent();
+ }
+ 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;
+ }
+
+ BookDescriptionSeqHolder first = new BookDescriptionSeqHolder();
+ Ice.IntHolder nrows = new Ice.IntHolder();
+ BookQueryResultPrxHolder result = new BookQueryResultPrxHolder();
+ _library.queryByAuthor((String)args.get(0), 1, first, nrows, result);
+
+ System.out.println(nrows.value + " results");
+ if(nrows.value == 0)
+ {
+ return;
+ }
+
+ _current = first.value.get(0);
+ _query = result.value;
+ printCurrent();
+ }
+ catch(Ice.LocalException ex)
+ {
+ error(ex.toString());
+ }
+ }
+
+ void
+ findTitle(java.util.List args)
+ {
+ if(args.size() != 1)
+ {
+ error("`title' 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;
+ }
+
+ BookDescriptionSeqHolder first = new BookDescriptionSeqHolder();
+ Ice.IntHolder nrows = new Ice.IntHolder();
+ BookQueryResultPrxHolder result = new BookQueryResultPrxHolder();
+ _library.queryByTitle((String)args.get(0), 1, first, nrows, result);
+
+ System.out.println(nrows.value + " results");
+ if(nrows.value == 0)
+ {
+ return;
+ }
+
+ _current = first.value.get(0);
+ _query = result.value;
+ printCurrent();
+ }
+ catch(Ice.LocalException ex)
+ {
+ error(ex.toString());
+ }
+ }
+
+ void
+ nextFoundBook()
+ {
+ if(_query == null)
+ {
+ System.out.println("no next book");
+ return;
+ }
+
+ try
+ {
+ Ice.BooleanHolder destroyed = new Ice.BooleanHolder();
+ java.util.List<BookDescription> next = _query.next(1, destroyed);
+ if(next.size() > 0)
+ {
+ _current = next.get(0);
+ }
+ else
+ {
+ assert destroyed.value;
+ _current = null;
+ }
+ if(destroyed.value)
+ {
+ _query = null;
+ }
+ printCurrent();
+ }
+ catch(Ice.ObjectNotExistException ex)
+ {
+ System.out.println("the query object no longer exists");
+ }
+ catch(Ice.LocalException ex)
+ {
+ error(ex.toString());
+ }
+ }
+
+ void
+ printCurrent()
+ {
+ 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");
+ }
+ }
+
+ 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) + "'");
+ _current = _current.proxy.describe();
+ }
+ else
+ {
+ System.out.println("no current book");
+ }
+ }
+ catch(BookRentedException ex)
+ {
+ System.out.println("the book has already been rented");
+ }
+ catch(InvalidCustomerException ex)
+ {
+ System.out.println("the customer name is invalid");
+ }
+ 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");
+ _current = _current.proxy.describe();
+ }
+ 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;
+ }
+
+ int
+ parse(String file)
+ {
+ _query = null;
+ _current = null;
+
+ try
+ {
+ _in = new java.io.BufferedReader(new java.io.FileReader(file));
+ }
+ catch(java.io.FileNotFoundException ex)
+ {
+ error(ex.getMessage());
+ return 1;
+ }
+
+ Grammar g = new Grammar(this);
+ g.parse();
+
+ System.out.println();
+
+ try
+ {
+ _in.close();
+ }
+ catch(java.io.IOException ex)
+ {
+ }
+
+ 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..b7e44a0dbdb
--- /dev/null
+++ b/java/demo/Database/library/README
@@ -0,0 +1,103 @@
+MySQL JDBC Demo
+===============
+
+This demo shows how to implement an Ice server that uses mysql through
+a JDBC API and demonstrates the following techniques:
+
+ - Mapping relational data to Ice objects, and in particular the
+ conversion between Ice and JDBC types.
+ - Using a JDBC connection pool to provide JDBC connections for Ice
+ requests.
+ - Using an Ice servant locator.
+ - Using a dispatch interceptor.
+
+
+Building the demo
+-----------------
+
+1. Install mysql if necessary.
+
+2. Download version 5.0.8 of the mysql JDBC connector here:
+
+ http://dev.mysql.com/downloads/connector/j/5.0.html
+
+ After extracting the archive, add mysql-connector-java-5.0.8-bin.jar
+ to your CLASSPATH.
+
+3. Create a database named "library" and grant privileges to a user. In
+ the commands below, replace USER with the name you have chosen and
+ PASSWORD with a suitable password:
+
+ $ mysql -u root -p
+ Enter password:
+ Welcome to the MySQL monitor.
+
+ mysql> CREATE DATABASE library;
+ Query OK, 1 row affected (0.00 sec)
+
+ mysql> GRANT ALL PRIVILEGES ON library.* TO "USER"@"localhost"
+ -> IDENTIFIED BY "PASSWORD";
+ Query OK, 0 rows affected (0.00 sec)
+
+ mysql> FLUSH PRIVILEGES;
+ Query OK, 0 rows affected (0.01 sec)
+
+ mysql> EXIT
+
+4. Create the SQL tables using the script createTypes.sql:
+
+ $ mysql --user=USER --pass=PASSWORD library < createTypes.sql
+
+5. Edit the JDBC properties in config.server to reflect your selected
+ user name and password:
+
+ JDBC.Username=USER
+ JDBC.Password=PASSWORD
+
+NOTE: The instructions assume that the demo server runs on the same
+ host as the mysql server. If you intend to run the demo server on
+ a different host than the mysql server, you will need to revise
+ the mysql privileges as well as the JDBC URL in config.server.
+
+
+Running the demo
+----------------
+
+To run the demo, first start the server:
+
+$ java Server
+
+The demo includes a text file named "books" containing a series of
+commands that populate the server's database with a collection of
+books. Pass this file as an argument the first time you run the
+client. In another window:
+
+$ java Client books
+
+Type "help" to get a list of valid commands.
+
+
+Running the demo with Glacier2
+------------------------------
+
+The demo also supports a Glacier2 deployment. You will need to edit
+config.client and uncomment these configuration parameters:
+
+#Ice.Default.Router=DemoGlacier2/router:ssl -p 4064 -h 127.0.0.1
+#Ice.ACM.Client=0
+#Ice.RetryIntervals=-1
+
+To run the demo using Glacier2, first start the server:
+
+$ java Server
+
+In a separate window, start the Glacier2 router:
+
+$ glacier2router --Ice.Config=config.glacier2
+
+In a separate window, start the client:
+
+$ java Client books
+
+Omit the "books" argument if you have already populated the server's
+database.
diff --git a/java/demo/Database/library/ReapThread.java b/java/demo/Database/library/ReapThread.java
new file mode 100644
index 00000000000..b44a79b6e8b
--- /dev/null
+++ b/java/demo/Database/library/ReapThread.java
@@ -0,0 +1,127 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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)
+ {
+ glacier2proxy = null;
+ proxy = p;
+ session = s;
+ }
+
+ SessionProxyPair(Glacier2.SessionPrx p, SessionI s)
+ {
+ glacier2proxy = p;
+ proxy = null;
+ session = s;
+ }
+
+ Glacier2.SessionPrx glacier2proxy;
+ Demo.SessionPrx proxy;
+ SessionI session;
+ }
+
+ ReapThread(Ice.Logger logger, long timeout)
+ {
+ _logger = logger;
+ _timeout = timeout;
+ }
+
+ synchronized public void
+ run()
+ {
+ while(!_terminated)
+ {
+ try
+ {
+ wait((_timeout / 2) * 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 * 1000)
+ {
+ _logger.trace("ReapThread", "The session " +
+ s.proxy.ice_getCommunicator().identityToString(s.proxy.ice_getIdentity()) +
+ " has timed out.");
+ if(s.proxy != null)
+ {
+ s.proxy.destroy();
+ }
+ else
+ {
+ s.glacier2proxy.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 are 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));
+ }
+
+ synchronized public void
+ add(Glacier2.SessionPrx proxy, SessionI session)
+ {
+ _sessions.add(new SessionProxyPair(proxy, session));
+ }
+
+ private final long _timeout; // 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..e616218df9e
--- /dev/null
+++ b/java/demo/Database/library/RunParser.java
@@ -0,0 +1,220 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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
+{
+ //
+ // Adapter for the two types of session objects.
+ //
+ interface SessionAdapter
+ {
+ public LibraryPrx getLibrary();
+ public void destroy();
+ public void refresh();
+ }
+
+ static class Glacier2SessionAdapter implements SessionAdapter
+ {
+ public LibraryPrx getLibrary()
+ {
+ return _session.getLibrary();
+ }
+
+ public void destroy()
+ {
+ _session.destroy();
+ }
+
+ public void refresh()
+ {
+ _session.refresh();
+ }
+
+ Glacier2SessionAdapter(Glacier2SessionPrx session)
+ {
+ _session = session;
+ }
+
+ private Glacier2SessionPrx _session;
+ }
+
+ static class DemoSessionAdapter implements SessionAdapter
+ {
+ public LibraryPrx getLibrary()
+ {
+ return _session.getLibrary();
+ }
+
+ public void destroy()
+ {
+ _session.destroy();
+ }
+
+ public void refresh()
+ {
+ _session.refresh();
+ }
+
+ DemoSessionAdapter(SessionPrx session)
+ {
+ _session = session;
+ }
+
+ private SessionPrx _session;
+ }
+
+ static private class SessionRefreshThread extends Thread
+ {
+ SessionRefreshThread(Ice.Logger logger, long timeout, SessionAdapter session)
+ {
+ _logger = logger;
+ _session = session;
+ _timeout = timeout; // seconds.
+ }
+
+ synchronized public void
+ run()
+ {
+ while(!_terminated)
+ {
+ try
+ {
+ wait(_timeout * 1000);
+ }
+ 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 SessionAdapter _session;
+ final private long _timeout;
+ private boolean _terminated = false;
+ }
+
+ static int
+ runParser(String appName, String[] args, Ice.Communicator communicator)
+ {
+ SessionAdapter session;
+ Glacier2.RouterPrx router = Glacier2.RouterPrxHelper.uncheckedCast(communicator.getDefaultRouter());
+ long timeout;
+ if(router != null)
+ {
+ Glacier2.SessionPrx glacier2session = null;
+ java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));
+ while(true)
+ {
+ System.out.println("This demo accepts any user-id / password combination.");
+
+ try
+ {
+ String id;
+ System.out.print("user id: ");
+ System.out.flush();
+ id = in.readLine();
+
+ String pw;
+ System.out.print("password: ");
+ System.out.flush();
+ pw = in.readLine();
+
+ try
+ {
+ glacier2session = router.createSession(id, pw);
+ timeout = router.getSessionTimeout() / 2;
+ break;
+ }
+ catch(Glacier2.PermissionDeniedException ex)
+ {
+ System.out.println("permission denied:\n" + ex.reason);
+ }
+ catch(Glacier2.CannotCreateSessionException ex)
+ {
+ System.out.println("cannot create session:\n" + ex.reason);
+ }
+ }
+ catch(java.io.IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ session = new Glacier2SessionAdapter(Glacier2SessionPrxHelper.uncheckedCast(glacier2session));
+ }
+ else
+ {
+ SessionFactoryPrx factory = SessionFactoryPrxHelper.checkedCast(
+ communicator.propertyToProxy("SessionFactory.Proxy"));
+ if(factory == null)
+ {
+ System.err.println(appName + ": invalid object reference");
+ return 1;
+ }
+
+ session = new DemoSessionAdapter(factory.create());
+ timeout = factory.getSessionTimeout()/2;
+ }
+ SessionRefreshThread refresh = new SessionRefreshThread(communicator.getLogger(), timeout, session);
+ refresh.start();
+
+ LibraryPrx library = session.getLibrary();
+
+ Parser parser = new Parser(communicator, library);
+
+ int rc = 0;
+
+ if(args.length == 1)
+ {
+ rc = parser.parse(args[0]);
+ }
+
+ if(rc == 0)
+ {
+ 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/SQLRequestContext.java b/java/demo/Database/library/SQLRequestContext.java
new file mode 100644
index 00000000000..533e74be491
--- /dev/null
+++ b/java/demo/Database/library/SQLRequestContext.java
@@ -0,0 +1,181 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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.
+//
+// **********************************************************************
+
+//
+// A SQL request context encapsulates SQL resources allocated in the
+// process of executing a request, such as the database connection,
+// and associated SQL statements.
+//
+// The request context is automatically destroyed at the end of a
+// request, or if obtain is called it must be destroyed manually by
+// calling destroy.
+//
+// When the request context is destroyed, the transaction is either
+// automatically committed or rolled back, depending whether the
+// request executed successfully.
+//
+class SQLRequestContext
+{
+ public static SQLRequestContext
+ getCurrentContext()
+ {
+ synchronized(_contextMap)
+ {
+ return _contextMap.get(Thread.currentThread());
+ }
+ }
+
+ public static void
+ initialize(Ice.Logger logger, ConnectionPool pool)
+ {
+ assert _logger == null;
+ assert _pool == null;
+
+ _logger = logger;
+ _pool = pool;
+ }
+
+ public java.sql.PreparedStatement
+ prepareStatement(String sql)
+ throws java.sql.SQLException
+ {
+ java.sql.PreparedStatement stmt = _conn.prepareStatement(sql);
+ _statements.add(stmt);
+ return stmt;
+ }
+
+ public java.sql.PreparedStatement
+ prepareStatement(String sql, int autoGeneratedKeys)
+ throws java.sql.SQLException
+ {
+ java.sql.PreparedStatement stmt = _conn.prepareStatement(sql, autoGeneratedKeys);
+ _statements.add(stmt);
+ return stmt;
+ }
+
+ // Called to obtain ownership of the context. The context is no
+ // longer destroyed automatically when the current request has
+ // completed.
+ public void
+ obtain()
+ {
+ if(_trace)
+ {
+ _logger.trace("SQLRequestContext", "obtain context: " + this +
+ " thread: " + Thread.currentThread());
+ }
+ _obtain = true;
+ }
+
+ public void
+ destroy(boolean commit)
+ {
+ // Must only be called on an obtained context.
+ assert _obtain;
+ destroyInternal(commit);
+ }
+
+ public void
+ error(String prefix, 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(prefix + ": error:\n" + sw.toString());
+ }
+
+ SQLRequestContext()
+ {
+ _conn = _pool.acquire();
+
+ synchronized(_contextMap)
+ {
+ if(_trace)
+ {
+ _logger.trace("SQLRequestContext", "create new context: " + this +
+ " thread: " + Thread.currentThread() +
+ ": connection: " + _conn);
+ }
+
+ _contextMap.put(Thread.currentThread(), this);
+ }
+ }
+
+ // Called only during the dispatch process.
+ void
+ destroyFromDispatch(boolean commit)
+ {
+ synchronized(_contextMap)
+ {
+ // Remove the current context from the thread->context
+ // map.
+ SQLRequestContext context = _contextMap.remove(Thread.currentThread());
+ assert context != null;
+ }
+
+ // If the context was obtained then don't destroy.
+ if(!_obtain)
+ {
+ destroyInternal(commit);
+ }
+ }
+
+ private void
+ destroyInternal(boolean commit)
+ {
+ // Release all resources.
+ try
+ {
+ if(commit)
+ {
+ _conn.commit();
+ if(_trace)
+ {
+ _logger.trace("SQLRequestContext", "commit context: " + this);
+ }
+ }
+ else
+ {
+ _conn.rollback();
+ if(_trace)
+ {
+ _logger.trace("SQLRequestContext", "rollback context: " + this);
+ }
+ }
+
+ java.util.Iterator<java.sql.Statement> p = _statements.iterator();
+ while(p.hasNext())
+ {
+ p.next().close();
+ }
+ }
+ catch(java.sql.SQLException e)
+ {
+ error("SQLRequestContext", e);
+ }
+
+ _pool.release(_conn);
+
+ _statements.clear();
+ _conn = null;
+ }
+
+ // A map of threads to request contexts.
+ private static java.util.Map<Thread, SQLRequestContext> _contextMap =
+ new java.util.HashMap<Thread, SQLRequestContext>();
+
+ private static Ice.Logger _logger = null;
+ private static ConnectionPool _pool = null;
+
+ private boolean _trace = true;
+ private java.util.List<java.sql.Statement> _statements = new java.util.LinkedList<java.sql.Statement>();
+ private java.sql.Connection _conn;
+ private boolean _obtain = false;
+}
diff --git a/java/demo/Database/library/Scanner.java b/java/demo/Database/library/Scanner.java
new file mode 100644
index 00000000000..879396725b4
--- /dev/null
+++ b/java/demo/Database/library/Scanner.java
@@ -0,0 +1,283 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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("title"))
+ {
+ return new Token(Token.TOK_FIND_TITLE);
+ }
+ 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..b2e66386ffa
--- /dev/null
+++ b/java/demo/Database/library/Server.java
@@ -0,0 +1,142 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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 LocatorI implements Ice.ServantLocator
+ {
+ public Ice.Object
+ locate(Ice.Current c, Ice.LocalObjectHolder cookie)
+ {
+ assert c.id.category.equals("book");
+ return _servant;
+ }
+
+ public void
+ finished(Ice.Current c, Ice.Object servant, Object cookie)
+ {
+ }
+
+ public void
+ deactivate(String category)
+ {
+ }
+
+ LocatorI(Ice.Object servant)
+ {
+ _servant = new DispatchInterceptorI(servant);
+ }
+
+ private Ice.Object _servant;
+ }
+
+ public int
+ run(String[] args)
+ {
+ args = communicator().getProperties().parseCommandLineOptions("JDBC", 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;
+ }
+
+ long timeout = properties.getPropertyAsIntWithDefault("SessionTimeout", 30);
+
+ ReapThread reaper = new ReapThread(logger, timeout);
+ reaper.start();
+
+ //
+ // Create an object adapter
+ //
+ Ice.ObjectAdapter adapter = communicator().createObjectAdapter("SessionFactory");
+
+ SQLRequestContext.initialize(logger, pool);
+ adapter.addServantLocator(new LocatorI(new BookI()), "book");
+
+ adapter.add(new SessionFactoryI(logger, reaper, timeout), communicator().stringToIdentity("SessionFactory"));
+ adapter.add(new Glacier2SessionManagerI(logger, reaper),
+ communicator().stringToIdentity("LibrarySessionManager"));
+
+ //
+ // 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/Session.ice b/java/demo/Database/library/Session.ice
new file mode 100644
index 00000000000..5640227eb05
--- /dev/null
+++ b/java/demo/Database/library/Session.ice
@@ -0,0 +1,82 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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_SESSION_ICE
+#define LIBRARY_SESSION_ICE
+
+module Demo
+{
+
+/* Forward declaration. */
+interface Library;
+
+/**
+ *
+ * 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();
+
+ /**
+ *
+ * Get the value of the session timeout. Sessions are destroyed
+ * if they see no activity for this period of time.
+ *
+ * @return The timeout (in seconds).
+ *
+ **/
+ ["nonmutating", "cpp:const"] idempotent long getSessionTimeout();
+};
+
+};
+
+#endif
diff --git a/java/demo/Database/library/SessionFactoryI.java b/java/demo/Database/library/SessionFactoryI.java
new file mode 100644
index 00000000000..31ab6716cd3
--- /dev/null
+++ b/java/demo/Database/library/SessionFactoryI.java
@@ -0,0 +1,46 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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
+{
+ public synchronized SessionPrx
+ create(Ice.Current c)
+ {
+ SessionI session = new SessionI(_logger, c.adapter);
+ _SessionTie servant = new _SessionTie(session);
+
+ SessionPrx proxy = SessionPrxHelper.uncheckedCast(c.adapter.addWithUUID(servant));
+
+ _logger.trace("SessionFactory", "create new session: " +
+ c.adapter.getCommunicator().identityToString(proxy.ice_getIdentity()));
+
+ _reaper.add(proxy, session);
+
+ return proxy;
+ }
+
+ public long
+ getSessionTimeout(Ice.Current c)
+ {
+ return _timeout;
+ }
+
+ SessionFactoryI(Ice.Logger logger, ReapThread reaper, long timeout)
+ {
+ _logger = logger;
+ _reaper = reaper;
+ _timeout = timeout;
+ }
+
+ private Ice.Logger _logger;
+ private ReapThread _reaper;
+ private long _timeout;
+}
diff --git a/java/demo/Database/library/SessionI.java b/java/demo/Database/library/SessionI.java
new file mode 100644
index 00000000000..6b213e9b0ab
--- /dev/null
+++ b/java/demo/Database/library/SessionI.java
@@ -0,0 +1,96 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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 implements _SessionOperations, _Glacier2SessionOperations
+{
+ 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 long
+ getSessionTimeout(Ice.Current c)
+ {
+ if(_destroyed)
+ {
+ throw new Ice.ObjectNotExistException();
+ }
+ return 5000;
+ }
+
+ synchronized public void
+ destroy(Ice.Current c)
+ {
+ if(_destroyed)
+ {
+ throw new Ice.ObjectNotExistException();
+ }
+
+ _destroyed = true;
+ _logger.trace("Session", "session " + c.adapter.getCommunicator().identityToString(c.id) +
+ " is now destroyed.");
+
+ // This method is never called on shutdown of the server.
+ _libraryI.destroy();
+ c.adapter.remove(_library.ice_getIdentity());
+ c.adapter.remove(c.id);
+ }
+
+ // Called on application shutdown.
+ synchronized public void
+ shutdown()
+ {
+ if(!_destroyed)
+ {
+ _destroyed = true;
+ _libraryI.shutdown();
+ }
+ }
+
+ synchronized public long
+ timestamp()
+ {
+ if(_destroyed)
+ {
+ throw new Ice.ObjectNotExistException();
+ }
+ return _timestamp;
+ }
+
+ SessionI(Ice.Logger logger, Ice.ObjectAdapter adapter)
+ {
+ _logger = logger;
+ _timestamp = System.currentTimeMillis();
+ _libraryI = new LibraryI();
+ _library = LibraryPrxHelper.uncheckedCast(adapter.addWithUUID(new DispatchInterceptorI(_libraryI)));
+ }
+
+ private Ice.Logger _logger;
+ 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 _libraryI;
+}
diff --git a/java/demo/Database/library/Token.java b/java/demo/Database/library/Token.java
new file mode 100644
index 00000000000..348edff9b58
--- /dev/null
+++ b/java/demo/Database/library/Token.java
@@ -0,0 +1,40 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 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_FIND_TITLE = 5;
+ public static final int TOK_NEXT_FOUND_BOOK = 6;
+ public static final int TOK_PRINT_CURRENT = 7;
+ public static final int TOK_RENT_BOOK = 8;
+ public static final int TOK_RETURN_BOOK = 9;
+ public static final int TOK_REMOVE_CURRENT = 10;
+ public static final int TOK_STRING = 11;
+ public static final int TOK_SEMI = 12;
+
+ 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..915b235a438
--- /dev/null
+++ b/java/demo/Database/library/build.xml
@@ -0,0 +1,55 @@
+<!--
+ **********************************************************************
+
+ Copyright (c) 2003-2009 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_Database_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}" tie="on">
+ <meta value="${java2metadata}"/>
+ <includepath>
+ <pathelement path="${slice.dir}" />
+ </includepath>
+ <fileset dir="." includes="Library.ice"/>
+ <fileset dir="." includes="Session.ice"/>
+ <fileset dir="." includes="Glacier2Session.ice"/>
+ </slice2java>
+ </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..9f0fa65a663
--- /dev/null
+++ b/java/demo/Database/library/config.client
@@ -0,0 +1,62 @@
+#
+# The client reads this property to create the reference to the
+# "SessionFactory" object in the server.
+#
+SessionFactory.Proxy=SessionFactory:default -p 10000
+
+#
+# The proxy to the Glacier2 router for all outgoing connections. This
+# must match the value of Glacier2.Client.Endpoints in config.glacier2.
+#
+#Ice.Default.Router=DemoGlacier2/router:ssl -p 4064 -h 127.0.0.1
+
+#
+# No active connection management is permitted because of the session
+# interfaces. Connections must remain established.
+#
+Ice.ACM.Client=0
+
+#
+# Connection retry is not possible because of the session
+# interfaces. Connections must remain established.
+#
+Ice.RetryIntervals=-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
+
+#
+# Security Tracing
+#
+# 0 = no security tracing
+# 1 = trace messages
+#
+#IceSSL.Trace.Security=1
+
+#
+# SSL Configuration
+#
+Ice.Plugin.IceSSL=IceSSL.PluginFactory
+IceSSL.DefaultDir=../../../../certs
+IceSSL.Truststore=certs.jks
+IceSSL.TrustOnly.Client=CN=Server
diff --git a/java/demo/Database/library/config.glacier2 b/java/demo/Database/library/config.glacier2
new file mode 100644
index 00000000000..053dbff990b
--- /dev/null
+++ b/java/demo/Database/library/config.glacier2
@@ -0,0 +1,55 @@
+#
+# Set the Glacier2 instance name.
+#
+Glacier2.InstanceName=DemoGlacier2
+
+#
+# The client-visible endpoint of Glacier2. This should be an endpoint
+# visible from the public Internet, and it should be secure.
+#
+Glacier2.Client.Endpoints=ssl -p 4064 -h 127.0.0.1
+
+#
+# The server-visible endpoint of Glacier2. This endpoint is only
+# required if callbacks are needed (leave empty otherwise). This
+# should be an endpoint on an internal network (like 192.168.x.x), or
+# on the loopback, so that the server is not directly accessible from
+# the Internet.
+#
+Glacier2.Server.Endpoints=tcp -h 127.0.0.1
+
+#
+# The proxy of the session manager.
+#
+Glacier2.SessionManager=LibrarySessionManager:tcp -h 127.0.0.1 -p 10000
+
+#
+# For this demo, we use the null permissions verifier. This permissions
+# verifier allows any user-id / password combination.
+#
+Glacier2.PermissionsVerifier=DemoGlacier2/NullPermissionsVerifier
+
+#
+# The timeout for inactive sessions. If any client session is inactive
+# for longer than this value, the session expires and is removed. The
+# unit is seconds.
+#
+Glacier2.SessionTimeout=30
+
+#
+# Security Tracing
+#
+# 0 = no security tracing
+# 1 = trace messages
+#
+IceSSL.Trace.Security=1
+
+#
+# SSL Configuration
+#
+Ice.Plugin.IceSSL=IceSSL:createIceSSL
+IceSSL.DefaultDir=../../../../certs
+IceSSL.CertAuthFile=cacert.pem
+IceSSL.CertFile=s_rsa1024_pub.pem
+IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.VerifyPeer=0
diff --git a/java/demo/Database/library/config.server b/java/demo/Database/library/config.server
new file mode 100644
index 00000000000..ef3eef86199
--- /dev/null
+++ b/java/demo/Database/library/config.server
@@ -0,0 +1,64 @@
+#
+# Configure the server endpoints.
+#
+SessionFactory.Endpoints=tcp -p 10000:ssl -p 10001
+
+# JDBC configuration.
+JDBC.Username=USER
+JDBC.Password=PASSWORD
+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=5
+
+#
+# How long to keep sessions alive with no activity. Its best to use
+# the same value as config.glacier2.
+#
+SessionTimeout=30
+
+#
+# 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
+
+#
+# Security Tracing
+#
+# 0 = no security tracing
+# 1 = trace messages
+#
+#IceSSL.Trace.Security=1
+
+#
+# SSL Configuration
+#
+Ice.Plugin.IceSSL=IceSSL.PluginFactory
+IceSSL.VerifyPeer=0
+IceSSL.DefaultDir=../../../../certs
+IceSSL.Keystore=server.jks
+IceSSL.Password=password
+IceSSL.Truststore=certs.jks
diff --git a/java/demo/Database/library/createTypes.sql b/java/demo/Database/library/createTypes.sql
new file mode 100644
index 00000000000..ec5fc72e5c3
--- /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
+) ENGINE=InnoDB;
+
+DROP TABLE IF EXISTS authors_books;
+CREATE TABLE authors_books
+(
+ book_id INT,
+ author_id INT
+) ENGINE=InnoDB;
+
+DROP TABLE IF EXISTS authors;
+CREATE TABLE authors
+(
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY(id),
+ name VARCHAR(255)
+) ENGINE=InnoDB;
+
+DROP TABLE IF EXISTS customers;
+CREATE TABLE customers
+(
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY(id),
+ name VARCHAR(255)
+) ENGINE=InnoDB;