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.commons.lang.SerializationUtils;
019 import org.apache.commons.lang.builder.ToStringBuilder;
020 import org.apache.commons.lang.builder.ToStringStyle;
021 import org.apache.ojb.broker.Identity;
022 import org.apache.ojb.broker.PBKey;
023 import org.apache.ojb.broker.PersistenceBroker;
024 import org.apache.ojb.broker.PersistenceBrokerFactory;
025 import org.apache.ojb.broker.util.collections.ManageableArrayList;
026 import org.apache.ojb.broker.util.configuration.Configuration;
027 import org.apache.ojb.broker.util.configuration.ConfigurationException;
028 import org.apache.ojb.broker.util.configuration.Configurator;
029 import org.apache.ojb.broker.util.factory.ConfigurableFactory;
030 import org.apache.ojb.broker.util.logging.Logger;
031 import org.apache.ojb.broker.util.logging.LoggerFactory;
032 import org.apache.ojb.odmg.locking.LockManager;
033 import org.apache.ojb.odmg.locking.LockManagerFactory;
034 import org.apache.ojb.odmg.oql.EnhancedOQLQuery;
035 import org.apache.ojb.odmg.oql.OQLQueryImpl;
036 import org.odmg.DArray;
037 import org.odmg.DBag;
038 import org.odmg.DList;
039 import org.odmg.DMap;
040 import org.odmg.DSet;
041 import org.odmg.Database;
042 import org.odmg.DatabaseClosedException;
043 import org.odmg.Implementation;
044 import org.odmg.ODMGRuntimeException;
045 import org.odmg.Transaction;
046
047
048 /**
049 * Default implementation of the {@link Implementation} interface.
050 *
051 * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
052 * @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird</a>
053 * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
054 *
055 * @version $Id: ImplementationImpl.java,v 1.1 2007-08-24 22:17:37 ewestfal Exp $
056 */
057 public class ImplementationImpl implements ImplementationExt
058 {
059 private Logger log = LoggerFactory.getLogger(ImplementationImpl.class);
060
061 // private List usedDatabases = new ArrayList();
062 private DatabaseImpl currentDatabase;
063 private Configurator configurator;
064 private OJBTxManager ojbTxManager;
065 private LockManager lockManager;
066
067 private Class oqlCollectionClass;
068 private boolean impliciteWriteLocks;
069 private boolean implicitLocking;
070 private boolean implicitLockingBackward;
071 private boolean ordering;
072 // private boolean noteUserOrder;
073
074 /**
075 * private Constructor: use static factory method
076 * getInstance() to obtain an instance
077 */
078 protected ImplementationImpl()
079 {
080 ojbTxManager = TxManagerFactory.instance();
081 lockManager = LockManagerFactory.getLockManager();
082 setConfigurator(PersistenceBrokerFactory.getConfigurator());
083 Configuration conf = getConfigurator().getConfigurationFor(null);
084 oqlCollectionClass = conf.getClass("OqlCollectionClass", ManageableArrayList.class);
085 impliciteWriteLocks = (conf.getString("LockAssociations", "WRITE").equalsIgnoreCase("WRITE"));
086 implicitLocking = conf.getBoolean("ImplicitLocking", true);
087 ordering = conf.getBoolean("Ordering", true);
088 // noteUserOrder = conf.getBoolean("NoteUserOrder", true);
089 implicitLockingBackward = conf.getBoolean("ImplicitLockingBackward", false);
090 if(log.isEnabledFor(Logger.INFO))
091 {
092 log.info("Settings: " + this.toString());
093 }
094 }
095
096 public OJBTxManager getTxManager()
097 {
098 return ojbTxManager;
099 }
100
101 protected LockManager getLockManager()
102 {
103 return lockManager;
104 }
105
106 protected synchronized void setCurrentDatabase(DatabaseImpl curDB)
107 {
108 currentDatabase = curDB;
109 }
110
111 protected synchronized DatabaseImpl getCurrentDatabase()
112 {
113 return currentDatabase;
114 }
115
116 public PBKey getCurrentPBKey()
117 {
118 return currentDatabase.getPBKey();
119 }
120
121 /**
122 * Gets the configurator.
123 * @return Returns a Configurator
124 */
125 public Configurator getConfigurator()
126 {
127 return configurator;
128 }
129
130 /**
131 * Sets the configurator.
132 * @param configurator The configurator to set
133 */
134 public void setConfigurator(Configurator configurator)
135 {
136 this.configurator = configurator;
137 }
138
139 /**
140 * Create a <code>Transaction</code> object and associate it with the current thread.
141 * @return The newly created <code>Transaction</code> instance.
142 * @see Transaction
143 */
144 public Transaction newTransaction()
145 {
146 if ((getCurrentDatabase() == null))
147 {
148 throw new DatabaseClosedException("Database is NULL, must have a DB in order to create a transaction");
149 }
150 TransactionImpl tx = new TransactionImpl(this);
151 try
152 {
153 getConfigurator().configure(tx);
154 }
155 catch (ConfigurationException e)
156 {
157 throw new ODMGRuntimeException("Error in configuration of TransactionImpl instance: " + e.getMessage());
158 }
159 return tx;
160 }
161
162 /**
163 * Get the current <code>Transaction</code> for the thread.
164 * @return The current <code>Transaction</code> object or null if there is none.
165 * @see Transaction
166 */
167 public Transaction currentTransaction()
168 {
169 if ((getCurrentDatabase() == null))
170 {
171 throw new DatabaseClosedException("Database is NULL, must have a DB in order to create a transaction");
172 }
173 return ojbTxManager.getTransaction();
174 }
175
176 public boolean hasOpenTransaction()
177 {
178 TransactionImpl tx = ojbTxManager.getTransaction();
179 return tx != null && tx.isOpen();
180 }
181
182 /**
183 * Create a new <code>Database</code> object.
184 * @return The new <code>Database</code> object.
185 * @see Database
186 */
187 public Database newDatabase()
188 {
189 return new DatabaseImpl(this);
190 }
191
192 /**
193 * Create a new <code>OQLQuery</code> object.
194 * @return The new <code>OQLQuery</code> object.
195 * @see org.odmg.OQLQuery
196 */
197 public EnhancedOQLQuery newOQLQuery()
198 {
199 if ((getCurrentDatabase() == null) || !getCurrentDatabase().isOpen())
200 {
201 throw new DatabaseClosedException("Database is not open");
202 }
203 return new OQLQueryImpl(this);
204 }
205
206 /**
207 * Create a new <code>DList</code> object.
208 * @return The new <code>DList</code> object.
209 * @see DList
210 */
211 public DList newDList()
212 {
213 if ((getCurrentDatabase() == null))
214 {
215 throw new DatabaseClosedException("Database is NULL, cannot create a DList with a null database.");
216 }
217 return (DList) DListFactory.singleton.createCollectionOrMap(getCurrentPBKey());
218 }
219
220 /**
221 * Create a new <code>DBag</code> object.
222 * @return The new <code>DBag</code> object.
223 * @see DBag
224 */
225 public DBag newDBag()
226 {
227 if ((getCurrentDatabase() == null))
228 {
229 throw new DatabaseClosedException("Database is NULL, cannot create a DBag with a null database.");
230 }
231 return (DBag) DBagFactory.singleton.createCollectionOrMap(getCurrentPBKey());
232 }
233
234 /**
235 * Create a new <code>DSet</code> object.
236 * @return The new <code>DSet</code> object.
237 * @see DSet
238 */
239 public DSet newDSet()
240 {
241 if ((getCurrentDatabase() == null))
242 {
243 throw new DatabaseClosedException("Database is NULL, cannot create a DSet with a null database.");
244 }
245 return (DSet) DSetFactory.singleton.createCollectionOrMap(getCurrentPBKey());
246 }
247
248 /**
249 * Create a new <code>DArray</code> object.
250 * @return The new <code>DArray</code> object.
251 * @see DArray
252 */
253 public DArray newDArray()
254 {
255 if ((getCurrentDatabase() == null))
256 {
257 throw new DatabaseClosedException("Database is NULL, cannot create a DArray with a null database.");
258 }
259 return (DArray) DArrayFactory.singleton.createCollectionOrMap(getCurrentPBKey());
260 }
261
262 /**
263 * Create a new <code>DMap</code> object.
264 * @return The new <code>DMap</code> object.
265 * @see DMap
266 */
267 public DMap newDMap()
268 {
269 if ((getCurrentDatabase() == null))
270 {
271 throw new DatabaseClosedException("Database is NULL, cannot create a DMap with a null database.");
272 }
273 return (DMap) DMapFactory.singleton.createCollectionOrMap(getCurrentPBKey());
274 }
275
276 /**
277 * Get a <code>String</code> representation of the object's identifier.
278 * OJB returns the serialized Identity of the object.
279 * @param obj The object whose identifier is being accessed.
280 * @return The object's identifier in the form of a String
281 */
282 public String getObjectId(Object obj)
283 {
284 Identity oid = null;
285 PersistenceBroker broker = null;
286
287 try
288 {
289 if (getCurrentDatabase() != null)
290 {
291 /**
292 * is there an open database we are calling getObjectId against? if yes, use it
293 */
294 broker = PersistenceBrokerFactory.createPersistenceBroker(getCurrentDatabase().getPBKey());
295 }
296 else
297 {
298 log.warn("Can't find open database, try to use the default configuration");
299 /**
300 * otherwise, use default.
301 */
302 broker = PersistenceBrokerFactory.defaultPersistenceBroker();
303 }
304
305 oid = broker.serviceIdentity().buildIdentity(obj);
306 }
307 finally
308 {
309 if(broker != null)
310 {
311 broker.close();
312 }
313 }
314 return new String(SerializationUtils.serialize(oid));
315 }
316
317 /**
318 * Returns the current used database or null.
319 */
320 public Database getDatabase(Object obj)
321 {
322 /* @todo enhance functionality */
323 return getCurrentDatabase();
324 }
325
326 /**
327 * Register opened database via the PBKey.
328 */
329 protected synchronized void registerOpenDatabase(DatabaseImpl newDB)
330 {
331 DatabaseImpl old_db = getCurrentDatabase();
332 if (old_db != null)
333 {
334 try
335 {
336 if (old_db.isOpen())
337 {
338 log.warn("## There is still an opened database, close old one ##");
339 old_db.close();
340 }
341 }
342 catch (Throwable t)
343 {
344 //ignore
345 }
346 }
347 if (log.isDebugEnabled()) log.debug("Set current database " + newDB + " PBKey was " + newDB.getPBKey());
348 setCurrentDatabase(newDB);
349 // usedDatabases.add(newDB.getPBKey());
350 }
351
352 /**
353 * <strong>Note:</strong> Method behavior changed between version 1.0.3 and
354 * 1.0.4. Now this method is used to set the global property <em>implicit locking</em>,
355 * use method {@link TransactionExt#setImplicitLocking(boolean)} to set the property
356 * for a running transaction.
357 *
358 * @see ImplementationExt#setImplicitLocking(boolean)
359 */
360 public void setImplicitLocking(boolean value)
361 {
362 if(implicitLockingBackward)
363 {
364 ((TransactionExt)currentTransaction()).setImplicitLocking(value);
365 }
366 else
367 {
368 this.implicitLocking = value;
369 }
370 }
371
372 /**
373 * @see ImplementationExt#isImplicitLocking()
374 */
375 public boolean isImplicitLocking()
376 {
377 return implicitLocking;
378 }
379
380 /**
381 * @see ImplementationExt#getOqlCollectionClass()
382 */
383 public Class getOqlCollectionClass()
384 {
385 return oqlCollectionClass;
386 }
387
388 /**
389 * @see ImplementationExt#setOqlCollectionClass(Class)
390 */
391 public void setOqlCollectionClass(Class oqlCollectionClass)
392 {
393 this.oqlCollectionClass = oqlCollectionClass;
394 }
395
396 /**
397 * @see ImplementationExt#setImpliciteWriteLocks(boolean)
398 */
399 public void setImpliciteWriteLocks(boolean impliciteWriteLocks)
400 {
401 this.impliciteWriteLocks = impliciteWriteLocks;
402 }
403
404 /**
405 * @see ImplementationExt#isImpliciteWriteLocks()
406 */
407 public boolean isImpliciteWriteLocks()
408 {
409 return impliciteWriteLocks;
410 }
411
412 public boolean isOrdering()
413 {
414 return ordering;
415 }
416
417 public void setOrdering(boolean ordering)
418 {
419 this.ordering = ordering;
420 }
421
422 // public boolean isNoteUserOrder()
423 // {
424 // return noteUserOrder;
425 // }
426 //
427 // public void setNoteUserOrder(boolean noteUserOrder)
428 // {
429 // this.noteUserOrder = noteUserOrder;
430 // }
431
432 /**
433 * Allow to use method {@link #setImplicitLocking(boolean)} in the same way
434 * as before version 1.0.4 - if set 'true', recommended setting is 'false'.
435 *
436 * @deprecated is only for backward compatibility with older versions (before 1.0.4)
437 * and will be removed in future versions.
438 */
439 public void setImplicitLockingBackward(boolean implicitLockingBackward)
440 {
441 this.implicitLockingBackward = implicitLockingBackward;
442 }
443
444 public String toString()
445 {
446 return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
447 .append("implicitLocking", isImplicitLocking())
448 .append("implicitWriteLocks", isImpliciteWriteLocks())
449 .append("ordering", isOrdering())
450 .append("oqlCollectionClass", getOqlCollectionClass())
451 .append("txManager", getTxManager())
452 .append("lockManager", getLockManager())
453 .toString();
454 }
455
456
457 //*****************************************************
458 // inner classes
459 //*****************************************************
460
461 abstract static class BaseFactory extends ConfigurableFactory
462 {
463 Object createCollectionOrMap()
464 {
465 return this.createNewInstance();
466 }
467
468 Object createCollectionOrMap(PBKey key)
469 {
470 return createNewInstance(PBKey.class, key);
471 }
472 }
473
474 static final class DListFactory extends BaseFactory
475 {
476 static final BaseFactory singleton = new DListFactory();
477 protected String getConfigurationKey()
478 {
479 return "DListClass";
480 }
481 }
482
483 static final class DArrayFactory extends BaseFactory
484 {
485 static final BaseFactory singleton = new DArrayFactory();
486 protected String getConfigurationKey()
487 {
488 return "DArrayClass";
489 }
490 }
491
492 static final class DBagFactory extends BaseFactory
493 {
494 static final BaseFactory singleton = new DBagFactory();
495 protected String getConfigurationKey()
496 {
497 return "DBagClass";
498 }
499 }
500
501 static final class DSetFactory extends BaseFactory
502 {
503 static final BaseFactory singleton = new DSetFactory();
504 protected String getConfigurationKey()
505 {
506 return "DSetClass";
507 }
508 }
509
510 static final class DMapFactory extends BaseFactory
511 {
512 static final BaseFactory singleton = new DMapFactory();
513 protected String getConfigurationKey()
514 {
515 return "DMapClass";
516 }
517 }
518 }