PageRenderTime 37ms CodeModel.GetById 2ms app.highlight 29ms RepoModel.GetById 2ms app.codeStats 0ms

/src/com/google/appengine/datanucleus/DatastoreConnectionFactoryImpl.java

http://datanucleus-appengine.googlecode.com/
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}