EMMA Coverage Report (generated Sat Nov 03 21:53:04 GMT 2007)
[all classes][sf.qof.session]

COVERAGE SUMMARY FOR SOURCE FILE [SessionContextFactory.java]

nameclass, %method, %block, %line, %
SessionContextFactory.java88%  (7/8)87%  (34/39)91%  (493/544)89%  (97.6/110)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class SessionContextFactory$10%   (0/1)100% (0/0)100% (0/0)100% (0/0)
     
class SessionContextFactory$SessionState100% (1/1)50%  (2/4)76%  (29/38)88%  (1.8/2)
valueOf (String): SessionContextFactory$SessionState 0%   (0/1)0%   (0/5)0%   (0/1)
values (): SessionContextFactory$SessionState [] 0%   (0/1)0%   (0/4)0%   (0/1)
<static initializer> 100% (1/1)100% (24/24)100% (2/2)
SessionContextFactory$SessionState (String, int): void 100% (1/1)100% (5/5)100% (1/1)
     
class SessionContextFactory$DefaultUserTransaction$TransactionState100% (1/1)50%  (2/4)84%  (49/58)92%  (1.8/2)
valueOf (String): SessionContextFactory$DefaultUserTransaction$TransactionState 0%   (0/1)0%   (0/5)0%   (0/1)
values (): SessionContextFactory$DefaultUserTransaction$TransactionState [] 0%   (0/1)0%   (0/4)0%   (0/1)
<static initializer> 100% (1/1)100% (44/44)100% (2/2)
SessionContextFactory$DefaultUserTransaction$TransactionState (String, int): ... 100% (1/1)100% (5/5)100% (1/1)
     
class SessionContextFactory$DefaultUserTransaction100% (1/1)100% (7/7)90%  (163/181)85%  (34/40)
commit (): void 100% (1/1)79%  (45/57)73%  (11/15)
rollback (): void 100% (1/1)83%  (29/35)75%  (6/8)
SessionContextFactory$DefaultUserTransaction (Connection): void 100% (1/1)100% (9/9)100% (4/4)
begin (): void 100% (1/1)100% (22/22)100% (4/4)
close (): void 100% (1/1)100% (4/4)100% (2/2)
isRollbackOnly (): boolean 100% (1/1)100% (29/29)100% (3/3)
setRollbackOnly (): void 100% (1/1)100% (25/25)100% (4/4)
     
class SessionContextFactory100% (1/1)83%  (5/6)93%  (38/41)85%  (11/13)
SessionContextFactory (): void 0%   (0/1)0%   (0/3)0%   (0/2)
<static initializer> 100% (1/1)100% (5/5)100% (1/1)
getContext (): SessionContext 100% (1/1)100% (3/3)100% (1/1)
getContext (String): SessionContext 100% (1/1)100% (20/20)100% (5/5)
setDataSource (DataSource): void 100% (1/1)100% (4/4)100% (2/2)
setDataSource (String, DataSource): void 100% (1/1)100% (6/6)100% (2/2)
     
class SessionContextFactory$DefaultSessionContext100% (1/1)100% (8/8)94%  (173/185)90%  (37/41)
stopSession (): void 100% (1/1)87%  (40/46)83%  (10/12)
startSession (): void 100% (1/1)91%  (59/65)86%  (12/14)
SessionContextFactory$DefaultSessionContext (String): void 100% (1/1)100% (12/12)100% (4/4)
SessionContextFactory$DefaultSessionContext (String, SessionContextFactory$1)... 100% (1/1)100% (4/4)100% (1/1)
access$100 (SessionContextFactory$DefaultSessionContext, DataSource): void 100% (1/1)100% (4/4)100% (1/1)
getConnection (): Connection 100% (1/1)100% (25/25)100% (4/4)
getUserTransaction (): UserTransaction 100% (1/1)100% (25/25)100% (4/4)
setDataSource (DataSource): void 100% (1/1)100% (4/4)100% (2/2)
     
class SessionContextFactory$DefaultSessionContext$1100% (1/1)100% (2/2)100% (11/11)100% (2/2)
SessionContextFactory$DefaultSessionContext$1 (SessionContextFactory$DefaultS... 100% (1/1)100% (6/6)100% (1/1)
initialValue (): SessionContextFactory$Session 100% (1/1)100% (5/5)100% (1/1)
     
class SessionContextFactory$Session100% (1/1)100% (8/8)100% (30/30)100% (11/11)
SessionContextFactory$Session (): void 100% (1/1)100% (6/6)100% (2/2)
SessionContextFactory$Session (SessionContextFactory$1): void 100% (1/1)100% (3/3)100% (1/1)
getConnection (): Connection 100% (1/1)100% (3/3)100% (1/1)
getState (): SessionContextFactory$SessionState 100% (1/1)100% (3/3)100% (1/1)
getUserTransaction (): UserTransaction 100% (1/1)100% (3/3)100% (1/1)
setConnection (Connection): void 100% (1/1)100% (4/4)100% (2/2)
setState (SessionContextFactory$SessionState): void 100% (1/1)100% (4/4)100% (2/2)
setUserTransaction (UserTransaction): void 100% (1/1)100% (4/4)100% (2/2)

1/*
2 * Copyright 2007 brunella ltd
3 *
4 * Licensed under the LGPL Version 3 (the "License");
5 * you may not use this file except in compliance with the License.
6 *
7 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
8 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
11 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
12 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
13 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
14 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
15 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
16 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
17 * THE POSSIBILITY OF SUCH DAMAGE.
18 */
19package sf.qof.session;
20 
21import java.sql.Connection;
22import java.sql.SQLException;
23import java.util.HashMap;
24import java.util.Map;
25 
26import javax.sql.DataSource;
27 
28/**
29 * Implementation of a session context factory.
30 * 
31 * <code>SessionContextFactory</code> provides factory methods to create and cache
32 * <code>SessionContext</code> objects.
33 * 
34 * <p>The <code>SessionContextFactory</code> can be used in the following way:</p>
35 * 
36 * <p><blockquote><pre>
37 * DataSource ds = ... // get the data source from somewhere
38 * // register the data source with the default session context 
39 * SessionContextFactory.setDataSource(ds);
40 * ...
41 * // get the default session context
42 * SessionContext ctx = SessionContextFactory.getContext();
43 * 
44 * // start a new session 
45 * ctx.startSession();
46 * 
47 * // start a new transaction
48 * ctx.getUserTransaction().begin();
49 * 
50 * // get the database connection for the current session
51 * Connection con = ctx.getConnection();
52 * 
53 * // do something with the connection
54 * ...
55 * 
56 * // commit and end the current transaction
57 * ctx.getUserTransaction().commit();
58 * 
59 * // stop the session
60 * ctx.stopSession();
61 * </pre></blockquote></p>
62 * 
63 * @see sf.qof.session.SessionContext
64 * @see sf.qof.session.UserTransaction
65 * 
66 */
67public class SessionContextFactory {
68 
69  private final static Map<String, SessionContext> sessionContextMap = new HashMap<String, SessionContext>();
70 
71  private SessionContextFactory() {
72  }
73 
74  /**
75   * Creates and returns the default <code>SessionContext</code>.  
76   * 
77   * @return the session context
78   */
79  public static SessionContext getContext() {
80        return getContext(SessionContext.DEFAULT_CONTEXT_NAME);
81  }
82 
83  /**
84   * Creates and returns the <code>SessionContext</code> for a given context name.
85   * 
86   * @param contextName the context name
87   * @return the session context
88   */
89  public synchronized static SessionContext getContext(String contextName) {
90        SessionContext sessionContext = sessionContextMap.get(contextName);
91        if (sessionContext == null) {
92          sessionContext = new DefaultSessionContext(contextName);
93          sessionContextMap.put(contextName, sessionContext);
94        }
95        return sessionContext;
96  }
97 
98  /**
99   * Registers a <code>DataSource</code> with the default session context.
100   * 
101   * @param dataSource  the data source
102   */
103  public static void setDataSource(DataSource dataSource) {
104        setDataSource(SessionContext.DEFAULT_CONTEXT_NAME, dataSource);
105  }
106 
107  /**
108   * Registers a <code>DataSource</code> with the specified session context. 
109   * 
110   * @param contextName  the session context name
111   * @param dataSource   the data source
112   */
113  public static void setDataSource(String contextName, DataSource dataSource) {
114        ((DefaultSessionContext) getContext(contextName)).setDataSource(dataSource);
115  }
116 
117  /**
118   * Internal implementation of <code>SessionContext</code>. 
119   *
120   * Uses a <code>ThreadLocal</code> field to handle sessions for different threads.
121   * 
122   */
123  protected static class DefaultSessionContext implements SessionContext {
124 
125        private DataSource dataSource;
126        private String contextName;
127 
128        private ThreadLocal<Session> sessionThreadLocal = new ThreadLocal<Session>() {
129          protected synchronized Session initialValue() {
130                return new Session();
131          }
132        };
133 
134        private DefaultSessionContext(String contextName) {
135          this.contextName = contextName;
136        }
137 
138        private void setDataSource(DataSource dataSource) {
139          this.dataSource = dataSource;
140        }
141 
142        public Connection getConnection() {
143          Session session = sessionThreadLocal.get();
144          if (session.getState() == SessionState.STOPPED) {
145                throw new IllegalStateException(
146                        "Session is not running in thread for context " + contextName);
147          } else {
148                return session.getConnection();
149          }
150        }
151 
152        public UserTransaction getUserTransaction() {
153          Session session = sessionThreadLocal.get();
154          if (session.getState() == SessionState.STOPPED) {
155                throw new IllegalStateException(
156                        "Session is not running in thread for context " + contextName);
157          } else {
158                return session.getUserTransaction();
159          }
160        }
161 
162        public void startSession() throws SystemException {
163          Session session = sessionThreadLocal.get();
164          if (session.getState() == SessionState.RUNNING) {
165                throw new IllegalStateException(
166                        "Session already running in thread for context " + contextName);
167          } else {
168                if (dataSource == null) {
169                  throw new SystemException("No data source defined for context "
170                          + contextName);
171                }
172                Connection connection;
173                try {
174                  connection = dataSource.getConnection();
175                  connection.setAutoCommit(false);
176                } catch (SQLException e) {
177                  throw new SystemException(e);
178                }
179                session.setConnection(connection);
180                session.setUserTransaction(new DefaultUserTransaction(connection));
181                session.setState(SessionState.RUNNING);
182          }
183        }
184 
185        public void stopSession() throws SystemException {
186          Session session = sessionThreadLocal.get();
187          if (session.getState() == SessionState.STOPPED) {
188                throw new IllegalStateException(
189                        "Session is not running in thread for context " + contextName);
190          } else {
191                session.setState(SessionState.STOPPED);
192                try {
193                  ((DefaultUserTransaction) session.getUserTransaction()).close();
194                  session.setUserTransaction(null);
195                  session.getConnection().close();
196                  session.setConnection(null);
197                } catch (SQLException e) {
198                  throw new SystemException(e);
199                }
200          }
201        }
202        
203        
204  }
205 
206  private static class Session {
207 
208        private Connection connection;
209        private UserTransaction userTransaction;
210        private SessionState state = SessionState.STOPPED;
211 
212        public Connection getConnection() {
213          return connection;
214        }
215 
216        public void setConnection(Connection connection) {
217          this.connection = connection;
218        }
219 
220        public SessionState getState() {
221          return state;
222        }
223 
224        public void setState(SessionState state) {
225          this.state = state;
226        }
227 
228        public UserTransaction getUserTransaction() {
229          return userTransaction;
230        }
231 
232        public void setUserTransaction(UserTransaction userTransaction) {
233          this.userTransaction = userTransaction;
234        }
235  }
236 
237  private static enum SessionState {
238        STOPPED, RUNNING
239  }
240 
241  /**
242   * Internal implementation of <code>UserTransaction</code>.
243   *
244   */
245  protected static class DefaultUserTransaction implements UserTransaction {
246 
247        private Connection connection;
248 
249        private TransactionState transactionState;
250 
251        /**
252         * Constructs a DefaultUserTransaction object.
253         *
254         * @param connection  the current database connection
255         */
256        public DefaultUserTransaction(Connection connection) {
257          this.connection = connection;
258          this.transactionState = TransactionState.NEW;
259        }
260 
261        public void begin() throws SystemException {
262          if (transactionState == TransactionState.NEW) {
263                transactionState = TransactionState.IN_TRANSACTION;
264          } else {
265                throw new IllegalStateException("Invalid state: Transaction is " + transactionState);
266          }
267        }
268 
269        public void commit() throws SystemException, RollbackException {
270          if (transactionState == TransactionState.NEW
271                  || transactionState == TransactionState.CLOSED) {
272                throw new IllegalStateException("Invalid state: Transaction is " + transactionState);
273          } else {
274                if (transactionState == TransactionState.IN_TRANSACTION_ROLLBACK) {
275                  transactionState = TransactionState.NEW;
276                  try {
277                        connection.rollback();
278                  } catch (SQLException e) {
279                        throw new SystemException(e);
280                  }
281                  throw new RollbackException("Transaction was rolled back");
282                } else {
283                  transactionState = TransactionState.NEW;
284                  try {
285                        connection.commit();
286                  } catch (SQLException e) {
287                        throw new SystemException(e);
288                  }
289                }
290          }
291        }
292 
293        public boolean isRollbackOnly() {
294          if (transactionState == TransactionState.NEW
295                  || transactionState == TransactionState.CLOSED) {
296                throw new IllegalStateException("Invalid state: Transaction is " + transactionState);
297          } else {
298                return transactionState == TransactionState.IN_TRANSACTION_ROLLBACK;
299          }
300        }
301 
302        public void rollback() throws SystemException {
303          if (transactionState == TransactionState.NEW
304                  || transactionState == TransactionState.CLOSED) {
305                throw new IllegalStateException("Invalid state: Transaction is " + transactionState);
306          } else {
307                try {
308                  transactionState = TransactionState.NEW;
309                  connection.rollback();
310                } catch (SQLException e) {
311                  throw new SystemException(e);
312                }
313          }
314        }
315 
316        public void setRollbackOnly() throws SystemException {
317          if (transactionState == TransactionState.NEW
318                  || transactionState == TransactionState.CLOSED) {
319                throw new IllegalStateException("Invalid state: Transaction is " + transactionState);
320          } else {
321                transactionState = TransactionState.IN_TRANSACTION_ROLLBACK;
322          }
323        }
324 
325        /**
326         * Closes the transaction.
327         */
328        public void close() {
329          transactionState = TransactionState.CLOSED;
330        }
331 
332        private static enum TransactionState {
333          NEW, IN_TRANSACTION, IN_TRANSACTION_ROLLBACK, CLOSED
334        }
335 
336  }
337}

[all classes][sf.qof.session]
EMMA 2.0.5312 (C) Vladimir Roubtsov