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.1 2007-08-24 22:17:37 ewestfal Exp $
041 */
042 public class DatabaseImpl implements org.odmg.Database
043 {
044 private Logger log = LoggerFactory.getLogger(DatabaseImpl.class);
045
046 private PBKey pbKey;
047 private boolean isOpen;
048 private ImplementationImpl odmg;
049
050 public DatabaseImpl(ImplementationImpl ojb)
051 {
052 isOpen = false;
053 this.odmg = ojb;
054 }
055
056 private TransactionImpl getTransaction()
057 {
058 Object result = odmg.currentTransaction();
059 // TODO: remove this workaround
060 // In managed environments only wrapped tx are returned, so
061 // we have to extract the real tx first
062 if(result instanceof NarrowTransaction)
063 {
064 return ((NarrowTransaction) result).getRealTransaction();
065 }
066 return (TransactionImpl) result;
067 }
068
069 /**
070 * Return the {@link org.apache.ojb.broker.PBKey} associated with this Database.
071 */
072 public PBKey getPBKey()
073 {
074 if (pbKey == null)
075 {
076 log.error("## PBKey not set, Database isOpen=" + isOpen + " ##");
077 if (!isOpen) throw new DatabaseClosedException("Database is not open");
078 }
079 return pbKey;
080 }
081
082 public boolean isOpen()
083 {
084 return this.isOpen;
085 }
086
087 /**
088 * Open the named database with the specified access mode.
089 * Attempts to open a database when it has already been opened will result in
090 * the throwing of the exception <code>DatabaseOpenException</code>.
091 * A <code>DatabaseNotFoundException</code> is thrown if the database does not exist.
092 * Some implementations may throw additional exceptions that are also derived from
093 * <code>ODMGException</code>.
094 * @param name The name of the database.
095 * @param accessMode The access mode, which should be one of the static fields:
096 * <code>OPEN_READ_ONLY</code>, <code>OPEN_READ_WRITE</code>,
097 * or <code>OPEN_EXCLUSIVE</code>.
098 * @exception ODMGException The database could not be opened.
099 */
100 public synchronized void open(String name, int accessMode) throws ODMGException
101 {
102 if (isOpen())
103 {
104 throw new DatabaseOpenException("Database is already open");
105 }
106 PersistenceBroker broker = null;
107 try
108 {
109 if (name == null)
110 {
111 log.info("Given argument was 'null', open default database");
112 broker = PersistenceBrokerFactory.defaultPersistenceBroker();
113 }
114 else
115 {
116 broker = PersistenceBrokerFactory.createPersistenceBroker(
117 BrokerHelper.extractAllTokens(name));
118 }
119 pbKey = broker.getPBKey();
120 isOpen = true;
121 //register opened database
122 odmg.registerOpenDatabase(this);
123 if (log.isDebugEnabled()) log.debug("Open database using PBKey " + pbKey);
124 }
125 catch (PBFactoryException ex)
126 {
127 log.error("Open database failed: " + ex.getMessage(), ex);
128 throw new DatabaseNotFoundException(
129 "OJB can't open database " + name + "\n" + ex.getMessage());
130 }
131 finally
132 {
133 // broker must be immediately closed
134 if (broker != null)
135 {
136 broker.close();
137 }
138 }
139 }
140
141 /**
142 * Close the database.
143 * After you have closed a database, further attempts to access objects in the
144 * database will cause the exception <code>DatabaseClosedException</code> to be thrown.
145 * Some implementations may throw additional exceptions that are also derived
146 * from <code>ODMGException</code>.
147 * @exception ODMGException Unable to close the database.
148 */
149 public void close() throws ODMGException
150 {
151 /**
152 * is the DB open? ODMG 3.0 says we can't close an already open database.
153 */
154 if (!isOpen())
155 {
156 throw new DatabaseClosedException("Database is not Open. Must have an open DB to call close.");
157 }
158 /**
159 * is the associated Tx open? ODMG 3.0 says we can't close the database with an open Tx pending.
160 * check if a tx was found, the tx was associated with database
161 */
162 if (odmg.hasOpenTransaction() &&
163 getTransaction().getAssociatedDatabase().equals(this))
164 {
165 String msg = "Database cannot be closed, associated Tx is still open." +
166 " Transaction status is '" + TxUtil.getStatusString(getTransaction().getStatus()) + "'." +
167 " Used PBKey was "+getTransaction().getBroker().getPBKey();
168 log.error(msg);
169 throw new TransactionInProgressException(msg);
170 }
171 isOpen = false;
172 // remove the current PBKey
173 pbKey = null;
174 // if we close current database, we have to notify implementation instance
175 if (this == odmg.getCurrentDatabase())
176 {
177 odmg.setCurrentDatabase(null);
178 }
179 }
180
181 /**
182 * Associate a name with an object and make it persistent.
183 * An object instance may be bound to more than one name.
184 * Binding a previously transient object to a name makes that object persistent.
185 * @param object The object to be named.
186 * @param name The name to be given to the object.
187 * @exception org.odmg.ObjectNameNotUniqueException
188 * If an attempt is made to bind a name to an object and that name is already bound
189 * to an object.
190 */
191 public void bind(Object object, String name)
192 throws ObjectNameNotUniqueException
193 {
194 /**
195 * Is DB open? ODMG 3.0 says it has to be to call bind.
196 */
197 if (!this.isOpen())
198 {
199 throw new DatabaseClosedException("Database is not open. Must have an open DB to call bind.");
200 }
201 /**
202 * Is Tx open? ODMG 3.0 says it has to be to call bind.
203 */
204 TransactionImpl tx = getTransaction();
205 if (tx == null || !tx.isOpen())
206 {
207 throw new TransactionNotInProgressException("Tx is not open. Must have an open TX to call bind.");
208 }
209
210 tx.getNamedRootsMap().bind(object, name);
211 }
212
213 /**
214 * Lookup an object via its name.
215 * @param name The name of an object.
216 * @return The object with that name.
217 * @exception ObjectNameNotFoundException There is no object with the specified name.
218 * ObjectNameNotFoundException
219 */
220 public Object lookup(String name) throws ObjectNameNotFoundException
221 {
222 /**
223 * Is DB open? ODMG 3.0 says it has to be to call bind.
224 */
225 if (!this.isOpen())
226 {
227 throw new DatabaseClosedException("Database is not open. Must have an open DB to call lookup");
228 }
229 /**
230 * Is Tx open? ODMG 3.0 says it has to be to call bind.
231 */
232 TransactionImpl tx = getTransaction();
233 if (tx == null || !tx.isOpen())
234 {
235 throw new TransactionNotInProgressException("Tx is not open. Must have an open TX to call lookup.");
236 }
237
238 return tx.getNamedRootsMap().lookup(name);
239 }
240
241 /**
242 * Disassociate a name with an object
243 * @param name The name of an object.
244 * @exception ObjectNameNotFoundException No object exists in the database with that name.
245 */
246 public void unbind(String name) throws ObjectNameNotFoundException
247 {
248 /**
249 * Is DB open? ODMG 3.0 says it has to be to call unbind.
250 */
251 if (!this.isOpen())
252 {
253 throw new DatabaseClosedException("Database is not open. Must have an open DB to call unbind");
254 }
255 TransactionImpl tx = getTransaction();
256 if (tx == null || !tx.isOpen())
257 {
258 throw new TransactionNotInProgressException("Tx is not open. Must have an open TX to call lookup.");
259 }
260
261 tx.getNamedRootsMap().unbind(name);
262 }
263
264 /**
265 * Make a transient object durable in the database.
266 * It must be executed in the context of an open transaction.
267 * If the transaction in which this method is executed commits,
268 * then the object is made durable.
269 * If the transaction aborts,
270 * then the makePersistent operation is considered not to have been executed,
271 * and the target object is again transient.
272 * ClassNotPersistenceCapableException is thrown if the implementation cannot make
273 * the object persistent because of the type of the object.
274 * @param object The object to make persistent.
275 * @throws TransactionNotInProgressException if there is no current transaction.
276 */
277 public void makePersistent(Object object)
278 {
279 /**
280 * Is DB open? ODMG 3.0 says it has to be to call makePersistent.
281 */
282 if (!this.isOpen())
283 {
284 throw new DatabaseClosedException("Database is not open");
285 }
286 /**
287 * Is Tx open? ODMG 3.0 says it has to be to call makePersistent.
288 */
289 TransactionImpl tx = getTransaction();
290 if (tx == null || !tx.isOpen())
291 {
292 throw new TransactionNotInProgressException("No transaction in progress, cannot persist");
293 }
294 RuntimeObject rt = new RuntimeObject(object, getTransaction());
295 tx.makePersistent(rt);
296 // tx.moveToLastInOrderList(rt.getIdentity());
297 }
298
299 /**
300 * Deletes an object from the database.
301 * It must be executed in the context of an open transaction.
302 * If the object is not persistent, then ObjectNotPersistent is thrown.
303 * If the transaction in which this method is executed commits,
304 * then the object is removed from the database.
305 * If the transaction aborts,
306 * then the deletePersistent operation is considered not to have been executed,
307 * and the target object is again in the database.
308 * @param object The object to delete.
309 */
310 public void deletePersistent(Object object)
311 {
312 if (!this.isOpen())
313 {
314 throw new DatabaseClosedException("Database is not open");
315 }
316 TransactionImpl tx = getTransaction();
317 if (tx == null || !tx.isOpen())
318 {
319 throw new TransactionNotInProgressException("No transaction in progress, cannot delete persistent");
320 }
321 RuntimeObject rt = new RuntimeObject(object, tx);
322 tx.deletePersistent(rt);
323 // tx.moveToLastInOrderList(rt.getIdentity());
324 }
325 }