Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/PersistenceManagerWrapper.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/PersistenceManagerWrapper.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/PersistenceManagerWrapper.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/PersistenceManagerWrapper.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,764 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * PersistenceManagerWrapper.java + * + * Created on January 16, 2001 + */ + +package org.apache.jdo.impl.pm; + +import java.util.*; + +import javax.jdo.*; + +import org.apache.jdo.pm.PersistenceManagerInternal; +import org.apache.jdo.util.I18NHelper; + + +/** + * This is a thin wrapper for the current implemetation of javax.jdo.PersistenceManager + * interface. Delegates most of method execution to the corresponding instance of + * the PersistenceManagerImpl. Becomes invalid after PersistenceManager is closed. + * + * @author Marina Vatkina + */ +public class PersistenceManagerWrapper implements PersistenceManager { + + // Previous PersistenceManagerWrapper + private PersistenceManagerWrapper prev = null; + + // Actual PersistenceManager + private PersistenceManagerImpl pm = null; + + // Boolean flag that allows to use this wrapper + private boolean isValid = false; + + /** + * I18N message handler + */ + private final static I18NHelper msg = + I18NHelper.getInstance("org.apache.jdo.impl.pm.Bundle"); // NOI18N + + // Constructed by PersistenceManagerFactoryImpl + PersistenceManagerWrapper(PersistenceManagerImpl pm) { + this.pm = pm; + prev = (PersistenceManagerWrapper)pm.getCurrentWrapper(); + pm.pushCurrentWrapper(this); + isValid = true; + } + + /** + * @see javax.jdo.PersistenceManager#isClosed() + */ + public boolean isClosed() { + if (isValid) { + return pm.isClosed(); + } else { + return true; + } + } + + + /** + * @see javax.jdo.PersistenceManager#close() + */ + public void close() { + if (isValid) { + pm.popCurrentWrapper(prev); + isValid = false; + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#currentTransaction() + */ + public Transaction currentTransaction() { + if (isValid) { + return pm.currentTransaction(); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#setIgnoreCache(boolean flag) + */ + public void setIgnoreCache(boolean flag) { + if (isValid) { + pm.setIgnoreCache(flag); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#getIgnoreCache() + */ + public boolean getIgnoreCache() { + if (isValid) { + return pm.getIgnoreCache(); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + + } + + /** + * @see javax.jdo.PersistenceManager#getMultithreaded() + */ + public boolean getMultithreaded() { + if (isValid) { + return pm.getMultithreaded(); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#setMultithreaded(boolean flag) + */ + public void setMultithreaded(boolean flag) { + if (isValid) { + pm.setMultithreaded(flag); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#evict(Object pc) + */ + public void evict(Object pc) { + if (isValid) { + pm.evict(pc); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#evictAll(Object[] pcs) + */ + public void evictAll(Object[] pcs) { + if (isValid) { + pm.evictAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#evictAll(Collection pcs) + */ + public void evictAll(Collection pcs) { + if (isValid) { + pm.evictAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#evictAll() + */ + public void evictAll() { + if (isValid) { + pm.evictAll(); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#refresh(Object pc) + */ + public void refresh(Object pc) { + if (isValid) { + pm.refresh(pc); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#refreshAll(Object[] pcs) + */ + public void refreshAll(Object[] pcs) { + if (isValid) { + pm.refreshAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#refreshAll(Collection pcs) + */ + public void refreshAll(Collection pcs) { + if (isValid) { + pm.refreshAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#refreshAll() + */ + public void refreshAll() { + if (isValid) { + pm.refreshAll(); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#newQuery() + */ + public Query newQuery(){ + if (isValid) { + return pm.newQuery(); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + /** + * @see javax.jdo.PersistenceManager#newQuery(Object compiled) + */ + public Query newQuery(Object compiled){ + if (isValid) { + return pm.newQuery(compiled); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#newQuery(Class cls) + */ + public Query newQuery(Class cls){ + if (isValid) { + return pm.newQuery(cls); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#newQuery(Extent cln) + */ + public Query newQuery(Extent cln){ + if (isValid) { + return pm.newQuery(cln); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#newQuery(Class cls,Collection cln) + */ + public Query newQuery(Class cls,Collection cln){ + if (isValid) { + return pm.newQuery(cls, cln); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#newQuery(String language, Object query) + */ + public Query newQuery (String language, Object query){ + if (isValid) { + return pm.newQuery(language, query); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#newQuery(Class cls, String filter) + */ + public Query newQuery (Class cls, String filter){ + if (isValid) { + return pm.newQuery(cls, filter); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#newQuery(Class cls, Collection cln, String filter) + */ + public Query newQuery (Class cls, Collection cln, String filter){ + if (isValid) { + return pm.newQuery(cls, cln, filter); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#newQuery(Extent cln, String filter) + */ + public Query newQuery (Extent cln, String filter){ + if (isValid) { + return pm.newQuery(cln, filter); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#getExtent(Class persistenceCapableClass, + * boolean subclasses) + */ + public Extent getExtent(Class persistenceCapableClass,boolean subclasses){ + if (isValid) { + return pm.getExtent(persistenceCapableClass, subclasses); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#getObjectById(Object oid, boolean validate) + */ + public Object getObjectById(Object oid, boolean validate){ + if (isValid) { + return pm.getObjectById(oid, validate); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#getObjectId(Object pc) + */ + public Object getObjectId(Object pc){ + if (isValid) { + return pm.getObjectId(pc); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#getTransactionalObjectId (Object pc) + */ + public Object getTransactionalObjectId (Object pc) { + if (isValid) { + return pm.getTransactionalObjectId(pc); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#newObjectIdInstance (Class pcClass, String str) + */ + public Object newObjectIdInstance (Class pcClass, String str) { + if (isValid) { + return pm.newObjectIdInstance (pcClass, str); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#makePersistent(Object pc) + */ + public void makePersistent(Object pc){ + if (isValid) { + pm.makePersistent(pc); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#makePersistentAll(Object[] pc) + */ + public void makePersistentAll(Object[] pcs){ + if (isValid) { + pm.makePersistentAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#makePersistentAll(Collection pcs) + */ + public void makePersistentAll (Collection pcs){ + if (isValid) { + pm.makePersistentAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#deletePersistent(Object pc) + */ + public void deletePersistent(Object pc){ + if (isValid) { + pm.deletePersistent(pc); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#deletePersistentAll(Object[] pc) + */ + public void deletePersistentAll (Object[] pcs){ + if (isValid) { + pm.deletePersistentAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#deletePersistentAll(Collection pc) + */ + public void deletePersistentAll (Collection pcs){ + if (isValid) { + pm.deletePersistentAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#makeTransient(Object pc) + */ + public void makeTransient(Object pc){ + if (isValid) { + pm.makeTransient(pc); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#makeTransientAll(Object[] pc) + */ + public void makeTransientAll(Object[] pcs){ + if (isValid) { + pm.makeTransientAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#makeTransientAll(Collection pcs) + */ + public void makeTransientAll (Collection pcs){ + if (isValid) { + pm.makeTransientAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#makeTransactional(Object pc) + */ + public void makeTransactional(Object pc){ + if (isValid) { + pm.makeTransactional(pc); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#makeTransactionalAll(Object[] pc) + */ + public void makeTransactionalAll(Object[] pcs){ + if (isValid) { + pm.makeTransactionalAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#makeTransactionalAll(Collection pcs) + */ + public void makeTransactionalAll (Collection pcs){ + if (isValid) { + pm.makeTransactionalAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /* + * @see javax.jdo.PersistenceManager#makeNontransactional(Object pc) + */ + public void makeNontransactional(Object pc){ + if (isValid) { + pm.makeNontransactional(pc); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#makeNontransactionalAll(Object[] pc) + */ + public void makeNontransactionalAll(Object[] pcs){ + if (isValid) { + pm.makeNontransactionalAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#makeNontransactionalAll(Collection pcs) + */ + public void makeNontransactionalAll (Collection pcs){ + if (isValid) { + pm.makeNontransactionalAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** Retrieve an instance from the store. This is only a hint to + * the PersistenceManager that the application intends to use the + * instance, and its field values should be retrieved. + * <P>The PersistenceManager might use policy information about the + * class to retrieve associated instances. + */ + public void retrieve(Object pc) { + if (isValid) { + pm.retrieve(pc); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** Retrieve field values of instances from the store. This tells + * the <code>PersistenceManager</code> that the application intends to use the + * instances, and all field values must be retrieved. + * <P>The <code>PersistenceManager</code> might use policy information about the + * class to retrieve associated instances. + * @param pcs the instances + */ + public void retrieveAll(Object[] pcs) { + if (isValid) { + pm.retrieveAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** Retrieve field values of instances from the store. This tells + * the <code>PersistenceManager</code> that the application intends to use the + * instances, and their field values should be retrieved. The fields + * in the default fetch group must be retrieved, and the implementation + * might retrieve more fields than the default fetch group. + * <P>The <code>PersistenceManager</code> might use policy information about the + * class to retrieve associated instances. + * @param pcs the instances + * @param DFGOnly whether to retrieve only the default fetch group fields + * @since 1.0.1 + */ + public void retrieveAll (Object[] pcs, boolean DFGOnly) { + if (isValid) { + pm.retrieveAll(pcs, DFGOnly); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** Retrieve field values of instances from the store. This tells + * the <code>PersistenceManager</code> that the application intends to use the + * instances, and all field values must be retrieved. + * <P>The <code>PersistenceManager</code> might use policy information about the + * class to retrieve associated instances. + * @param pcs the instances + */ + public void retrieveAll(Collection pcs) { + if (isValid) { + pm.retrieveAll(pcs); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** Retrieve field values of instances from the store. This tells + * the <code>PersistenceManager</code> that the application intends to use the + * instances, and their field values should be retrieved. The fields + * in the default fetch group must be retrieved, and the implementation + * might retrieve more fields than the default fetch group. + * <P>The <code>PersistenceManager</code> might use policy information about the + * class to retrieve associated instances. + * @param pcs the instances + * @param DFGOnly whether to retrieve only the default fetch group fields + * @since 1.0.1 + */ + public void retrieveAll (Collection pcs, boolean DFGOnly) { + if (isValid) { + pm.retrieveAll(pcs, DFGOnly); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + + /** + * @see javax.jdo.PersistenceManager#getPersistenceManagerFactory() + */ + public PersistenceManagerFactory getPersistenceManagerFactory(){ + if (isValid) { + return pm.getPersistenceManagerFactory(); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#setUserObject(Object o) + */ + public void setUserObject(Object o){ + if (isValid) { + pm.setUserObject(o); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#getUserObject() + */ + public Object getUserObject(){ + if (isValid) { + return pm.getUserObject(); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * @see javax.jdo.PersistenceManager#getObjectIdClass(Class cls) + */ + public Class getObjectIdClass(Class cls){ + if (isValid) { + return pm.getObjectIdClass(cls); + } else { + throw new JDOFatalUserException(msg.msg( + "EXC_PersistenceManagerClosed"));// NOI18N + } + } + + /** + * Returns PersistenceManagerInternal associated with this wrapper. + * This method should be accessed by the PersistenceManagerInternal + * only. + * @return PersistenceManagerInternal. + */ + protected PersistenceManagerInternal getPersistenceManager() { + return (PersistenceManagerInternal)pm; + } + + /** + * Returns a hash code value for this PersistenceManagerWrapper. + * @return a hash code value for this PersistenceManagerWrapper. + */ + public int hashCode() { + return pm.hashCode(); + } + + /** + * Indicates whether some other object is "equal to" this one. + * @param obj the reference object with which to compare. + * @return <code>true</code> if this object is the same as the obj + * argument; <code>false</code> otherwise. + */ + public boolean equals(Object obj) { + if (obj instanceof PersistenceManagerWrapper) { + return (((PersistenceManagerWrapper)obj).pm == this.pm); + + } else if (obj instanceof PersistenceManagerImpl) { + return (((PersistenceManagerImpl)obj) == this.pm); + } + return false; + } +}
Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/TransactionImpl.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/TransactionImpl.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/TransactionImpl.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/TransactionImpl.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,1160 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * TransactionImpl.java + * + * Create on December 1, 2000 + */ + +package org.apache.jdo.impl.pm; + +import java.util.*; +import javax.transaction.*; + +import javax.jdo.*; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.jdo.ejb.EJBImplHelper; +import org.apache.jdo.store.Connector; +import org.apache.jdo.store.StoreManager; +import org.apache.jdo.util.I18NHelper; + +/** + * + * The Transaction interface allows operations to be performed against + * the transaction in the target Transaction object. A Transaction + * object is created corresponding to each PersistentManagerImpl creation. + * The Transaction object can be used for synchronization registration, + * transaction completion and status query operations. + * + * This implementation is StoreManager independent. + * + * @author Marina Vatkina + */ +class TransactionImpl implements javax.jdo.Transaction { + + /** + * Transaction status (from javax.transaction.Status). + */ + private int status; + + /** + * The commit process has already begun (even though the status is still + * STATUS_ACTIVE). This is the first thing set during commit or rollback. + */ + private boolean startedCommit; + + /** + * Registered Synchronization object. + */ + private Object synchronization; + + /** + * Synchronisation object associated with this transaction instance + */ + private Object txSync = null; + + /** + * PersistenceManagerFactory associated with this transaction + */ + private PersistenceManagerFactoryImpl pmFactory = null; + + /** + * PersistenceManager associated with this transaction (1-1) + */ + private PersistenceManagerImpl persistenceManager = null; + + /** + * Connector associated with this transaction + */ + private Connector connector = null; + + /** + * javax.transaction.Transaction instance associated with the current + * thread or null if there is none. + */ + private javax.transaction.Transaction jta = null; + + /** + * Flag that indicates how to handle objects after commit. + * If true, at commit instances retain their values and the instances + */ + private boolean retainValues = true; + + /** + * Flag that indicates how to handle objects after rollback. + * If true, at rollback instances have their values restored. + */ + private boolean restoreValues = true; + + /** + * Flag that indicates type of the transaction. + * Optimistic transactions do not hold data store locks until commit time. + */ + private boolean optimistic = true; + + /** + * Flag that indicates if queries and navigation are allowed + * without an active transaction + */ + private boolean nontransactionalRead = true; + + /** + * Flag that indicates if write access is allowed + * without an active transaction + */ + private boolean nontransactionalWrite = true; + + /** values for the datasource user and user password to access + * security connections + */ + private String username = null; + private String password = null; + + /** + * Possible values of txType + */ + protected static final int NON_MGD = 0; + protected static final int CMT = 1; + protected static final int BMT_UT = 2; + protected static final int BMT_JDO = 3; + + /** + * Flag to indicate usage mode (non-managed versus managed, and so on). + */ + private int txType = -1; + + /** + * Logger instance + */ + private static final Log logger = LogFactory.getFactory().getInstance( + "org.apache.jdo.impl.pm"); // NOI18N + + /** + * I18N message handler + */ + private final static I18NHelper msg = + I18NHelper.getInstance("org.apache.jdo.impl.pm.Bundle"); // NOI18N + + /** + * Constructors new instance of TransactionImpl for the corresponding + * PersistenceManagerImpl. Username and password are provided for future + * validation and Connector request. + * + * @param pm calling instance of PersistenceManagerImpl + * @param pmf PersistenceManagerFactoryImpl associated with the instance of + * PersistenceManagerImpl + * @param username user name for Connector request + * @param password user password for Connector request + */ + TransactionImpl(PersistenceManagerImpl pm, PersistenceManagerFactoryImpl pmf, + String username, String password) { + + this.status = Status.STATUS_NO_TRANSACTION; + this.startedCommit = false; + this.persistenceManager = pm; + + pmFactory = pmf; + optimistic = pmFactory.getOptimistic(); + retainValues = pmFactory.getRetainValues(); + restoreValues = pmFactory.getRestoreValues(); + nontransactionalRead = pmFactory.getNontransactionalRead(); + nontransactionalWrite = pmFactory.getNontransactionalWrite(); + + this.username = username; + this.password = password; + + } + + // + // ----- Methods from javax.jdo.Transaction interface ------ + // + + /** + * Returns PersistenceManager associated with this transaction + * @see javax.jdo.Transaction#getPersistenceManager() + */ + public javax.jdo.PersistenceManager getPersistenceManager() { + persistenceManager.assertIsOpen(); + return (javax.jdo.PersistenceManager) persistenceManager.getCurrentWrapper(); + } + + /** + * @see javax.jdo.Transaction#isActive() + */ + public boolean isActive() { + persistenceManager.assertIsOpen(); + return !isTerminated(); + } + + /** + * @see javax.jdo.Transaction#setRetainValues(boolean flag) + */ + public void setRetainValues(boolean flag) { + persistenceManager.assertIsOpen(); + + // Cannot change flag value when transaction commit is in progress. + if (startedCommit) + throw new JDOUserException(msg.msg( + "EXC_CannotSetFlag")); // NOI18N + + this.retainValues = flag; + } + + /** + * @see javax.jdo.Transaction#getRetainValues() + */ + public boolean getRetainValues() { + persistenceManager.assertIsOpen(); + return retainValues; + } + + /** + * @see javax.jdo.Transaction#setRestoreValues(boolean flag) + */ + public void setRestoreValues(boolean flag) { + persistenceManager.assertIsOpen(); + // Cannot change flag if transaction is active. + if (isActive()) { + throw new JDOUserException(msg.msg( + "EXC_CannotSetFlagIfActive")); // NOI18N + } + this.restoreValues = flag; + } + + /** + * @see javax.jdo.Transaction#getRestoreValues() + */ + public boolean getRestoreValues() { + persistenceManager.assertIsOpen(); + return restoreValues; + } + + /** + * @see javax.jdo.Transaction#setNontransactionalRead(boolean flag) + */ + public synchronized void setNontransactionalRead (boolean flag) { + persistenceManager.assertIsOpen(); + + // Cannot change flag value when transaction commit is in progress. + if (startedCommit) + throw new JDOUserException(msg.msg( + "EXC_CannotSetFlag")); // NOI18N + + this.nontransactionalRead = flag; + + } + + /** + * @see javax.jdo.Transaction#getNontransactionalRead() + */ + public boolean getNontransactionalRead() { + persistenceManager.assertIsOpen(); + return nontransactionalRead; + } + + /** + * @see javax.jdo.Transaction#setNontransactionalWrite(boolean flag) + */ + public synchronized void setNontransactionalWrite (boolean flag) { + persistenceManager.assertIsOpen(); + + // Cannot change flag value when transaction commit is in progress. + if (startedCommit) + throw new JDOUserException(msg.msg( + "EXC_CannotSetFlag")); // NOI18N + + this.nontransactionalWrite = flag; + } + + /** + * @see javax.jdo.Transaction#getNontransactionalWrite() + */ + public boolean getNontransactionalWrite() { + persistenceManager.assertIsOpen(); + return nontransactionalWrite; + } + + /** + * @see javax.jdo.Transaction#setOptimistic(boolean flag) + */ + public synchronized void setOptimistic(boolean flag) { + persistenceManager.assertIsOpen(); + + if (isTerminated()) { + this.optimistic = flag; + } else { + // Cannot change flag value inside an active transaction. + throw new JDOUserException(msg.msg( + "EXC_CannotChangeType")); // NOI18N + } + + // Notify PM about Tx type change + persistenceManager.notifyOptimistic(flag); + } + + /** + * @see javax.jdo.Transaction#getOptimistic() + */ + public boolean getOptimistic() { + persistenceManager.assertIsOpen(); + return optimistic; + } + + /** + * @see javax.jdo.Transaction#setSynchronization(Synchronization sync) + */ + public void setSynchronization(Synchronization sync) { + persistenceManager.assertIsOpen(); + if (sync == synchronization) { + return; // the same Synchronization. + + } else if (sync != null && synchronization != null) { + throw new JDOUserException(msg.msg( + "EXC_SynchronizationNotNull")); // NOI18N + } + + this.registerSynchronization(sync); + } + + /** + * @see javax.jdo.Transaction#getRetainValues() + */ + public Synchronization getSynchronization() { + persistenceManager.assertIsOpen(); + return (Synchronization)synchronization; + } + + public void assertReadAllowed() { + if ((!isActive()) && (!getNontransactionalRead())) { + throw new JDOUserException(msg.msg( + "EXC_NontransactionalRead"));// NOI18N + } + } + + /** + * Begin a transaction. + * @see javax.jdo.Transaction#begin() + */ + public void begin() { + // Check and set status... + beginInternal(); + + // BMT with JDO Transaction + if (EJBImplHelper.isManaged()) { + txType = BMT_JDO; + try { + EJBImplHelper.getUserTransaction().begin(); + jta = EJBImplHelper.getTransaction(); + if (txSync == null) + txSync = new TransactionSynchronization(this); + + jta.registerSynchronization((Synchronization)txSync); + pmFactory.registerPersistenceManager(persistenceManager, jta); + + } catch (JDOException e) { + throw e; // re-throw it. + } catch (Exception e) { + throw new JDOFatalInternalException( + "EXC_ErrorRegister", e); // NOI18N + } + } else { + // Mark as non-managed transaction. + txType = NON_MGD; + } + + } + + /** + * Commit the transaction represented by this Transaction object + * @see javax.jdo.Transaction#commit() + */ + public void commit() { + persistenceManager.assertIsOpen(); + + if (txType == CMT || txType == BMT_UT) { + // Error - should not be called + throw new JDOUserException(msg.msg( + "EXC_WrongMgdOperation", "commit")); //NOI18N + } else if (txType == BMT_JDO) { + // Send request to the container: + try { + EJBImplHelper.getUserTransaction().commit(); + return; + } catch (Exception e) { + throw new JDOException("", e); // NOI18N + } + } + + // Proceede with non-managed environment call. + synchronized (this) { + // + // Disallow parallel transaction completion calls: + // + if (startedCommit) { + throw new JDOUserException(msg.msg( + "EXC_TransactionCommitting")); // NOI18N + } + + // This flag prevents user from making any changes to the transaction object. + this.startedCommit = true; + } + + if (debugging()) + this.traceCall("commit"); // NOI18N + + try { + this.prepareFlush(true); // do actual beforeComplition. + this.commitPrepare(); // check internal status. + this.commitComplete(); // commitConnector and set status to success. + + } catch (Throwable e) { + try { + this.internalRollback(); + } catch (Exception re) { + // Do not rethrow the rollback exception - just log it. + if (debugging()) + logger.debug("Exception during rollback after failed commit: " + re); + } + + if (e instanceof JDOException) { + throw (JDOException)e; + } + throw new JDOException("", e); // NOI18N + } finally { + this.internalAfterCompletion(); // do afterCompletion and cleanup. + } + } + + /** + * Rollback the transaction represented by this transaction object. + * @see javax.jdo.Transaction#rollback() + */ + public void rollback() { + persistenceManager.assertIsOpen(); + if (txType == CMT || txType == BMT_UT) { + // Error - should not be called + throw new JDOUserException(msg.msg( + "EXC_WrongMgdOperation", "rollback")); //NOI18N + } + + if (debugging()) + this.traceCall("rollback"); // NOI18N + + synchronized (this) { + // + // Disallow parallel transaction completion calls: + // + if (startedCommit) { + throw new JDOUserException(msg.msg( + "EXC_TransactionCommitting")); // NOI18N + + } else if ((this.status != Status.STATUS_ACTIVE) && + (this.status != Status.STATUS_MARKED_ROLLBACK)) { + + throw new JDOUserException(msg.msg( + "EXC_TransactionNotActive")); // NOI18N + } + + // This flag prevents user from making any changes to the transaction object. + this.startedCommit = true; + } + + try { + this.internalRollback(); + + if (txType == BMT_JDO) { + // Send request to the container: + EJBImplHelper.getUserTransaction().rollback(); + } + } catch (JDOException e) { + throw e; + + } catch (Exception e) { + throw new JDOException("", e); // NOI18N + + } finally { + if (txType == NON_MGD) { + // afterCompletion and cleanup in case of the managed env. had been + // done already. + this.internalAfterCompletion(); + } + } + } + + // + // ----- Other public methods ------ + // + + /** + * Modify the transaction object such that the only possible outcome of + * the transaction is to roll back. + */ + public void setRollbackOnly() { + if (debugging()) + this.traceCall("setRollbackOnly"); // NOI18N + + if ((this.status == Status.STATUS_ROLLING_BACK) + || (this.status == Status.STATUS_ROLLEDBACK) + || (this.status == Status.STATUS_MARKED_ROLLBACK)) { + // + // Already rolled back, rollback in progress or already marked. + // + return; + } + + if (txType == NON_MGD) { + this.setStatus(Status.STATUS_MARKED_ROLLBACK); + } else { + try { + jta.setRollbackOnly(); + } catch (Exception e) { + throw new JDOException("", e); // NOI18N + } + } + + } + + /** + * Obtain the status of this transaction object. + * + * @return The transaction status. + */ + public int getStatus() { + synchronized (this) { + return this.status; + } + } + + /** + * Translates a javax.transaction.Status value into a string. + * + * @param status Status object to translate. + * @return Printable String for a Status object. + */ + public static String statusString(int status) { + switch (status) { + case Status.STATUS_ACTIVE: return "STATUS_ACTIVE"; // NOI18N + case Status.STATUS_MARKED_ROLLBACK: return "STATUS_MARKED_ROLLBACK"; // NOI18N + case Status.STATUS_PREPARED: return "STATUS_PREPARED"; // NOI18N + case Status.STATUS_COMMITTED: return "STATUS_COMMITTED"; // NOI18N + case Status.STATUS_ROLLEDBACK: return "STATUS_ROLLEDBACK"; // NOI18N + case Status.STATUS_UNKNOWN: return "STATUS_UNKNOWN"; // NOI18N + case Status.STATUS_NO_TRANSACTION: return "STATUS_NO_TRANSACTION"; // NOI18N + case Status.STATUS_PREPARING: return "STATUS_PREPARING"; // NOI18N + case Status.STATUS_COMMITTING: return "STATUS_COMMITTING"; // NOI18N + case Status.STATUS_ROLLING_BACK: return "STATUS_ROLLING_BACK"; // NOI18N + default: break; + } + return "STATUS_Invalid[" + status + "]"; // NOI18N + } + + /** + * Returns a string representation of this transaction object. + * + * @return String describing contents of this Transaction object. + */ + public String toString() { + StringBuffer s = new StringBuffer(); + + s.append(" Transaction: \n status = " + this.statusString(this.status)+ "\n"); // NOI18N + if (this.startedCommit) + s.append(" startedCommit = true\n"); // NOI18N + + if (synchronization != null) + s.append(" sync = " + synchronization.getClass().getName() + "\n"); // NOI18N + + return s.toString(); + } + + // + // ----- protected methods ------ + // + + /** + * Returns current transaction type + * @return current transaction type as int. + */ + protected int getTransactionType() { + return txType; + } + + /** Verify that username and password are equal to ones stored before + * + * @param username as String + * @param password as String + * @return true if they are equal + */ + protected boolean verify(String username, String password) { + if ((this.username != null && !this.username.equals(username)) || + (this.username == null && username != null) || + (this.password != null && !this.password.equals(password)) || + (this.password == null && password != null)) { + return false; + } + return true; + } + + /** Returns true if commit has started + * @return true if commit has started + */ + protected boolean startedCommit() { + return startedCommit; + } + + /** + * Flush changes to the datastore. Performed in an active datastore + * transaction only. + */ + protected void internalFlush() { + if (this.status != Status.STATUS_ACTIVE) { + throw new JDOUserException(msg.msg( + "EXC_TransactionNotActive")); // NOI18N + } + + this.prepareFlush(false); // prepare the flush. + } + + /** + * Begin a transaction in a managed environment. Called by + * PersistenceManagerFactoryImpl when JTA Transaction associated with + * the current thread is active. + * + * @param t JTA Transaction associated with the current thread + */ + protected void begin(javax.transaction.Transaction t) { + + beginInternal(); + try { + jta = t; + if (txSync == null) + txSync = new TransactionSynchronization(this); + + jta.registerSynchronization((Synchronization)txSync); + } catch (Exception e) { + throw new JDOFatalInternalException(msg.msg( + "EXC_ErrorRegister")); //NOI18N + } + + // Set transaction type. + txType = CMT; + } + + /** + * Called in the managed environment only for transaction completion + * by TransactionSynchronization#beforeCompletion(). + */ + protected void beforeCompletion() { + + if (txType == NON_MGD) { + // Error - should not be called + throw new JDOUserException(msg.msg( + "EXC_WrongNonMgdOperation", "beforeCompletion")); //NOI18N + } + + Object o = null; + + // This flag prevents user from making any changes to the transaction object. + this.startedCommit = true; + + try { + o = EJBImplHelper.enlistBeforeCompletion( + new Object[] {this, persistenceManager, jta}); + this.prepareFlush(true); // do actual beforeComplition. + this.commitPrepare(); // check internal status. + + // do not do commitConnector() in the managed environment: + this.setStatus(Status.STATUS_COMMITTED); + + } finally { + EJBImplHelper.delistBeforeCompletion(o); + } + } + + /** + * Called in the managed environment only for transaction completion + * by TransactionSynchronization#afterCompletion(int st). + */ + protected void afterCompletion(int st) { + if (txType == NON_MGD) { + // Error - should not be called + throw new JDOUserException(msg.msg( + "EXC_WrongNonMgdOperation", "afterCompletion")); //NOI18N + } + st = EJBImplHelper.translateStatus(st); // translate Status + + if (debugging()) { + this.traceCall("afterCompletion", st); // NOI18N + } + + if (st == Status.STATUS_ROLLEDBACK) { + this.internalRollback(); + } + + if (st != this.status) { + // Status mismatch - should not happen. + throw new JDOUserException(msg.msg( + "EXC_InvalidStatus", // NOI18N + "afterCompletion", this.statusString(this.status), // NOI18N + this.statusString(st))); + } + + this.internalAfterCompletion(); + + } + + // + // ----- private methods ------ + // + + /** + * Status change and validation. Called by begin methods. + */ + private void beginInternal() { + persistenceManager.assertIsOpen(); + + if (debugging()) + this.traceCall("begin"); // NOI18N + + if (this.isActive()) { + throw new JDOUserException(msg.msg( + "EXC_ErrorBegin")); // NOI18N + + } + this.setStatus(Status.STATUS_ACTIVE); + + connector = this.getConnector(); + connector.begin(optimistic); + } + + /** + * Lower-level before-commit method - phase 1. + * + * This is called to flush changes to the store. + * State transition: + * STATUS_ACTIVE starting state + * internalBeforeCompletion() called while still active + * STATUS_PREPARING no longer active, about to "really" commit + * + * @param _commit true if called during the commit processing + * For exceptions see commit() method. + */ + private void prepareFlush(boolean _commit) { + boolean rollbackOnly = false; //marked for rollback + + if (debugging()) + this.traceCall("prepareFlush"); // NOI18N + // + // Prepare connection + // + connector = this.getConnector(); + + // + // Validate transaction state before we commit + // + + if ((this.status == Status.STATUS_ROLLING_BACK) + || (this.status == Status.STATUS_ROLLEDBACK)) { + throw new JDOUserException(msg.msg( + "EXC_TransactionRolledback")); // NOI18N + } + + if (connector.getRollbackOnly() || + this.status == Status.STATUS_MARKED_ROLLBACK) { + rollbackOnly = true; + + } else if (this.status != Status.STATUS_ACTIVE) { + throw new JDOUserException(msg.msg( + "EXC_TransactionNotActive")); // NOI18N + } + + // + // User notifications done outside of lock - check for concurrent + // rollback or setRollbackOnly during notification. + // + if (!rollbackOnly) { + this.flushInstances(_commit); + + if (this.status == Status.STATUS_ACTIVE) { // All ok + if (this.startedCommit) { // inside commit - change status. + this.setStatus(Status.STATUS_PREPARING); + } + + } else if (this.status == Status.STATUS_MARKED_ROLLBACK) { + // This could happen only if this.setRollbackOnly() was called + // during flushInstances() without throwing an + // exception. + rollbackOnly = true; + + } else { // concurrently rolled back - should not happen. + throw new JDOUserException(msg.msg( + "EXC_TransactionRolledback")); // NOI18N + } + } + if (rollbackOnly) { + // Do not rollback here, but throw the exception and the rollback + // will happen in the 'catch' block. Usually happens if the + // connector was set rollback-only before the commit. + this.setRollbackOnly(); + + throw new JDOUserException(msg.msg( + "EXC_MarkedRolledback")); // NOI18N + + } + } + + /** + * Lower-level prepare-commit method - phase 2. + * + * This is called when flush is finished but before connectorCommit. + * Will allow to support 2-phase commit. + * State transition: + * STATUS_PREPARING starting state + * STATUS_PREPARED + * + * For exceptions see commit() method. + */ + private void commitPrepare() { + if (debugging()) + this.traceCall("commitPrepare"); // NOI18N + // + // Once we've reached the Status.STATUS_PREPARING state we do not need + // to check for concurrent state changes. All user-level methods + // (rollback, setRollbackOnly, register, enlist, etc) are no longer + // allowed. + // + + // + // Validate initial state + // + if (this.status != Status.STATUS_PREPARING) { + throw new JDOUserException(msg.msg( + "EXC_WrongStateCommit")); // NOI18N + } + + this.setStatus(Status.STATUS_PREPARED); + } + + /** + * Lower-level commit method - phase 3. Called only in a non- + * managed environment. + * + * State transition: + * STATUS_PREPARED starting state + * STATUS_COMMITTING starting to do final phase + * commitConnector() commit the flush. + * STATUS_COMMITTED + * + */ + private void commitComplete() { + if (debugging()) + this.traceCall("commitComplete"); // NOI18N + + // + // Validate initial state + // + if (this.status == Status.STATUS_ROLLING_BACK) { + this.setStatus(Status.STATUS_ROLLING_BACK); + + this.setStatus(Status.STATUS_ROLLEDBACK); + + } else if (this.status == Status.STATUS_PREPARED) { + this.setStatus(Status.STATUS_COMMITTING); + this.commitConnector(); + this.setStatus(Status.STATUS_COMMITTED); + + } else { + throw new JDOUserException(msg.msg( + "EXC_WrongStateCommit")); // NOI18N + } + } + + /** + * Lower-level internal rollback method. This is to avoid concurrent rollbacks. + * + */ + private void internalRollback() { + if (debugging()) + this.traceCall("internalRollback"); // NOI18N + + this.setStatus(Status.STATUS_ROLLING_BACK); + try { + if (txType == NON_MGD) { + this.rollbackConnector(); + } + } catch (JDOException ex) { + throw ex; + + } catch (Exception ex) { + throw new JDOException("", ex); + + } finally { + this.setStatus(Status.STATUS_ROLLEDBACK); + } + } + + /** + * + * Force rollback. This is called when something goes wrong during + * a late state check (i.e. some failure occurred during the prepare + * stage). Unless we're not already rolling back (or rolled back) this + * will blindly change the state of the transaction and complete the + * latter stage of rollback. + * + * @return the final status of the transaction. + * + * See internalRollback() for exceptions + */ + private int forceRollback() { + if (debugging()) + this.traceCall("forceRollback"); // NOI18N + + if ((this.status == Status.STATUS_ROLLING_BACK) // Already + || (this.status == Status.STATUS_ROLLEDBACK) // Done + || (this.status == Status.STATUS_COMMITTED) // Too late + || (this.status == Status.STATUS_NO_TRANSACTION) // Never was + ) { + return this.status; + } + try { + this.internalRollback(); + } finally { + this.internalAfterCompletion(); + } + + return this.status; + } + + /** + * Register a Synchronization object for this transaction object. + * The transction manager invokes the beforeCompletion method prior to + * starting the transaction commit process. After the transaction is + * completed (or aborted), the transaction manager invokes the + * afterCompletion method. + * + * @param sync The Synchronization object for the transaction. + */ + private void registerSynchronization(Synchronization sync) { + if (debugging()) + this.traceCall("registerSynchronization"); // NOI18N + synchronized (this) { + // + // Disallow registration of new synchronization objects during + // beforeCompletion or afterCompletion processing. Synchronizations + // are themselves involved in the process. + // + if (this.startedCommit) { + throw new JDOUserException(msg.msg( + "EXC_TransactionCommitting")); // NOI18N + } + + synchronization = sync; + + if (debugging()) { + this.traceCall("registerSynchronization"); // NOI18N + } + } + } + + + /** + * Confirm that transaction is terminated. + * + * @return True if transaction is completed or not started. + */ + private boolean isTerminated() { + synchronized (this) { + return ( (this.status == Status.STATUS_COMMITTED) + || (this.status == Status.STATUS_ROLLEDBACK) + || (this.status == Status.STATUS_NO_TRANSACTION)); + } + } + + /** + * Flush dirty persistent instances to the datastore. + * If called during the commit processing, notifies registered + * Synchronization interfaces with beforeCompletion(). + */ + private void flushInstances(boolean commit) { + if (commit) { + this.getConnector().beforeCompletion(); + if (synchronization != null) { + ((Synchronization)synchronization).beforeCompletion(); + } + } + + persistenceManager.flushInstances(); + } + + /** + * Notify Connector, PersistenceManager, and registered Synchronization + * instances about afterCompletion(). + * All status changes occured before executing this method. + */ + private void internalAfterCompletion() { + // + // This will execute w/o an active transaction context + // + persistenceManager.afterCompletion(status); + + try { + if (synchronization != null) + ((Synchronization)synchronization).afterCompletion(status); + } catch (Exception ex) { + // + // Exceptions ignored + // + } + + this.finish(); + } + + /** + * Set status under lock (may be a nested lock which is ok) + */ + private void setStatus(int status) { + if (debugging()) { + logger.debug( + "Tran[" + this.toString() + "].setStatus: " + // NOI18N + this.statusString(this.status) + " => " + // NOI18N + this.statusString(status)); + } + + synchronized(this) { + this.status = status; + persistenceManager.notifyStatusChange(!isTerminated()); + } + } + + /** + * Finish this transaction + */ + private void finish() { + if (debugging()) + this.traceCall("finish"); // NOI18N + + // + // Do not clear: + // + // .status -- users can still check status + // + this.startedCommit = false; + + if (txType == CMT || txType == BMT_UT) { + persistenceManager.forceClose(); + } else if (txType == BMT_JDO) { + persistenceManager.deregisterJTA(); + } + + jta = null; + txType = NON_MGD; // Restore the flag + } + + // + // ----- Connector utilities ----- + // + + /** + * Get a connector + */ + private Connector getConnector() { + StoreManager srm = persistenceManager.getStoreManager(); + + if (username != null) { + return srm.getConnector(username, password); + } + return srm.getConnector(); + } + + /** + * Close a connector does flush of the changes and close + */ + private void flushConnector() { + connector = this.getConnector(); + connector.flush(); + } + + /** + * Rollback a connector does rollback and close + */ + private void rollbackConnector() { + connector = this.getConnector(); + connector.rollback(); + } + + /** + * Commit a connector does flush if necessary, commit and close + */ + private void commitConnector() { + connector = this.getConnector(); + connector.commit(); + } + + // + // ----- Debugging utilities ----- + // + + /** + * Verifies if debugging is enabled. + * @return true if debugging is enabled. + */ + private boolean debugging() { + return logger.isDebugEnabled(); + } + + + /** + * Trace method call. + */ + private void traceCall(String call) { + logger.debug( + "Tran[" + this.toString() + "]." + call + // NOI18N + ": status = " + this.statusString(this.status) + // NOI18N + ", txType: " + txTypeString()); // NOI18N + } + + /** + * Trace method call with a provided status. + */ + private void traceCall(String call, int st) { + logger.debug( + "Tran[" + this.toString() + "]." + call + // NOI18N + ": status = " + this.statusString(st) + // NOI18N + ", txType: " + txTypeString()); // NOI18N + } + + /** + * Translates a txType value into a string. + * + * @return Printable String for a txType value + */ + private String txTypeString() { + switch (txType) { + case NON_MGD: return "NON_MGD"; // NOI18N + case CMT: return "CMT"; // NOI18N + case BMT_UT: return "BMT_UT"; // NOI18N + case BMT_JDO: return "BMT_JDO"; // NOI18N + default: break; + } + return "UNKNOWN"; // NOI18N + } +} + + + Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/TransactionSynchronization.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/TransactionSynchronization.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/TransactionSynchronization.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/TransactionSynchronization.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,60 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * TransactionSynchronization.java + * + * Create on August 1, 20001 + */ + +package org.apache.jdo.impl.pm; + +import javax.transaction.*; + + +/** + * This is a Synchronization instance associated with the corresponding instance + * of the TransactionImpl. Is used for synchronization callbacks in a managed + * environment. This is a separate object to avoid a requirement for a non-managed + * application have JTA classes in its classpath. + * + * @author Marina Vatkina + */ +class TransactionSynchronization implements Synchronization { + /** Reference to TransactionImpl instance associated + * with this instance of TransactionSynchronization + */ + private TransactionImpl tx = null; + + TransactionSynchronization(TransactionImpl newtx) { + tx = newtx; + } + + /** + * @see javax.transaction.Synchronization#beforeCompletion() + */ + public void beforeCompletion() { + tx.beforeCompletion(); + } + + /** + * @see javax.transaction.Synchronization#afterCompletion(int status) + */ + public void afterCompletion(int status) { + tx.afterCompletion(status); + } + +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/package.html URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/package.html?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/package.html (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/pm/package.html Fri Mar 18 17:02:29 2005 @@ -0,0 +1,28 @@ +<!-- + Copyright 2005 The Apache Software Foundation. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<html> +<head> +<title>Package org.apache.jdo.impl.pm</title> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/> +</head> + +<body bgcolor="#FFFFFF"> +<p>This package contains classes that are for use across all kinds of implementations + of the JDO Reference Implementation. The classes herein by and large implement + the interfaces defined in <a href="../package-summary.html">org.apache.jdo.pm</a>. +</body> +</html> Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/ArrayList.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/ArrayList.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/ArrayList.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/ArrayList.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,605 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * sco.ArrayList.java + */ + +package org.apache.jdo.impl.sco; + +import java.util.Collection; +import java.util.Iterator; + +import javax.jdo.JDOUserException; +import javax.jdo.JDOFatalInternalException; + +import org.apache.jdo.sco.SCO; +import org.apache.jdo.sco.SCOCollection; +import org.apache.jdo.state.StateManagerInternal; +import org.apache.jdo.util.I18NHelper; + + +/** + * A mutable 2nd class object that represents ArrayList. + * @author Marina Vatkina + * @version 1.0.1 + * @see java.util.ArrayList + */ +public class ArrayList extends java.util.ArrayList + implements SCOCollection { + + private transient StateManagerInternal owner; + + private transient int fieldNumber = -1; + + private transient Class elementType; + + private transient boolean allowNulls; + + private transient java.util.Vector added = new java.util.Vector(); + + private transient java.util.Vector removed = new java.util.Vector(); + + /** + * I18N message handler + */ + private final static I18NHelper msg = I18NHelper.getInstance( + "org.apache.jdo.impl.sco.Bundle"); // NOI18N + + private final static String _ArrayList = "ArrayList"; // NOI18N + + /** + * Constructs an empty <code>ArrayList</code> object. + * + * @param elementType the element types allowed + * @param allowNulls true if nulls are allowed + */ + public ArrayList(Class elementType, boolean allowNulls) { + super(); + + this.elementType = elementType; + this.allowNulls = allowNulls; + } + + /** + * Constructs an empty <code>ArrayList</code> object that the specified + * initial capacity. + * + * @param elementType the element types allowed + * @param allowNulls true if nulls are allowed + * @param initialCapacity the initial capacity of the list. + * @exception IllegalArgumentException if the specified initial capacity + * is negative + */ + public ArrayList(Class elementType, boolean allowNulls, + int initialCapacity) { + super(initialCapacity); + this.elementType = elementType; + this.allowNulls = allowNulls; + } + + /** ------------------Public Methods----------------*/ + + /** + * Replaces the element at the specified position in this ArrayList with the + * specified element. + * + * @param index index of element to replace. + * @param element element to be stored at the specified position. + * @return the element previously at the specified position. + * @exception IndexOutOfBoundsException index out of range + * (index < 0 || index >= size()). + * @exception IllegalArgumentException fromIndex > toIndex. + * @see java.util.ArrayList + */ + public Object set(int index, Object element) { + SCOHelper.debug(_ArrayList, "set"); // NOI18N + + if (element == null) { + SCOHelper.assertNullsAllowed(element, allowNulls); + // It is actualy remove + return this.remove(index); + } + SCOHelper.assertElementType(element, elementType); + // Mark the field as dirty + this.makeDirty(); + + Object o = super.set(index, element); + if (added.remove(o) == false) { + removed.add(o); + } + if (removed.remove(element) == false) { + added.add(element); + } + // Apply updates + this.trackUpdates(true); + + return o; + } + + + /** + * Appends the specified element to the end of this ArrayList. + * + * @param o element to be appended to this ArrayList. + * @return true (as per the general contract of Collection.add). + * @see java.util.ArrayList + */ + public boolean add(Object o) { + SCOHelper.debug(_ArrayList, "add"); // NOI18N + + SCOHelper.assertNullsAllowed(o, allowNulls); + SCOHelper.assertElementType(o, elementType); + + // Mark the field as dirty + this.makeDirty(); + + if (removed.remove(o) == false) { + added.add(o); + } + + boolean modified = super.add(o); + + // Apply updates + this.trackUpdates(modified); + + return modified; + } + + /** + * Removes the first occurrence of the specified element in this ArrayList + * If the ArrayList does not contain the element, it is unchanged. + * + * @param o element to be removed from this ArrayList, if present. + * @return true if the ArrayList contained the specified element. + * @see java.util.ArrayList + */ + public boolean remove(Object o) { + SCOHelper.debug(_ArrayList, "remove"); // NOI18N + + // Because java.util.AbstractCollection.remove(Object) + // delegates remove() to remove(int) which is not supported, + // we cannot rely on jdk. We need to process remove here. + + // Mark the field as dirty + this.makeDirty(); + + int i = super.indexOf(o); + Object obj = null; + if (i > -1) { + obj = super.remove(i); + if (added.remove(obj) == false) { + removed.add(obj); + } + // Apply updates + this.trackUpdates(true); + return true; + } + return false; + } + + /** + * Inserts the specified element at the specified position in this ArrayList. + * + * @param index index at which the specified element is to be inserted. + * @param element element to be inserted. + * @exception IndexOutOfBoundsException index is out of range + * (index < 0 || index > size()). + * @see java.util.ArrayList + */ + public void add(int index, Object element) { + SCOHelper.debug(_ArrayList, "add by index"); // NOI18N + + SCOHelper.assertNullsAllowed(element, allowNulls); + SCOHelper.assertElementType(element, elementType); + + // Mark the field as dirty + this.makeDirty(); + + super.add(index, element); + if (removed.remove(element) == false) { + added.add(element); + } + // Apply updates + this.trackUpdates(true); + + } + + /** + * Removes the element at the specified position in this ArrayList. + * shifts any subsequent elements to the left (subtracts one from their + * indices). Returns the element that was removed from the ArrayList. + * + * @param index the index of the element to removed. + * @exception IndexOutOfBoundsException index out of range (index + * < 0 || index >= size()). + * @see java.util.ArrayList + */ + public Object remove(int index) { + SCOHelper.debug(_ArrayList, "remove by index"); // NOI18N + + // Mark the field as dirty + this.makeDirty(); + + Object obj = super.remove(index); + if (added.remove(obj) == false) { + removed.add(obj); + } + // Apply updates + this.trackUpdates(true); + + return obj; + } + + /** + * Removes all of the elements from this ArrayList. The ArrayList will + * be empty after this call returns (unless it throws an exception). + * + * @see java.util.ArrayList + */ + public void clear() { + SCOHelper.debug(_ArrayList, "clear"); // NOI18N + + // Mark the field as dirty + this.makeDirty(); + + for (Iterator iter = super.iterator(); iter.hasNext();) { + Object o = iter.next(); + if (added.remove(o) == false) { + removed.add(o); + } + } + added.clear(); + super.clear(); + + // Apply updates + this.trackUpdates(true); + } + + /** + * Appends all of the elements in the specified Collection to the end of + * this ArrayList, in the order that they are returned by the specified + * Collection's Iterator. + * + * @param c elements to be inserted into this ArrayList. + * @exception IndexOutOfBoundsException index out of range (index + * < 0 || index > size()). + * @see java.util.ArrayList + */ + public boolean addAll(Collection c) { + SCOHelper.debug(_ArrayList, "addAll"); // NOI18N + + // iterate the collection and make a list of wrong elements. + Throwable[] err = new Throwable[c.size()]; + int l = 0; + + Iterator i = c.iterator(); + while (i.hasNext()) { + Object o = i.next(); + try { + SCOHelper.assertNullsAllowed(o, allowNulls); + SCOHelper.assertElementType(o, elementType); + } catch (Throwable e) { + err[l++] = e; + } + } + SCOHelper.validateResult(l, err); + + // Mark the field as dirty + this.makeDirty(); + + removed.removeAll(c); + added.addAll(c); + + boolean modified = super.addAll(c); + + // Apply updates + this.trackUpdates(modified); + + return modified; + } + + /** + * Removes from this ArrayList all of its elements that are contained in the + * specified Collection. + * + * @return true if this ArrayList changed as a result of the call. + * @see java.util.ArrayList + */ + public boolean removeAll(Collection c) { + SCOHelper.debug(_ArrayList, "removeAll"); // NOI18N + + boolean modified = false; + // Mark the field as dirty + this.makeDirty(); + + Iterator e = c.iterator(); + while (e.hasNext()) { + Object o = e.next(); + if(super.contains(o)) { + removeInternal(o); + if (added.remove(o) == false) { + removed.add(o); + } + modified = true; + } + } + + // Apply updates + this.trackUpdates(modified); + + return modified; + } + + /** + * Inserts all of the elements in in the specified Collection into this + * ArrayList at the specified position. Shifts the element currently at + * that position (if any) and any subsequent elements to the right + * (increases their indices). The new elements will appear in the ArrayList + * in the order that they are returned by the specified Collection's + * iterator. + * + * @param index index at which to insert first element + * from the specified collection. + * @param c elements to be inserted into this ArrayList. + * @exception IndexOutOfBoundsException index out of range (index + * < 0 || index > size()). + * @see java.util.ArrayList + */ + public boolean addAll(int index, Collection c) { + SCOHelper.debug(_ArrayList, "addAll from index"); // NOI18N + + // iterate the collection and make a list of wrong elements. + Throwable[] err = new Throwable[c.size()]; + int l = 0; + + Iterator i = c.iterator(); + while (i.hasNext()) { + Object o = i.next(); + try { + SCOHelper.assertNullsAllowed(o, allowNulls); + SCOHelper.assertElementType(o, elementType); + } catch (Throwable e) { + err[l++] = e; + } + } + SCOHelper.validateResult(l, err); + + // Mark the field as dirty + this.makeDirty(); + + removed.removeAll(c); + added.addAll(c); + + boolean modified = super.addAll(index, c); + + // Apply updates + this.trackUpdates(modified); + + return modified; + } + + /** + * Retains only the elements in this ArrayList that are contained in the + * specified Collection. + * + * @return true if this ArrayList changed as a result of the call. + * @see java.util.ArrayList + */ + public boolean retainAll(Collection c) { + SCOHelper.debug(_ArrayList, "retainAll"); // NOI18N + + boolean modified = false; + java.util.ArrayList v = new java.util.ArrayList(); + + // Mark the field as dirty + this.makeDirty(); + + for (Iterator iter = super.iterator(); iter.hasNext();) { + Object o = iter.next(); + if (!c.contains(o)) { + v.add(o); + if (added.remove(o) == false) { + removed.add(o); + } + modified = true; + } + } + + // Now remove the rest (stored in "v") + for (Iterator iter = v.iterator(); iter.hasNext();) { + removeInternal(iter.next()); + } + + // Apply updates + this.trackUpdates(modified); + + return modified; + } + + /** + * Creates and returns a copy of this object. + * + * <P>Mutable Second Class Objects are required to provide a public + * clone method in order to allow for copying PersistenceCapable + * objects. In contrast to Object.clone(), this method must not throw a + * CloneNotSupportedException. + */ + public Object clone() { + SCOHelper.debug(_ArrayList, "clone"); // NOI18N + + Object obj = super.clone(); + if (obj instanceof SCO) + ((SCO)obj).unsetOwner(owner, fieldNumber); + + return obj; + } + + /** + * @see SCOCollection#reset() + */ + public void reset() { + added.clear(); + removed.clear(); + } + + /** + * @see SCOCollection#addInternal(Object o) + */ + public void addInternal(Object o) { + super.add(o); + } + + + /** + * @see SCOCollection#addAllInternal(Collection c) + */ + public void addAllInternal(Collection c) { + super.addAll(c); + } + + /** + * @see SCOCollection#getAdded() + */ + public Collection getAdded() { + return (Collection)added; + } + + /** + * @see SCOCollection#getRemoved() + */ + public Collection getRemoved() { + return (Collection)removed; + } + + + /** + * @see SCOCollection#clearInternal() + */ + public void clearInternal() { + super.clear(); + this.reset(); + } + + /** + * @see SCOCollection#removeInternal(Object o) + */ + public void removeInternal(Object o) { + int i = super.indexOf(o); + super.remove(i); + } + + /** + * @see SCO#unsetOwner(Object owner, int fieldNumber) + */ + public void unsetOwner(Object owner, int fieldNumber) { + // Unset only if owner and fieldNumber match. + if (this.owner == owner && this.fieldNumber == fieldNumber) { + this.owner = null; + this.fieldNumber = -1; + } + } + + /** + * Marks object dirty + */ + private void makeDirty() { + if (owner != null) { + owner.makeDirty(fieldNumber); + } + } + + /** + * Apply changes + * @param modified true if content of this list has been changed. + */ + private void trackUpdates(boolean modified) { + if (modified && owner != null) { + owner.trackUpdates(fieldNumber, this); + } + } + + /** + * @see SCO#setOwner (Object owner, int fieldNumber) + */ + public void setOwner (Object owner, int fieldNumber) { + // Set only if it was not set before. + if (this.owner == null && owner instanceof StateManagerInternal) { + this.owner = (StateManagerInternal)owner; + this.fieldNumber = fieldNumber; + } + } + + /** + * @see SCO#getOwner () + */ + public Object getOwner() { + return SCOHelper.getOwner(owner); + } + + /** + * @see SCO#getFieldName() + */ + public String getFieldName() { + return SCOHelper.getFieldName(owner, fieldNumber); + } + + /** + * @see SCOCollection#getElementType() { + */ + public Class getElementType() { + return elementType; + } + + /** + * @see SCOCollection#allowNulls() { + */ + public boolean allowNulls() { + return allowNulls; + } + + /** Get an iterator over the frozen elements of this collection. + * This class does not require freezing, so this method returns + * a standard iterator. + * @since 1.0.1 + * @return an iterator over the elements. + */ + public Iterator frozenIterator() { + return iterator(); + } + + /** Set the contents of this Collection from the frozen elements. + * This class does not support explicit frozen operations, and this method + * always throws an exception. + * @since 1.0.1 + * @param elements not used. + */ + public void setFrozen(Object[] elements) { + throw new JDOFatalInternalException( + msg.msg("EXC_UnsupportedFreezerOperation")); //NOI18N + } + + /** Get an iterator regardless of whether the collection is frozen. + * This class does not support frozen operations and always returns + * a regular iterator. + * @since 1.0.1 + * @return an iterator over the elements. + */ + public Iterator eitherIterator() { + return iterator(); + } + +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Bundle.properties URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Bundle.properties?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Bundle.properties (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Bundle.properties Fri Mar 18 17:02:29 2005 @@ -0,0 +1,34 @@ +# +# Copyright 2005 The Apache Software Foundation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Exceptions for allowNulls validation: +EXC_ElementNullsNotAllowed=Nulls are not allowed as elements of this Collection. +EXC_KeyNullsNotAllowed=Nulls are not allowed as keys of this Map. +EXC_ValueNullsNotAllowed=Nulls are not allowed as values of this Map. + +# Exceptions for type validation: +EXC_ElementClassCastException=New element cannot be cast to {0}. +EXC_KeyClassCastException=New key cannot be cast to {0}. +EXC_ValueClassCastException=New value cannot be cast to {0}. + +# Exception processing Collection or Map as an argument: +EXC_FailedToProcessAll=Failed to process all parameters. + +# Exceptions for freezing Set and Map +EXC_OidNotComparable=Object id classes must be comparable. Class {0} does not implement Comparable. +EXC_ConcurrentModification=This collection was thawed during iteration of the frozen contents. +EXC_RemoveNotSupported=Optional method remove() is not supported for frozen Iterator. +EXC_UnsupportedFreezerOperation=This class does not support operations for freezing and thawing. +