/src/com/google/appengine/datanucleus/DatastoreConnectionFactoryImpl.java
Java | 230 lines | 130 code | 33 blank | 67 comment | 12 complexity | 32051aa6143ecce74a67aac689f0ddc7 MD5 | raw file
1/********************************************************************** 2Copyright (c) 2009 Google Inc. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15**********************************************************************/ 16package com.google.appengine.datanucleus; 17 18import com.google.appengine.api.datastore.DatastoreService; 19import com.google.appengine.api.datastore.DatastoreServiceConfig; 20 21import org.datanucleus.ExecutionContext; 22import org.datanucleus.PersistenceConfiguration; 23import org.datanucleus.Transaction; 24import org.datanucleus.store.StoreManager; 25import org.datanucleus.store.connection.AbstractConnectionFactory; 26import org.datanucleus.store.connection.ManagedConnection; 27import org.datanucleus.store.connection.ManagedConnectionResourceListener; 28import org.datanucleus.util.NucleusLogger; 29 30import java.util.ArrayList; 31import java.util.List; 32import java.util.Map; 33 34import javax.transaction.xa.XAResource; 35 36/** 37 * Factory for connections to the datastore. There are two connection factories for a DatastoreManager. 38 * <ul> 39 * <li>Transactional : a connection (DatastoreService) is obtained at the start of the transaction and we 40 * call "beginTransaction" on it. It is closed at the end of the transaction after we call "commit"/"rollback".</li> 41 * <li>Nontransactional : a connection (DatastoreService) is obtained on the first operation, and is retained 42 * until PM/EM.close(). All operations are atomic, since we don't call "beginTransaction", hence no need to call 43 * "commit"/"rollback"</li> 44 * </ul> 45 * 46 * <p> 47 * By default, when the user invokes transaction.begin() in user-space this will start a DatastoreTransaction. 48 * If they have the persistence property <i>datanucleus.appengine.autoCreateDatastoreTxns</i> set to false 49 * then this means it will NOT start a transaction. Why anyone would want to do this is unknown to me 50 * but anyway it's there. 51 * </p> 52 * 53 * @author Max Ross <maxr@google.com> 54 */ 55public class DatastoreConnectionFactoryImpl extends AbstractConnectionFactory { 56 57 public static final String AUTO_CREATE_TXNS_PROPERTY = 58 "datanucleus.appengine.autoCreateDatastoreTxns"; 59 60 private final boolean isAutoCreateTransaction; 61 62 /** 63 * Constructs a connection factory for the datastore. 64 * Provides ManagedConnections to communicate with the datastore. 65 * 66 * @param storeMgr The store manager 67 * @param resourceType Name of the resource ("appengine", "appengine-nontx") 68 */ 69 public DatastoreConnectionFactoryImpl(StoreManager storeMgr, String resourceType) { 70 super(storeMgr, resourceType); 71 72 PersistenceConfiguration conf = storeMgr.getNucleusContext().getPersistenceConfiguration(); 73 if (conf.getProperty(DatastoreConnectionFactoryImpl.AUTO_CREATE_TXNS_PROPERTY) == null) { 74 // User hasn't configured the "auto-create" property, so set it 75 conf.setProperty(DatastoreConnectionFactoryImpl.AUTO_CREATE_TXNS_PROPERTY, Boolean.TRUE.toString()); 76 } 77 this.isAutoCreateTransaction = conf.getBooleanProperty(AUTO_CREATE_TXNS_PROPERTY); 78 } 79 80 public void close() {} 81 82 /** 83 * {@inheritDoc} 84 */ 85 public ManagedConnection getConnection(ExecutionContext ec, Transaction txn, Map options) { 86 return storeMgr.getConnectionManager().allocateConnection(this, ec, txn, options); 87 } 88 89 /** 90 * {@inheritDoc} 91 */ 92 public ManagedConnection createManagedConnection(ExecutionContext ec, Map transactionOptions) { 93 return new DatastoreManagedConnection(storeMgr, isAutoCreateTransaction()); 94 } 95 96 boolean isAutoCreateTransaction() { 97 return isAutoCreateTransaction; 98 } 99 100 // TODO Change this to extend AbstractManagedConnection 101 static class DatastoreManagedConnection implements ManagedConnection { 102 private boolean managed = false; 103 private boolean locked = false; 104 private final List<ManagedConnectionResourceListener> listeners = 105 new ArrayList<ManagedConnectionResourceListener>(); 106 private final XAResource datastoreXAResource; 107 108 DatastoreManagedConnection(StoreManager storeMgr, boolean autoCreateTransaction) { 109 DatastoreManager datastoreManager = (DatastoreManager) storeMgr; 110 DatastoreServiceConfig config = datastoreManager.getDefaultDatastoreServiceConfigForWrites(); 111 DatastoreService datastoreService = DatastoreServiceFactoryInternal.getDatastoreService(config); 112 if (NucleusLogger.CONNECTION.isDebugEnabled()) { 113 if (datastoreService instanceof WrappedDatastoreService) { 114 NucleusLogger.CONNECTION.debug("Created ManagedConnection using DatastoreService = " + 115 ((WrappedDatastoreService)datastoreService).getDelegate()); 116 } else { 117 NucleusLogger.CONNECTION.debug("Created ManagedConnection using DatastoreService = " + datastoreService); 118 } 119 } 120 if (autoCreateTransaction) { 121 datastoreXAResource = new DatastoreXAResource( 122 datastoreService, datastoreManager.getDefaultDatastoreTransactionOptions()); 123 } else { 124 datastoreXAResource = new EmulatedXAResource(datastoreService); 125 } 126 } 127 128 /* (non-Javadoc) 129 * @see org.datanucleus.store.connection.ManagedConnection#closeAfterTransactionEnd() 130 */ 131 @Override 132 public boolean closeAfterTransactionEnd() { 133 return true; 134 } 135 136 /* (non-Javadoc) 137 * @see org.datanucleus.store.connection.ManagedConnection#closeOnRelease() 138 */ 139 @Override 140 public boolean closeOnRelease() { 141 return false; 142 } 143 144 /* (non-Javadoc) 145 * @see org.datanucleus.store.connection.ManagedConnection#commitOnRelease() 146 */ 147 @Override 148 public boolean commitOnRelease() { 149 return false; 150 } 151 152 /* (non-Javadoc) 153 * @see org.datanucleus.store.connection.ManagedConnection#setCloseOnRelease(boolean) 154 */ 155 @Override 156 public void setCloseOnRelease(boolean flag) { 157 } 158 159 /* (non-Javadoc) 160 * @see org.datanucleus.store.connection.ManagedConnection#setCommitOnRelease(boolean) 161 */ 162 @Override 163 public void setCommitOnRelease(boolean flag) { 164 } 165 166 public Object getConnection() { 167 // Return the DatastoreService 168 return ((EmulatedXAResource)datastoreXAResource).getDatastoreService(); 169 } 170 171 public XAResource getXAResource() { 172 return datastoreXAResource; 173 } 174 175 public void release() { 176 if (!managed) { 177 close(); 178 } 179 } 180 181 public void close() { 182 // Take copy since listeners can de-register themselves at close 183 List<ManagedConnectionResourceListener> resourceListeners = new ArrayList(listeners); 184 185 for (ManagedConnectionResourceListener listener : resourceListeners) { 186 listener.managedConnectionPreClose(); 187 } 188 // nothing to actually close 189 for (ManagedConnectionResourceListener listener : resourceListeners) { 190 listener.managedConnectionPostClose(); 191 } 192 } 193 194 public void setManagedResource() { 195 managed = true; 196 } 197 198 public boolean isLocked() { 199 return locked; 200 } 201 202 public void lock() { 203 locked = true; 204 } 205 206 public void unlock() { 207 locked = false; 208 } 209 210 public void transactionFlushed() { 211 for (ManagedConnectionResourceListener listener : listeners) { 212 listener.transactionFlushed(); 213 } 214 } 215 216 public void transactionPreClose() { 217 for (ManagedConnectionResourceListener listener : listeners) { 218 listener.transactionPreClose(); 219 } 220 } 221 222 public void addListener(ManagedConnectionResourceListener listener) { 223 listeners.add(listener); 224 } 225 226 public void removeListener(ManagedConnectionResourceListener listener) { 227 listeners.remove(listener); 228 } 229 } 230}