001: /*
002: * User: Michael Rettig
003: * Date: Aug 13, 2002
004: * Time: 10:53:29 AM
005: */
006: package net.sourceforge.jaxor;
007:
008: import net.sourceforge.jaxor.api.*;
009: import net.sourceforge.jaxor.db.SingleConnectionTransaction;
010: import net.sourceforge.jaxor.impl.InstanceCacheImpl;
011: import net.sourceforge.jaxor.impl.UnitOfWorkImpl;
012: import net.sourceforge.jaxor.util.MethodCache;
013: import net.sourceforge.jaxor.util.SystemException;
014:
015: import java.sql.Connection;
016:
017: /**
018: * This class is the main interaction point with the persistence
019: * framework. Its main responsiblity is managing the connections used
020: * for executing the SQL statements to map the enities to the
021: * relational database and coordinating the UnitOfWork implementation.
022: * <p>
023: * Essentially, the JaxorSession can be used as a "smarter" UnitOfWork
024: * implementation everwhere you would normally employ the UnitOfWork
025: * design pattern as described in Fowler2003. For example, in a
026: * servlet's doGet method, you could use:
027: * <pre>
028: * final protected void doGet(HttpServletRequest request,
029: * HttpServletResponse response)
030: * throws ServletException, IOException {
031: *
032: * // we specify a transaction-aware implementation of UnitOfWork
033: * // since the default version does not manage JDBC transactions
034: * JaxorSession.begin(new TransUnitOfWork());
035: * handleGet(request, response);
036: * JaxorSession.flush();
037: *
038: * }
039: * </pre>
040: * </p>
041: * <p>
042: * The above example assumes that whatever connection retrieval
043: * mechanism was previously configured in the servlet's init method
044: * using the <code>setDefaultConnectionFactory</code> method.
045: * </p>
046: * <p>
047: * Alternatively, for a command-line utility you would generally use
048: * the following sequence of API calls:
049: *
050: * <pre>
051: * public static void main(String[] args) {
052: * JaxorSession.begin(new TransUnitOfWork(), new ConnectionFactoryImpl());
053: * handleCommands(args);
054: * JaxorSession.flush();
055: * }
056: * </pre>
057: * </p>
058: * <p>
059: * For a Java Swing client that uses Jaxor, the <code>begin</code> and
060: * <code>flush</code> calls would be specified in each of the Action
061: * implementations.
062: * </p>
063: * @see #begin()
064: * @see #commit()
065: * @see #setDefaultFactory
066: */
067:
068: public class JaxorSession {
069: private static final ThreadLocal SESSIONS = new ThreadLocal();
070: private static JaxorContextFactory _defaultFactory = null;
071:
072: /**
073: * This method is the most generic of the <code>begin</code>
074: * methods and allows the client to control both the
075: * <code>UnitOfWork</code> and <code>ConnectionFactory</code>
076: * instances to be specified for the logical Jaxor transaction.
077: *
078: * @param uow the UnitOfWork implementation to be used
079: * @param factory the ConnectionFactory
080: */
081:
082: public static void begin(UnitOfWork uow, JaxorTransaction factory) {
083: setSession(uow, new InstanceCacheImpl(), new MethodCache(),
084: factory);
085: }
086:
087: /**
088: * This method should be called to flush the UnitOfWork held by
089: * the session. This method causes all of the inserts, updates,
090: * and deletes to happen in the database.
091: */
092:
093: public static void commit() {
094: getJaxorContext().commit();
095: }
096:
097: /**
098: * This method completely resets the session's context.
099: */
100:
101: public static void end() {
102: JaxorContext conn = getJaxorContext();
103: if (conn != null)
104: conn.end();
105: SESSIONS.set(null);
106: }
107:
108: private static void setSession(UnitOfWork newWork,
109: InstanceCache cache, QueryCache query,
110: JaxorTransaction factory) {
111: setJaxorContext(new JaxorContextImpl(factory, cache, query,
112: newWork));
113: }
114:
115: /**
116: * This method is called internally to change the active
117: * JaxorContext. It should not normally be called by Jaxor clients.
118: *
119: * @param context the new JaxorContext
120: */
121:
122: public static void setJaxorContext(JaxorContext context) {
123: SESSIONS.set(new JaxorSession(context));
124: }
125:
126: public static JaxorContext getJaxorContext() {
127: JaxorSession jaxorSession = getJaxorSession();
128: if (jaxorSession != null)
129: return jaxorSession._context;
130: return null;
131: }
132:
133: private static JaxorSession getJaxorSession() {
134: return (JaxorSession) SESSIONS.get();
135: }
136:
137: public static void begin(Connection conn) {
138: begin(new SingleConnectionTransaction(conn));
139: }
140:
141: /**
142: * This method is called by Jaxor clients to start a new
143: * transaction using the default UnitOfWork implementation and the
144: * indicated connection factory.
145: *
146: * @param factory the connection factory to be used for this
147: * transaction
148: */
149:
150: public static void begin(JaxorTransaction factory) {
151: begin(new UnitOfWorkImpl(), factory);
152: }
153:
154: /**
155: * This method is used to specify a default ConnectionFactory
156: * instance to be used for all subsequent JaxorSession
157: * transactions. Setting a default factory does not preclude the
158: * use of a different connection factory by calling the {@link
159: * #begin()} method with an appropriate factory instance.
160: * <p>
161: * NOTE: calling this method will replace any existing connection
162: * factory for all subsequent transactions started with
163: * begin().
164: * </p>
165: *
166: * @param factory the new default factory
167: */
168:
169: public static void setDefaultFactory(JaxorContextFactory factory) {
170: _defaultFactory = factory;
171: }
172:
173: /**
174: * This overloaded version of <code>begin</code> will use the
175: * default connection factory specified using the <code>
176: * setDefaultConnectionFactory</code> method.
177: *
178: * @exception NullPointerException
179: * if no connection factory has been specified
180: * @see #begin()
181: * @see #setDefaultFactory
182: */
183:
184: public static void begin() {
185: if (_defaultFactory == null) {
186: throw new NullPointerException(
187: "error: no default connection factory specified");
188: }
189:
190: setJaxorContext(_defaultFactory.create());
191: }
192:
193: private final JaxorContext _context;
194:
195: private JaxorSession(JaxorContext context) {
196: _context = context;
197: }
198:
199: }
|