Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
MetadataManager |
|
| 2.3333333333333335;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 | } |