Coverage Report - org.apache.ojb.broker.metadata.MetadataManager
 
Classes in this File Line Coverage Branch Coverage Complexity
MetadataManager
N/A
N/A
2.333
 
 1  
 package org.apache.ojb.broker.metadata;
 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 java.io.FileNotFoundException;
 19  
 import java.io.InputStream;
 20  
 import java.util.Hashtable;
 21  
 import java.util.Iterator;
 22  
 import java.util.List;
 23  
 
 24  
 import org.apache.commons.lang.SerializationUtils;
 25  
 import org.apache.ojb.broker.PBKey;
 26  
 import org.apache.ojb.broker.core.PersistenceBrokerConfiguration;
 27  
 import org.apache.ojb.broker.util.configuration.impl.OjbConfigurator;
 28  
 import org.apache.ojb.broker.util.logging.Logger;
 29  
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 30  
 
 31  
 /**
 32  
  * Central class for metadata operations/manipulations - manages OJB's
 33  
  * metadata objects, in particular:
 34  
  * <ul>
 35  
  * <li>{@link org.apache.ojb.broker.metadata.DescriptorRepository} contains
 36  
  * metadata of persistent objects</li>
 37  
  * <li>{@link org.apache.ojb.broker.metadata.ConnectionRepository} contains
 38  
  * all connection metadata information</li>
 39  
  * </ul>
 40  
  *
 41  
  * This class allows transparent flexible metadata loading/manipulation at runtime.
 42  
  *
 43  
  * <p>
 44  
  * <b>How to read/merge metadata</b><br/>
 45  
  * Per default OJB loads default {@link org.apache.ojb.broker.metadata.DescriptorRepository}
 46  
  * and {@link org.apache.ojb.broker.metadata.ConnectionRepository} instances, by reading the
 47  
  * specified repository file. This is done first time the <code>MetadataManager</code> instance
 48  
  * was used.
 49  
  * <br/>
 50  
  * To read metadata information at runtime use
 51  
  * {@link #readDescriptorRepository readDescriptorRepository} and
 52  
  * {@link #readConnectionRepository readConnectionRepository}
 53  
  * methods.
 54  
  * <br/>
 55  
  * It is also possible to merge different repositories using
 56  
  * {@link #mergeDescriptorRepository mergeDescriptorRepository}
 57  
  * and {@link #mergeConnectionRepository mergeConnectionRepository}
 58  
  *
 59  
  * </p>
 60  
  *
 61  
  * <a name="perThread"/>
 62  
  * <h3>Per thread handling of metadata</h3>
 63  
  * <p>
 64  
  * Per default the manager handle one global {@link org.apache.ojb.broker.metadata.DescriptorRepository}
 65  
  * for all calling threads, but it is ditto possible to use different metadata <i>profiles</i> in a per thread
 66  
  * manner - <i>profiles</i> means different copies of {@link org.apache.ojb.broker.metadata.DescriptorRepository}
 67  
  * objects.
 68  
  * <p/>
 69  
  *
 70  
  * <p>
 71  
  * <a name="enablePerThreadMode"/>
 72  
  * <b>Enable the per thread mode</b><br/>
 73  
  * To enable the 'per thread' mode for {@link org.apache.ojb.broker.metadata.DescriptorRepository}
 74  
  * instances:
 75  
  * <pre>
 76  
  *   MetadataManager mm = MetadataManager.getInstance();
 77  
  *   // tell the manager to use per thread mode
 78  
  *   mm.setEnablePerThreadChanges(true);
 79  
  *   ...
 80  
  * </pre>
 81  
  * This could be done e.g. at start up.<br/>
 82  
  * Now it's possible to use dedicated <code>DescriptorRepository</code> instances
 83  
  * per thread:
 84  
  *  <pre>
 85  
  *   // e.g we get a coppy of the global repository
 86  
  *   DescriptorRepository dr = mm.copyOfGlobalRepository();
 87  
  *   // now we can manipulate the persistent object metadata of the copy
 88  
  *   ......
 89  
  *
 90  
  *   // set the changed repository for this thread
 91  
  *   mm.setDescriptor(dr);
 92  
  *
 93  
  *   // now let this thread lookup a PersistenceBroker instance
 94  
  *   // with the modified metadata
 95  
  *   // all other threads use the global metadata
 96  
  *   PersistenceBroker broker = Persis......
 97  
  * </pre>
 98  
  * Note: Change metadata <i>before</i> lookup the {@link org.apache.ojb.broker.PersistenceBroker}
 99  
  * instance for current thread, because the metadata was bound to the PB at lookup.
 100  
  * </p>
 101  
  *
 102  
  * <p>
 103  
  * <b>How to use different metadata profiles</b><br/>
 104  
  * MetadataManager was shipped with a simple mechanism to
 105  
  * add, remove and load different persistent objects metadata
 106  
  * profiles (different {@link org.apache.ojb.broker.metadata.DescriptorRepository}
 107  
  * instances) in a per thread manner. Use
 108  
  * <ul>
 109  
  * <li>{@link #addProfile addProfile} add different persistent object metadata profiles</li>
 110  
  * <li>{@link #removeProfile removeProfile} remove a persistent object metadata profiles</li>
 111  
  * <li>{@link #loadProfile loadProfile} load a profile for the current thread</li>
 112  
  * </ul>
 113  
  * Note: method {@link #loadProfile loadProfile} only works if
 114  
  * the <a href="#enablePerThreadMode">per thread mode</a> is enabled.
 115  
  * </p>
 116  
  *
 117  
  *
 118  
  * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
 119  
  * @version $Id: MetadataManager.java,v 1.1 2007-08-24 22:17:29 ewestfal Exp $
 120  
  */
 121  
 public class MetadataManager
 122  
 {
 123  
     private static Logger log = LoggerFactory.getLogger(MetadataManager.class);
 124  
 
 125  
     private static final String MSG_STR = "* Can't find DescriptorRepository for current thread, use default one *";
 126  
     private static ThreadLocal threadedRepository = new ThreadLocal();
 127  
     private static ThreadLocal currentProfileKey = new ThreadLocal();
 128  
     private static MetadataManager singleton;
 129  
 
 130  
     private Hashtable metadataProfiles;
 131  
     private DescriptorRepository globalRepository;
 132  
     private ConnectionRepository connectionRepository;
 133  
     private boolean enablePerThreadChanges;
 134  
     private PBKey defaultPBKey;
 135  
 
 136  
     // singleton
 137  
     private MetadataManager()
 138  
     {
 139  
         init();
 140  
     }
 141  
 
 142  
     private void init()
 143  
     {
 144  
         metadataProfiles = new Hashtable();
 145  
         final String repository = ((PersistenceBrokerConfiguration) OjbConfigurator.getInstance()
 146  
                 .getConfigurationFor(null)).getRepositoryFilename();
 147  
         try
 148  
         {
 149  
             globalRepository     = new RepositoryPersistor().readDescriptorRepository(repository);
 150  
             connectionRepository = new RepositoryPersistor().readConnectionRepository(repository);
 151  
         }
 152  
         catch (FileNotFoundException ex)
 153  
         {
 154  
             log.warn("Could not access '" + repository + "' or a DOCTYPE/DTD-dependency. "
 155  
                      + "(Check letter case for file names and HTTP-access if using DOCTYPE PUBLIC)"
 156  
                      + " Starting with empty metadata and connection configurations.", ex);
 157  
             globalRepository     = new DescriptorRepository();
 158  
             connectionRepository = new ConnectionRepository();
 159  
         }
 160  
         catch (Exception ex)
 161  
         {
 162  
             throw new MetadataException("Can't read repository file '" + repository + "'", ex);
 163  
         }
 164  
     }
 165  
 
 166  
     public void shutdown()
 167  
     {
 168  
         threadedRepository = null;
 169  
         currentProfileKey = null;
 170  
         globalRepository = null;
 171  
         metadataProfiles = null;
 172  
         singleton = null;
 173  
     }
 174  
 
 175  
     /**
 176  
      * Returns an instance of this class.
 177  
      */
 178  
     public static synchronized MetadataManager getInstance()
 179  
     {
 180  
         // lazy initialization
 181  
         if (singleton == null)
 182  
         {
 183  
             singleton = new MetadataManager();
 184  
         }
 185  
         return singleton;
 186  
     }
 187  
 
 188  
     /**
 189  
      * Returns the current valid {@link org.apache.ojb.broker.metadata.DescriptorRepository} for
 190  
      * the caller. This is the provided way to obtain the
 191  
      * {@link org.apache.ojb.broker.metadata.DescriptorRepository}.
 192  
      * <br>
 193  
      * When {@link #isEnablePerThreadChanges per thread descriptor handling}  is enabled
 194  
      * it search for a specific {@link org.apache.ojb.broker.metadata.DescriptorRepository}
 195  
      * for the calling thread, if none can be found the global descriptor was returned.
 196  
      *
 197  
      * @see MetadataManager#getGlobalRepository
 198  
      * @see MetadataManager#copyOfGlobalRepository
 199  
      */
 200  
     public DescriptorRepository getRepository()
 201  
     {
 202  
         DescriptorRepository repository;
 203  
         if (enablePerThreadChanges)
 204  
         {
 205  
             repository = (DescriptorRepository) threadedRepository.get();
 206  
             if (repository == null)
 207  
             {
 208  
                 repository = getGlobalRepository();
 209  
                 log.info(MSG_STR);
 210  
             }
 211  
 // arminw:
 212  
 // TODO: Be more strict in per thread mode and throw a exception when not find descriptor for calling thread?
 213  
 //            if (repository == null)
 214  
 //            {
 215  
 //                throw new MetadataException("Can't find a DescriptorRepository for current thread, don't forget" +
 216  
 //                        " to set a DescriptorRepository if enable per thread changes before perform other action");
 217  
 //            }
 218  
             return repository;
 219  
         }
 220  
         else
 221  
         {
 222  
             return globalRepository;
 223  
         }
 224  
     }
 225  
 
 226  
     /**
 227  
      * Returns explicit the global {@link org.apache.ojb.broker.metadata.DescriptorRepository} - use with
 228  
      * care, because it ignores the {@link #isEnablePerThreadChanges per thread mode}.
 229  
      *
 230  
      * @see MetadataManager#getRepository
 231  
      * @see MetadataManager#copyOfGlobalRepository
 232  
      */
 233  
     public DescriptorRepository getGlobalRepository()
 234  
     {
 235  
         return globalRepository;
 236  
     }
 237  
 
 238  
     /**
 239  
      * Returns the {@link ConnectionRepository}.
 240  
      */
 241  
     public ConnectionRepository connectionRepository()
 242  
     {
 243  
         return connectionRepository;
 244  
     }
 245  
 
 246  
     /**
 247  
      * Merge the given {@link ConnectionRepository} with the existing one (without making
 248  
      * a deep copy of the containing connection descriptors).
 249  
      * @see #mergeConnectionRepository(ConnectionRepository targetRepository, ConnectionRepository sourceRepository, boolean deep)
 250  
      */
 251  
     public void mergeConnectionRepository(ConnectionRepository repository)
 252  
     {
 253  
         mergeConnectionRepository(connectionRepository(), repository, false);
 254  
     }
 255  
 
 256  
     /**
 257  
      * Merge the given source {@link ConnectionRepository} with the
 258  
      * existing target. If parameter
 259  
      * <tt>deep</tt> is set <code>true</code> deep copies of source objects were made.
 260  
      * <br/>
 261  
      * Note: Using <tt>deep copy mode</tt> all descriptors will be serialized
 262  
      * by using the default class loader to resolve classes. This can be problematic
 263  
      * when classes are loaded by a context class loader.
 264  
      * <p>
 265  
      * Note: All classes within the repository structure have to implement
 266  
      * <code>java.io.Serializable</code> to be able to create a cloned copy.
 267  
      */
 268  
     public void mergeConnectionRepository(
 269  
             ConnectionRepository targetRepository, ConnectionRepository sourceRepository, boolean deep)
 270  
     {
 271  
         List list = sourceRepository.getAllDescriptor();
 272  
         for (Iterator iterator = list.iterator(); iterator.hasNext();)
 273  
         {
 274  
             JdbcConnectionDescriptor jcd = (JdbcConnectionDescriptor) iterator.next();
 275  
             if (deep)
 276  
             {
 277  
                 //TODO: adopt copy/clone methods for metadata classes?
 278  
                 jcd = (JdbcConnectionDescriptor) SerializationUtils.clone(jcd);
 279  
             }
 280  
             targetRepository.addDescriptor(jcd);
 281  
         }
 282  
     }
 283  
 
 284  
     /**
 285  
      * Merge the given {@link org.apache.ojb.broker.metadata.DescriptorRepository}
 286  
      * (without making a deep copy of containing class-descriptor objects) with the
 287  
      * global one, returned by method {@link #getRepository()} - keep
 288  
      * in mind if running in <a href="#perThread">per thread mode</a>
 289  
      * merge maybe only takes effect on current thread.
 290  
      *
 291  
      * @see #mergeDescriptorRepository(DescriptorRepository targetRepository, DescriptorRepository sourceRepository, boolean deep)
 292  
      */
 293  
     public void mergeDescriptorRepository(DescriptorRepository repository)
 294  
     {
 295  
         mergeDescriptorRepository(getRepository(), repository, false);
 296  
     }
 297  
 
 298  
     /**
 299  
      * Merge the given {@link org.apache.ojb.broker.metadata.DescriptorRepository}
 300  
      * files, the source objects will be pushed to the target repository. If parameter
 301  
      * <tt>deep</tt> is set <code>true</code> deep copies of source objects were made.
 302  
      * <br/>
 303  
      * Note: Using <tt>deep copy mode</tt> all descriptors will be serialized
 304  
      * by using the default class loader to resolve classes. This can be problematic
 305  
      * when classes are loaded by a context class loader.
 306  
      * <p>
 307  
      * Note: All classes within the repository structure have to implement
 308  
      * <code>java.io.Serializable</code> to be able to create a cloned copy.
 309  
      *
 310  
      * @see #isEnablePerThreadChanges
 311  
      * @see #setEnablePerThreadChanges
 312  
      */
 313  
     public void mergeDescriptorRepository(
 314  
             DescriptorRepository targetRepository, DescriptorRepository sourceRepository, boolean deep)
 315  
     {
 316  
         Iterator it = sourceRepository.iterator();
 317  
         while (it.hasNext())
 318  
         {
 319  
             ClassDescriptor cld = (ClassDescriptor) it.next();
 320  
             if (deep)
 321  
             {
 322  
                 //TODO: adopt copy/clone methods for metadata classes?
 323  
                 cld = (ClassDescriptor) SerializationUtils.clone(cld);
 324  
             }
 325  
             targetRepository.put(cld.getClassOfObject(), cld);
 326  
             cld.setRepository(targetRepository);
 327  
         }
 328  
     }
 329  
 
 330  
     /**
 331  
      * Read ClassDescriptors from the given repository file.
 332  
      * @see #mergeDescriptorRepository
 333  
      */
 334  
     public DescriptorRepository readDescriptorRepository(String fileName)
 335  
     {
 336  
         try
 337  
         {
 338  
             RepositoryPersistor persistor = new RepositoryPersistor();
 339  
             return persistor.readDescriptorRepository(fileName);
 340  
         }
 341  
         catch (Exception e)
 342  
         {
 343  
             throw new MetadataException("Can not read repository " + fileName, e);
 344  
         }
 345  
     }
 346  
 
 347  
     /**
 348  
      * Read ClassDescriptors from the given InputStream.
 349  
      * @see #mergeDescriptorRepository
 350  
      */
 351  
     public DescriptorRepository readDescriptorRepository(InputStream inst)
 352  
     {
 353  
         try
 354  
         {
 355  
             RepositoryPersistor persistor = new RepositoryPersistor();
 356  
             return persistor.readDescriptorRepository(inst);
 357  
         }
 358  
         catch (Exception e)
 359  
         {
 360  
             throw new MetadataException("Can not read repository " + inst, e);
 361  
         }
 362  
     }
 363  
 
 364  
     /**
 365  
      * Read JdbcConnectionDescriptors from the given repository file.
 366  
      *
 367  
      * @see #mergeConnectionRepository
 368  
      */
 369  
     public ConnectionRepository readConnectionRepository(String fileName)
 370  
     {
 371  
         try
 372  
         {
 373  
             RepositoryPersistor persistor = new RepositoryPersistor();
 374  
             return persistor.readConnectionRepository(fileName);
 375  
         }
 376  
         catch (Exception e)
 377  
         {
 378  
             throw new MetadataException("Can not read repository " + fileName, e);
 379  
         }
 380  
     }
 381  
 
 382  
     /**
 383  
      * Read JdbcConnectionDescriptors from this InputStream.
 384  
      *
 385  
      * @see #mergeConnectionRepository
 386  
      */
 387  
     public ConnectionRepository readConnectionRepository(InputStream inst)
 388  
     {
 389  
         try
 390  
         {
 391  
             RepositoryPersistor persistor = new RepositoryPersistor();
 392  
             return persistor.readConnectionRepository(inst);
 393  
         }
 394  
         catch (Exception e)
 395  
         {
 396  
             throw new MetadataException("Can not read repository from " + inst, e);
 397  
         }
 398  
     }
 399  
 
 400  
     /**
 401  
      * Set the {@link org.apache.ojb.broker.metadata.DescriptorRepository} - if <i>global</i> was true, the
 402  
      * given descriptor aquire global availability (<i>use with care!</i>),
 403  
      * else the given descriptor was associated with the calling thread.
 404  
      *
 405  
      * @see #isEnablePerThreadChanges
 406  
      * @see #setEnablePerThreadChanges
 407  
      */
 408  
     public void setDescriptor(DescriptorRepository repository, boolean global)
 409  
     {
 410  
         if (global)
 411  
         {
 412  
             if (log.isDebugEnabled()) log.debug("Set new global repository: " + repository);
 413  
             globalRepository = repository;
 414  
         }
 415  
         else
 416  
         {
 417  
             if (log.isDebugEnabled()) log.debug("Set new threaded repository: " + repository);
 418  
             threadedRepository.set(repository);
 419  
         }
 420  
     }
 421  
 
 422  
     /**
 423  
      * Set {@link DescriptorRepository} for the current thread.
 424  
      * Convenience method for
 425  
      * {@link #setDescriptor(DescriptorRepository repository, boolean global) setDescriptor(repository, false)}.
 426  
      */
 427  
     public void setDescriptor(DescriptorRepository repository)
 428  
     {
 429  
         setDescriptor(repository, false);
 430  
     }
 431  
 
 432  
     /**
 433  
      * Convenience method for
 434  
      * {@link #setDescriptor setDescriptor(repository, false)}.
 435  
      * @deprecated use {@link #setDescriptor}
 436  
      */
 437  
     public void setPerThreadDescriptor(DescriptorRepository repository)
 438  
     {
 439  
         setDescriptor(repository, false);
 440  
     }
 441  
 
 442  
     /**
 443  
      * Returns a copy of the current global
 444  
      * {@link org.apache.ojb.broker.metadata.DescriptorRepository}
 445  
      * <p>
 446  
      * Note: All classes within the repository structure have to implement
 447  
      * <code>java.io.Serializable</code> to be able to create a cloned copy.
 448  
      *
 449  
      * @see MetadataManager#getGlobalRepository
 450  
      * @see MetadataManager#getRepository
 451  
      */
 452  
     public DescriptorRepository copyOfGlobalRepository()
 453  
     {
 454  
         return (DescriptorRepository) SerializationUtils.clone(globalRepository);
 455  
     }
 456  
 
 457  
     /**
 458  
      * If returns <i>true</i> if <a href="#perThread">per thread</a> runtime
 459  
      * changes of the {@link org.apache.ojb.broker.metadata.DescriptorRepository}
 460  
      * is enabled and the {@link #getRepository} method returns a threaded
 461  
      * repository file if set, or the global if no threaded was found.
 462  
      * <br>
 463  
      * If returns <i>false</i> the {@link #getRepository} method return
 464  
      * always the {@link #getGlobalRepository() global} repository.
 465  
      *
 466  
      * @see #setEnablePerThreadChanges
 467  
      */
 468  
     public boolean isEnablePerThreadChanges()
 469  
     {
 470  
         return enablePerThreadChanges;
 471  
     }
 472  
 
 473  
     /**
 474  
      * Enable the possibility of making <a href="#perThread">per thread</a> runtime changes
 475  
      * of the {@link org.apache.ojb.broker.metadata.DescriptorRepository}.
 476  
      *
 477  
      * @see #isEnablePerThreadChanges
 478  
      */
 479  
     public void setEnablePerThreadChanges(boolean enablePerThreadChanges)
 480  
     {
 481  
         this.enablePerThreadChanges = enablePerThreadChanges;
 482  
     }
 483  
 
 484  
     /**
 485  
      * Add a metadata profile.
 486  
      * @see #loadProfile
 487  
      */
 488  
     public void addProfile(Object key, DescriptorRepository repository)
 489  
     {
 490  
         if (metadataProfiles.contains(key))
 491  
         {
 492  
             throw new MetadataException("Duplicate profile key. Key '" + key + "' already exists.");
 493  
         }
 494  
         metadataProfiles.put(key, repository);
 495  
     }
 496  
 
 497  
     /**
 498  
      * Load the given metadata profile for the current thread.
 499  
      *
 500  
      */
 501  
     public void loadProfile(Object key)
 502  
     {
 503  
         if (!isEnablePerThreadChanges())
 504  
         {
 505  
             throw new MetadataException("Can not load profile with disabled per thread mode");
 506  
         }
 507  
         DescriptorRepository rep = (DescriptorRepository) metadataProfiles.get(key);
 508  
         if (rep == null)
 509  
         {
 510  
             throw new MetadataException("Can not find profile for key '" + key + "'");
 511  
         }
 512  
         currentProfileKey.set(key);
 513  
         setDescriptor(rep);
 514  
     }
 515  
 
 516  
     /**
 517  
      * Returns the last activated profile key.
 518  
      * @return the last activated profile key or null if no profile has been loaded
 519  
      * @throws MetadataException if per-thread changes has not been activated
 520  
      * @see #loadProfile(Object)
 521  
      */
 522  
     public Object getCurrentProfileKey() throws MetadataException
 523  
     {
 524  
         if (!isEnablePerThreadChanges())
 525  
         {
 526  
             throw new MetadataException("Call to this method is undefined, since per-thread mode is disabled.");
 527  
         }
 528  
         return currentProfileKey.get();
 529  
     }
 530  
 
 531  
     /**
 532  
      * Remove the given metadata profile.
 533  
      */
 534  
     public DescriptorRepository removeProfile(Object key)
 535  
     {
 536  
         return (DescriptorRepository) metadataProfiles.remove(key);
 537  
     }
 538  
 
 539  
     /**
 540  
      * Remove all metadata profiles.
 541  
      */
 542  
     public void clearProfiles()
 543  
     {
 544  
         metadataProfiles.clear();
 545  
         currentProfileKey.set(null);
 546  
     }
 547  
 
 548  
     /**
 549  
      * Remove all profiles
 550  
      *
 551  
      * @see #removeProfile
 552  
      * @see #addProfile
 553  
      */
 554  
     public void removeAllProfiles()
 555  
     {
 556  
         metadataProfiles.clear();
 557  
         currentProfileKey.set(null);
 558  
     }
 559  
 
 560  
     /**
 561  
      * Return the default {@link PBKey} used in convinience method
 562  
      * {@link org.apache.ojb.broker.PersistenceBrokerFactory#defaultPersistenceBroker}.
 563  
      * <br/>
 564  
      * If in {@link JdbcConnectionDescriptor} the
 565  
      * {@link JdbcConnectionDescriptor#isDefaultConnection() default connection}
 566  
      * is enabled, OJB will detect the default {@link org.apache.ojb.broker.PBKey} by itself.
 567  
      *
 568  
      * @see #setDefaultPBKey
 569  
      */
 570  
     public PBKey getDefaultPBKey()
 571  
     {
 572  
         if(defaultPBKey == null)
 573  
         {
 574  
             defaultPBKey = buildDefaultKey();
 575  
         }
 576  
         return defaultPBKey;
 577  
     }
 578  
 
 579  
     /**
 580  
      * Set the {@link PBKey} used in convinience method
 581  
      * {@link org.apache.ojb.broker.PersistenceBrokerFactory#defaultPersistenceBroker}.
 582  
      * <br/>
 583  
      * It's only allowed to use one {@link JdbcConnectionDescriptor} with enabled
 584  
      * {@link JdbcConnectionDescriptor#isDefaultConnection() default connection}. In this case
 585  
      * OJB will automatically set the default key.
 586  
      * <br/>
 587  
      * Note: It's recommended to set this key only once and not to change at runtime
 588  
      * of OJB to avoid side-effects.
 589  
      * If set more then one time a warning will be logged.
 590  
      * @throws MetadataException if key was set more than one time
 591  
      */
 592  
     public void setDefaultPBKey(PBKey defaultPBKey)
 593  
     {
 594  
         if(this.defaultPBKey != null)
 595  
         {
 596  
             log.warn("The used default PBKey change. Current key is " + this.defaultPBKey + ", new key will be " + defaultPBKey);
 597  
         }
 598  
         this.defaultPBKey = defaultPBKey;
 599  
         log.info("Set default PBKey for convenience broker creation: " + defaultPBKey);
 600  
     }
 601  
 
 602  
     /**
 603  
      * Try to build an default PBKey for convenience PB create method.
 604  
      *
 605  
      * @return PBKey or <code>null</code> if default key was not declared in
 606  
      * metadata
 607  
      */
 608  
     private PBKey buildDefaultKey()
 609  
     {
 610  
         List descriptors = connectionRepository().getAllDescriptor();
 611  
         JdbcConnectionDescriptor descriptor;
 612  
         PBKey result = null;
 613  
         for (Iterator iterator = descriptors.iterator(); iterator.hasNext();)
 614  
         {
 615  
             descriptor = (JdbcConnectionDescriptor) iterator.next();
 616  
             if (descriptor.isDefaultConnection())
 617  
             {
 618  
                 if(result != null)
 619  
                 {
 620  
                     log.error("Found additional connection descriptor with enabled 'default-connection' "
 621  
                             + descriptor.getPBKey() + ". This is NOT allowed. Will use the first found descriptor " + result
 622  
                             + " as default connection");
 623  
                 }
 624  
                 else
 625  
                 {
 626  
                     result = descriptor.getPBKey();
 627  
                 }
 628  
             }
 629  
         }
 630  
 
 631  
         if(result == null)
 632  
         {
 633  
             log.info("No 'default-connection' attribute set in jdbc-connection-descriptors," +
 634  
                     " thus it's currently not possible to use 'defaultPersistenceBroker()' " +
 635  
                     " convenience method to lookup PersistenceBroker instances. But it's possible"+
 636  
                     " to enable this at runtime using 'setDefaultKey' method.");
 637  
         }
 638  
         return result;
 639  
     }
 640  
 }