1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002, 2014 Oracle and/or its affiliates. All rights reserved. 5 * 6 */ 7 8 package com.sleepycat.je.jca.ra; 9 10 import java.io.PrintWriter; 11 import java.util.ArrayList; 12 import java.util.HashMap; 13 import java.util.Iterator; 14 import java.util.Map; 15 16 import javax.resource.ResourceException; 17 import javax.resource.spi.ConnectionEvent; 18 import javax.resource.spi.ConnectionEventListener; 19 import javax.resource.spi.ConnectionRequestInfo; 20 import javax.resource.spi.LocalTransaction; 21 import javax.resource.spi.ManagedConnection; 22 import javax.resource.spi.ManagedConnectionMetaData; 23 import javax.security.auth.Subject; 24 import javax.transaction.xa.XAResource; 25 26 import com.sleepycat.je.Database; 27 import com.sleepycat.je.DatabaseConfig; 28 import com.sleepycat.je.DatabaseException; 29 import com.sleepycat.je.DbInternal; 30 import com.sleepycat.je.SecondaryConfig; 31 import com.sleepycat.je.SecondaryDatabase; 32 import com.sleepycat.je.TransactionConfig; 33 import com.sleepycat.je.XAEnvironment; 34 35 public class JEManagedConnection implements ManagedConnection { 36 private final ArrayList<ConnectionEventListener> listeners; 37 private JEConnection conn; 38 private XAEnvironment env; 39 private JELocalTransaction savedLT; 40 private TransactionConfig savedTransConfig; 41 private final Map<String,Database> rwDatabaseHandleCache; 42 private final Map<String,Database> roDatabaseHandleCache; 43 private final Map<String,Database> rwSecondaryDatabaseHandleCache; 44 private final Map<String,Database> roSecondaryDatabaseHandleCache; 45 JEManagedConnection(Subject subject, JERequestInfo jeInfo)46 JEManagedConnection(Subject subject, JERequestInfo jeInfo) 47 throws ResourceException { 48 49 try { 50 savedTransConfig = jeInfo.getTransactionConfig(); 51 this.env = new XAEnvironment(jeInfo.getJERootDir(), 52 jeInfo.getEnvConfig()); 53 } catch (DatabaseException DE) { 54 throw new ResourceException(DE.toString()); 55 } 56 listeners = new ArrayList<ConnectionEventListener>(); 57 savedLT = null; 58 rwDatabaseHandleCache = new HashMap<String,Database>(); 59 roDatabaseHandleCache = new HashMap<String,Database>(); 60 rwSecondaryDatabaseHandleCache = new HashMap<String,Database>(); 61 roSecondaryDatabaseHandleCache = new HashMap<String,Database>(); 62 } 63 getConnection(Subject subject, ConnectionRequestInfo connectionRequestInfo)64 public Object getConnection(Subject subject, 65 ConnectionRequestInfo connectionRequestInfo) { 66 if (conn == null) { 67 conn = new JEConnection(this); 68 } 69 return conn; 70 } 71 getEnvironment()72 protected XAEnvironment getEnvironment() { 73 return env; 74 } 75 getLocalTransaction()76 public LocalTransaction getLocalTransaction() { 77 78 /* 79 * If there is no JEConnection associated with this ManagedConnection 80 * yet, then the ManagedConnection holds on to the JELocalTransaction. 81 * Once a JEConnection is associated (it may not ever happen), we hand 82 * off the JELocalTransaction to the JEConnection and forget about it 83 * in the ManagedConnection. 84 */ 85 if (conn == null) { 86 savedLT = new JELocalTransaction(env, savedTransConfig, this); 87 return savedLT; 88 } 89 90 JELocalTransaction lt = conn.getLocalTransaction(); 91 if (lt == null) { 92 if (savedLT == null) { 93 lt = new JELocalTransaction(env, savedTransConfig, this); 94 } else { 95 lt = savedLT; 96 } 97 conn.setLocalTransaction(lt); 98 savedLT = null; 99 } 100 return lt; 101 } 102 getXAResource()103 public XAResource getXAResource() { 104 return env; 105 } 106 associateConnection(Object connection)107 public void associateConnection(Object connection) { 108 conn = (JEConnection) connection; 109 conn.setManagedConnection(this, savedLT); 110 savedLT = null; 111 } 112 addConnectionEventListener(ConnectionEventListener listener)113 public void addConnectionEventListener(ConnectionEventListener listener) { 114 listeners.add(listener); 115 } 116 117 public void removeConnectionEventListener(ConnectionEventListener listener)118 removeConnectionEventListener(ConnectionEventListener listener) { 119 120 listeners.remove(listener); 121 } 122 getMetaData()123 public ManagedConnectionMetaData getMetaData() { 124 return new JEConnectionMetaData(); 125 } 126 setLogWriter(PrintWriter out)127 public void setLogWriter(PrintWriter out) { 128 } 129 getLogWriter()130 public PrintWriter getLogWriter() { 131 return null; 132 } 133 close()134 protected void close() { 135 ConnectionEvent connEvent = 136 new ConnectionEvent(this, ConnectionEvent.CONNECTION_CLOSED); 137 connEvent.setConnectionHandle(conn); 138 sendConnectionEvent(connEvent); 139 } 140 sendConnectionEvent(ConnectionEvent connEvent)141 protected void sendConnectionEvent(ConnectionEvent connEvent) { 142 for (int i = listeners.size() - 1; i >= 0; i--) { 143 ConnectionEventListener listener = 144 listeners.get(i); 145 if (connEvent.getId() == ConnectionEvent.CONNECTION_CLOSED) { 146 listener.connectionClosed(connEvent); 147 } else if (connEvent.getId() == 148 ConnectionEvent.CONNECTION_ERROR_OCCURRED) { 149 listener.connectionErrorOccurred(connEvent); 150 } else if (connEvent.getId() == 151 ConnectionEvent.LOCAL_TRANSACTION_STARTED) { 152 listener.localTransactionStarted(connEvent); 153 } else if (connEvent.getId() == 154 ConnectionEvent.LOCAL_TRANSACTION_COMMITTED) { 155 listener.localTransactionCommitted(connEvent); 156 } else if (connEvent.getId() == 157 ConnectionEvent.LOCAL_TRANSACTION_ROLLEDBACK) { 158 listener.localTransactionRolledback(connEvent); 159 } 160 } 161 } 162 destroy()163 public void destroy() 164 throws ResourceException { 165 166 try { 167 cleanupDatabaseHandleCache(roDatabaseHandleCache); 168 cleanupDatabaseHandleCache(rwDatabaseHandleCache); 169 cleanupDatabaseHandleCache(roSecondaryDatabaseHandleCache); 170 cleanupDatabaseHandleCache(rwSecondaryDatabaseHandleCache); 171 env.close(); 172 } catch (DatabaseException DE) { 173 throw new ResourceException(DE.toString()); 174 } 175 } 176 cleanup()177 public void cleanup() { 178 } 179 removeDatabase(String dbName)180 void removeDatabase(String dbName) 181 throws DatabaseException { 182 183 removeDatabaseFromCache(roDatabaseHandleCache, dbName); 184 removeDatabaseFromCache(rwDatabaseHandleCache, dbName); 185 removeDatabaseFromCache(roSecondaryDatabaseHandleCache, dbName); 186 removeDatabaseFromCache(rwSecondaryDatabaseHandleCache, dbName); 187 env.removeDatabase(null, dbName); 188 } 189 truncateDatabase(String dbName, boolean returnCount)190 long truncateDatabase(String dbName, boolean returnCount) 191 throws DatabaseException { 192 193 removeDatabaseFromCache(roDatabaseHandleCache, dbName); 194 removeDatabaseFromCache(rwDatabaseHandleCache, dbName); 195 removeDatabaseFromCache(roSecondaryDatabaseHandleCache, dbName); 196 removeDatabaseFromCache(rwSecondaryDatabaseHandleCache, dbName); 197 return env.truncateDatabase(null, dbName, returnCount); 198 } 199 openDatabase(String dbName, DatabaseConfig config)200 Database openDatabase(String dbName, DatabaseConfig config) 201 throws DatabaseException { 202 203 if (config.getReadOnly()) { 204 synchronized (roDatabaseHandleCache) { 205 return openDatabaseInternal 206 (roDatabaseHandleCache, dbName, config); 207 } 208 } else { 209 synchronized (rwDatabaseHandleCache) { 210 return openDatabaseInternal 211 (rwDatabaseHandleCache, dbName, config); 212 } 213 } 214 } 215 openSecondaryDatabase(String dbName, Database primaryDatabase, SecondaryConfig config)216 SecondaryDatabase openSecondaryDatabase(String dbName, 217 Database primaryDatabase, 218 SecondaryConfig config) 219 throws DatabaseException { 220 221 if (config.getReadOnly()) { 222 synchronized (roSecondaryDatabaseHandleCache) { 223 return openSecondaryDatabaseInternal 224 (roSecondaryDatabaseHandleCache, dbName, 225 primaryDatabase, config); 226 } 227 } else { 228 synchronized (rwSecondaryDatabaseHandleCache) { 229 return openSecondaryDatabaseInternal 230 (rwSecondaryDatabaseHandleCache, dbName, 231 primaryDatabase, config); 232 } 233 } 234 } 235 236 private Database openDatabaseInternal(Map<String,Database> databaseHandleCache, String dbName, DatabaseConfig config)237 openDatabaseInternal(Map<String,Database> databaseHandleCache, 238 String dbName, 239 DatabaseConfig config) 240 throws DatabaseException { 241 242 Database db; 243 if (config.getExclusiveCreate()) { 244 db = env.openDatabase(null, dbName, config); 245 databaseHandleCache.put(dbName, db); 246 } else { 247 db = databaseHandleCache.get(dbName); 248 if (db == null) { 249 db = env.openDatabase(null, dbName, config); 250 databaseHandleCache.put(dbName, db); 251 } else { 252 DbInternal.validate(config, db.getConfig()); 253 } 254 } 255 return db; 256 } 257 258 private SecondaryDatabase openSecondaryDatabaseInternal(Map<String,Database> databaseHandleCache, String dbName, Database primaryDatabase, SecondaryConfig config)259 openSecondaryDatabaseInternal(Map<String,Database> databaseHandleCache, 260 String dbName, 261 Database primaryDatabase, 262 SecondaryConfig config) 263 throws DatabaseException { 264 265 SecondaryDatabase db; 266 if (config.getExclusiveCreate()) { 267 db = env.openSecondaryDatabase(null, dbName, 268 primaryDatabase, config); 269 databaseHandleCache.put(dbName, db); 270 } else { 271 db = (SecondaryDatabase) databaseHandleCache.get(dbName); 272 if (db == null) { 273 db = env.openSecondaryDatabase(null, dbName, 274 primaryDatabase, config); 275 databaseHandleCache.put(dbName, db); 276 } else { 277 DbInternal.validate(config, db.getConfig()); 278 } 279 } 280 return db; 281 } 282 removeDatabaseFromCache(Map<String,Database> cache, String dbName)283 private void removeDatabaseFromCache(Map<String,Database> cache, 284 String dbName) 285 throws DatabaseException { 286 287 synchronized (cache) { 288 Database db = cache.get(dbName); 289 if (db == null) { 290 return; 291 } 292 db.close(); 293 cache.remove(dbName); 294 } 295 } 296 cleanupDatabaseHandleCache(Map<String,Database> cache)297 private void cleanupDatabaseHandleCache(Map<String,Database> cache) 298 throws DatabaseException { 299 300 synchronized (cache) { 301 Iterator<Database> iter = cache.values().iterator(); 302 303 while (iter.hasNext()) { 304 Database db = iter.next(); 305 db.close(); 306 } 307 } 308 } 309 } 310