001: package org.apache.ojb.odmg;
002:
003: /* Copyright 2002-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import org.apache.ojb.broker.PBFactoryException;
019: import org.apache.ojb.broker.PBKey;
020: import org.apache.ojb.broker.PersistenceBroker;
021: import org.apache.ojb.broker.PersistenceBrokerFactory;
022: import org.apache.ojb.broker.util.BrokerHelper;
023: import org.apache.ojb.broker.util.logging.Logger;
024: import org.apache.ojb.broker.util.logging.LoggerFactory;
025: import org.odmg.DatabaseClosedException;
026: import org.odmg.DatabaseNotFoundException;
027: import org.odmg.DatabaseOpenException;
028: import org.odmg.ODMGException;
029: import org.odmg.ObjectNameNotFoundException;
030: import org.odmg.ObjectNameNotUniqueException;
031: import org.odmg.TransactionInProgressException;
032: import org.odmg.TransactionNotInProgressException;
033:
034: /**
035: * Implementation class of the {@link org.odmg.Database} interface.
036: *
037: * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
038: * @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird</a>
039: * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
040: * @version $Id: DatabaseImpl.java,v 1.26.2.9 2005/12/21 22:29:21 tomdz Exp $
041: */
042: public class DatabaseImpl implements org.odmg.Database {
043: private Logger log = LoggerFactory.getLogger(DatabaseImpl.class);
044:
045: private PBKey pbKey;
046: private boolean isOpen;
047: private ImplementationImpl odmg;
048:
049: public DatabaseImpl(ImplementationImpl ojb) {
050: isOpen = false;
051: this .odmg = ojb;
052: }
053:
054: private TransactionImpl getTransaction() {
055: Object result = odmg.currentTransaction();
056: // TODO: remove this workaround
057: // In managed environments only wrapped tx are returned, so
058: // we have to extract the real tx first
059: if (result instanceof NarrowTransaction) {
060: return ((NarrowTransaction) result).getRealTransaction();
061: }
062: return (TransactionImpl) result;
063: }
064:
065: /**
066: * Return the {@link org.apache.ojb.broker.PBKey} associated with this Database.
067: */
068: public PBKey getPBKey() {
069: if (pbKey == null) {
070: log.error("## PBKey not set, Database isOpen=" + isOpen
071: + " ##");
072: if (!isOpen)
073: throw new DatabaseClosedException(
074: "Database is not open");
075: }
076: return pbKey;
077: }
078:
079: public boolean isOpen() {
080: return this .isOpen;
081: }
082:
083: /**
084: * Open the named database with the specified access mode.
085: * Attempts to open a database when it has already been opened will result in
086: * the throwing of the exception <code>DatabaseOpenException</code>.
087: * A <code>DatabaseNotFoundException</code> is thrown if the database does not exist.
088: * Some implementations may throw additional exceptions that are also derived from
089: * <code>ODMGException</code>.
090: * @param name The name of the database.
091: * @param accessMode The access mode, which should be one of the static fields:
092: * <code>OPEN_READ_ONLY</code>, <code>OPEN_READ_WRITE</code>,
093: * or <code>OPEN_EXCLUSIVE</code>.
094: * @exception ODMGException The database could not be opened.
095: */
096: public synchronized void open(String name, int accessMode)
097: throws ODMGException {
098: if (isOpen()) {
099: throw new DatabaseOpenException("Database is already open");
100: }
101: PersistenceBroker broker = null;
102: try {
103: if (name == null) {
104: log
105: .info("Given argument was 'null', open default database");
106: broker = PersistenceBrokerFactory
107: .defaultPersistenceBroker();
108: } else {
109: broker = PersistenceBrokerFactory
110: .createPersistenceBroker(BrokerHelper
111: .extractAllTokens(name));
112: }
113: pbKey = broker.getPBKey();
114: isOpen = true;
115: //register opened database
116: odmg.registerOpenDatabase(this );
117: if (log.isDebugEnabled())
118: log.debug("Open database using PBKey " + pbKey);
119: } catch (PBFactoryException ex) {
120: log.error("Open database failed: " + ex.getMessage(), ex);
121: throw new DatabaseNotFoundException(
122: "OJB can't open database " + name + "\n"
123: + ex.getMessage());
124: } finally {
125: // broker must be immediately closed
126: if (broker != null) {
127: broker.close();
128: }
129: }
130: }
131:
132: /**
133: * Close the database.
134: * After you have closed a database, further attempts to access objects in the
135: * database will cause the exception <code>DatabaseClosedException</code> to be thrown.
136: * Some implementations may throw additional exceptions that are also derived
137: * from <code>ODMGException</code>.
138: * @exception ODMGException Unable to close the database.
139: */
140: public void close() throws ODMGException {
141: /**
142: * is the DB open? ODMG 3.0 says we can't close an already open database.
143: */
144: if (!isOpen()) {
145: throw new DatabaseClosedException(
146: "Database is not Open. Must have an open DB to call close.");
147: }
148: /**
149: * is the associated Tx open? ODMG 3.0 says we can't close the database with an open Tx pending.
150: * check if a tx was found, the tx was associated with database
151: */
152: if (odmg.hasOpenTransaction()
153: && getTransaction().getAssociatedDatabase()
154: .equals(this )) {
155: String msg = "Database cannot be closed, associated Tx is still open."
156: + " Transaction status is '"
157: + TxUtil.getStatusString(getTransaction()
158: .getStatus())
159: + "'."
160: + " Used PBKey was "
161: + getTransaction().getBroker().getPBKey();
162: log.error(msg);
163: throw new TransactionInProgressException(msg);
164: }
165: isOpen = false;
166: // remove the current PBKey
167: pbKey = null;
168: // if we close current database, we have to notify implementation instance
169: if (this == odmg.getCurrentDatabase()) {
170: odmg.setCurrentDatabase(null);
171: }
172: }
173:
174: /**
175: * Associate a name with an object and make it persistent.
176: * An object instance may be bound to more than one name.
177: * Binding a previously transient object to a name makes that object persistent.
178: * @param object The object to be named.
179: * @param name The name to be given to the object.
180: * @exception org.odmg.ObjectNameNotUniqueException
181: * If an attempt is made to bind a name to an object and that name is already bound
182: * to an object.
183: */
184: public void bind(Object object, String name)
185: throws ObjectNameNotUniqueException {
186: /**
187: * Is DB open? ODMG 3.0 says it has to be to call bind.
188: */
189: if (!this .isOpen()) {
190: throw new DatabaseClosedException(
191: "Database is not open. Must have an open DB to call bind.");
192: }
193: /**
194: * Is Tx open? ODMG 3.0 says it has to be to call bind.
195: */
196: TransactionImpl tx = getTransaction();
197: if (tx == null || !tx.isOpen()) {
198: throw new TransactionNotInProgressException(
199: "Tx is not open. Must have an open TX to call bind.");
200: }
201:
202: tx.getNamedRootsMap().bind(object, name);
203: }
204:
205: /**
206: * Lookup an object via its name.
207: * @param name The name of an object.
208: * @return The object with that name.
209: * @exception ObjectNameNotFoundException There is no object with the specified name.
210: * ObjectNameNotFoundException
211: */
212: public Object lookup(String name)
213: throws ObjectNameNotFoundException {
214: /**
215: * Is DB open? ODMG 3.0 says it has to be to call bind.
216: */
217: if (!this .isOpen()) {
218: throw new DatabaseClosedException(
219: "Database is not open. Must have an open DB to call lookup");
220: }
221: /**
222: * Is Tx open? ODMG 3.0 says it has to be to call bind.
223: */
224: TransactionImpl tx = getTransaction();
225: if (tx == null || !tx.isOpen()) {
226: throw new TransactionNotInProgressException(
227: "Tx is not open. Must have an open TX to call lookup.");
228: }
229:
230: return tx.getNamedRootsMap().lookup(name);
231: }
232:
233: /**
234: * Disassociate a name with an object
235: * @param name The name of an object.
236: * @exception ObjectNameNotFoundException No object exists in the database with that name.
237: */
238: public void unbind(String name) throws ObjectNameNotFoundException {
239: /**
240: * Is DB open? ODMG 3.0 says it has to be to call unbind.
241: */
242: if (!this .isOpen()) {
243: throw new DatabaseClosedException(
244: "Database is not open. Must have an open DB to call unbind");
245: }
246: TransactionImpl tx = getTransaction();
247: if (tx == null || !tx.isOpen()) {
248: throw new TransactionNotInProgressException(
249: "Tx is not open. Must have an open TX to call lookup.");
250: }
251:
252: tx.getNamedRootsMap().unbind(name);
253: }
254:
255: /**
256: * Make a transient object durable in the database.
257: * It must be executed in the context of an open transaction.
258: * If the transaction in which this method is executed commits,
259: * then the object is made durable.
260: * If the transaction aborts,
261: * then the makePersistent operation is considered not to have been executed,
262: * and the target object is again transient.
263: * ClassNotPersistenceCapableException is thrown if the implementation cannot make
264: * the object persistent because of the type of the object.
265: * @param object The object to make persistent.
266: * @throws TransactionNotInProgressException if there is no current transaction.
267: */
268: public void makePersistent(Object object) {
269: /**
270: * Is DB open? ODMG 3.0 says it has to be to call makePersistent.
271: */
272: if (!this .isOpen()) {
273: throw new DatabaseClosedException("Database is not open");
274: }
275: /**
276: * Is Tx open? ODMG 3.0 says it has to be to call makePersistent.
277: */
278: TransactionImpl tx = getTransaction();
279: if (tx == null || !tx.isOpen()) {
280: throw new TransactionNotInProgressException(
281: "No transaction in progress, cannot persist");
282: }
283: RuntimeObject rt = new RuntimeObject(object, getTransaction());
284: tx.makePersistent(rt);
285: // tx.moveToLastInOrderList(rt.getIdentity());
286: }
287:
288: /**
289: * Deletes an object from the database.
290: * It must be executed in the context of an open transaction.
291: * If the object is not persistent, then ObjectNotPersistent is thrown.
292: * If the transaction in which this method is executed commits,
293: * then the object is removed from the database.
294: * If the transaction aborts,
295: * then the deletePersistent operation is considered not to have been executed,
296: * and the target object is again in the database.
297: * @param object The object to delete.
298: */
299: public void deletePersistent(Object object) {
300: if (!this .isOpen()) {
301: throw new DatabaseClosedException("Database is not open");
302: }
303: TransactionImpl tx = getTransaction();
304: if (tx == null || !tx.isOpen()) {
305: throw new TransactionNotInProgressException(
306: "No transaction in progress, cannot delete persistent");
307: }
308: RuntimeObject rt = new RuntimeObject(object, tx);
309: tx.deletePersistent(rt);
310: // tx.moveToLastInOrderList(rt.getIdentity());
311: }
312: }
|