View Javadoc

1   package org.apache.ojb.odmg;
2   
3   /* Copyright 2002-2005 The Apache Software Foundation
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  import org.apache.commons.lang.SerializationUtils;
19  import org.apache.commons.lang.builder.ToStringBuilder;
20  import org.apache.commons.lang.builder.ToStringStyle;
21  import org.apache.ojb.broker.Identity;
22  import org.apache.ojb.broker.PBKey;
23  import org.apache.ojb.broker.PersistenceBroker;
24  import org.apache.ojb.broker.PersistenceBrokerFactory;
25  import org.apache.ojb.broker.util.collections.ManageableArrayList;
26  import org.apache.ojb.broker.util.configuration.Configuration;
27  import org.apache.ojb.broker.util.configuration.ConfigurationException;
28  import org.apache.ojb.broker.util.configuration.Configurator;
29  import org.apache.ojb.broker.util.factory.ConfigurableFactory;
30  import org.apache.ojb.broker.util.logging.Logger;
31  import org.apache.ojb.broker.util.logging.LoggerFactory;
32  import org.apache.ojb.odmg.locking.LockManager;
33  import org.apache.ojb.odmg.locking.LockManagerFactory;
34  import org.apache.ojb.odmg.oql.EnhancedOQLQuery;
35  import org.apache.ojb.odmg.oql.OQLQueryImpl;
36  import org.odmg.DArray;
37  import org.odmg.DBag;
38  import org.odmg.DList;
39  import org.odmg.DMap;
40  import org.odmg.DSet;
41  import org.odmg.Database;
42  import org.odmg.DatabaseClosedException;
43  import org.odmg.Implementation;
44  import org.odmg.ODMGRuntimeException;
45  import org.odmg.Transaction;
46  
47  
48  /**
49   * Default implementation of the {@link Implementation} interface.
50   *
51   * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
52   * @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird</a>
53   * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
54   *
55   * @version $Id: ImplementationImpl.java,v 1.1 2007-08-24 22:17:37 ewestfal Exp $
56   */
57  public class ImplementationImpl implements ImplementationExt
58  {
59      private Logger log = LoggerFactory.getLogger(ImplementationImpl.class);
60  
61  //    private List usedDatabases = new ArrayList();
62      private DatabaseImpl currentDatabase;
63      private Configurator configurator;
64      private OJBTxManager ojbTxManager;
65      private LockManager lockManager;
66  
67      private Class oqlCollectionClass;
68      private boolean impliciteWriteLocks;
69      private boolean implicitLocking;
70      private boolean implicitLockingBackward;
71      private boolean ordering;
72  //    private boolean noteUserOrder;
73  
74      /**
75       * private Constructor: use static factory method
76       * getInstance() to obtain an instance
77       */
78      protected ImplementationImpl()
79      {
80          ojbTxManager = TxManagerFactory.instance();
81          lockManager = LockManagerFactory.getLockManager();
82          setConfigurator(PersistenceBrokerFactory.getConfigurator());
83          Configuration conf = getConfigurator().getConfigurationFor(null);
84          oqlCollectionClass = conf.getClass("OqlCollectionClass", ManageableArrayList.class);
85          impliciteWriteLocks = (conf.getString("LockAssociations", "WRITE").equalsIgnoreCase("WRITE"));
86          implicitLocking = conf.getBoolean("ImplicitLocking", true);
87          ordering = conf.getBoolean("Ordering", true);
88  //        noteUserOrder = conf.getBoolean("NoteUserOrder", true);
89          implicitLockingBackward = conf.getBoolean("ImplicitLockingBackward", false);
90          if(log.isEnabledFor(Logger.INFO))
91          {
92              log.info("Settings: " + this.toString());
93          }
94      }
95  
96      public OJBTxManager getTxManager()
97      {
98          return ojbTxManager;
99      }
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 }