1 /*
2 * Hibernate, Relational Persistence for Idiomatic Java
3 *
4 * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
5 * indicated by the @author tags or express copyright attribution
6 * statements applied by the authors. All third-party contributions are
7 * distributed under license by Red Hat Middleware LLC.
8 *
9 * This copyrighted material is made available to anyone wishing to use, modify,
10 * copy, or redistribute it subject to the terms and conditions of the GNU
11 * Lesser General Public License, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this distribution; if not, write to:
20 * Free Software Foundation, Inc.
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301 USA
23 *
24 */
25 package org.hibernate.cfg;
26
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.FileNotFoundException;
30 import java.io.FileOutputStream;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.ObjectInputStream;
34 import java.io.Serializable;
35 import java.io.StringReader;
36 import java.lang.reflect.Array;
37 import java.net.URL;
38 import java.util.ArrayList;
39 import java.util.Enumeration;
40 import java.util.HashMap;
41 import java.util.HashSet;
42 import java.util.Iterator;
43 import java.util.List;
44 import java.util.ListIterator;
45 import java.util.Map;
46 import java.util.Properties;
47 import java.util.Set;
48 import java.util.TreeMap;
49 import java.util.jar.JarFile;
50 import java.util.zip.ZipEntry;
51
52 import org.dom4j.Attribute;
53 import org.dom4j.DocumentException;
54 import org.dom4j.Element;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57 import org.w3c.dom.Document;
58 import org.xml.sax.EntityResolver;
59 import org.xml.sax.InputSource;
60
61 import org.hibernate.EmptyInterceptor;
62 import org.hibernate.HibernateException;
63 import org.hibernate.Interceptor;
64 import org.hibernate.InvalidMappingException;
65 import org.hibernate.MappingException;
66 import org.hibernate.MappingNotFoundException;
67 import org.hibernate.SessionFactory;
68 import org.hibernate.SessionFactoryObserver;
69 import org.hibernate.dialect.Dialect;
70 import org.hibernate.dialect.MySQLDialect;
71 import org.hibernate.dialect.function.SQLFunction;
72 import org.hibernate.engine.FilterDefinition;
73 import org.hibernate.engine.Mapping;
74 import org.hibernate.event.AutoFlushEventListener;
75 import org.hibernate.event.DeleteEventListener;
76 import org.hibernate.event.DirtyCheckEventListener;
77 import org.hibernate.event.EventListeners;
78 import org.hibernate.event.EvictEventListener;
79 import org.hibernate.event.FlushEntityEventListener;
80 import org.hibernate.event.FlushEventListener;
81 import org.hibernate.event.InitializeCollectionEventListener;
82 import org.hibernate.event.LoadEventListener;
83 import org.hibernate.event.LockEventListener;
84 import org.hibernate.event.MergeEventListener;
85 import org.hibernate.event.PersistEventListener;
86 import org.hibernate.event.PostCollectionRecreateEventListener;
87 import org.hibernate.event.PostCollectionRemoveEventListener;
88 import org.hibernate.event.PostCollectionUpdateEventListener;
89 import org.hibernate.event.PostDeleteEventListener;
90 import org.hibernate.event.PostInsertEventListener;
91 import org.hibernate.event.PostLoadEventListener;
92 import org.hibernate.event.PostUpdateEventListener;
93 import org.hibernate.event.PreCollectionRecreateEventListener;
94 import org.hibernate.event.PreCollectionRemoveEventListener;
95 import org.hibernate.event.PreCollectionUpdateEventListener;
96 import org.hibernate.event.PreDeleteEventListener;
97 import org.hibernate.event.PreInsertEventListener;
98 import org.hibernate.event.PreLoadEventListener;
99 import org.hibernate.event.PreUpdateEventListener;
100 import org.hibernate.event.RefreshEventListener;
101 import org.hibernate.event.ReplicateEventListener;
102 import org.hibernate.event.SaveOrUpdateEventListener;
103 import org.hibernate.id.IdentifierGenerator;
104 import org.hibernate.id.PersistentIdentifierGenerator;
105 import org.hibernate.impl.SessionFactoryImpl;
106 import org.hibernate.mapping.AuxiliaryDatabaseObject;
107 import org.hibernate.mapping.Collection;
108 import org.hibernate.mapping.ForeignKey;
109 import org.hibernate.mapping.IdentifierCollection;
110 import org.hibernate.mapping.Index;
111 import org.hibernate.mapping.PersistentClass;
112 import org.hibernate.mapping.Property;
113 import org.hibernate.mapping.RootClass;
114 import org.hibernate.mapping.SimpleValue;
115 import org.hibernate.mapping.Table;
116 import org.hibernate.mapping.UniqueKey;
117 import org.hibernate.proxy.EntityNotFoundDelegate;
118 import org.hibernate.secure.JACCConfiguration;
119 import org.hibernate.tool.hbm2ddl.DatabaseMetadata;
120 import org.hibernate.tool.hbm2ddl.TableMetadata;
121 import org.hibernate.type.SerializationException;
122 import org.hibernate.type.Type;
123 import org.hibernate.util.ArrayHelper;
124 import org.hibernate.util.CollectionHelper;
125 import org.hibernate.util.ConfigHelper;
126 import org.hibernate.util.PropertiesHelper;
127 import org.hibernate.util.ReflectHelper;
128 import org.hibernate.util.SerializationHelper;
129 import org.hibernate.util.StringHelper;
130 import org.hibernate.util.XMLHelper;
131
132 /**
133 * An instance of <tt>Configuration</tt> allows the application
134 * to specify properties and mapping documents to be used when
135 * creating a <tt>SessionFactory</tt>. Usually an application will create
136 * a single <tt>Configuration</tt>, build a single instance of
137 * <tt>SessionFactory</tt> and then instantiate <tt>Session</tt>s in
138 * threads servicing client requests. The <tt>Configuration</tt> is meant
139 * only as an initialization-time object. <tt>SessionFactory</tt>s are
140 * immutable and do not retain any association back to the
141 * <tt>Configuration</tt>.<br>
142 * <br>
143 * A new <tt>Configuration</tt> will use the properties specified in
144 * <tt>hibernate.properties</tt> by default.
145 *
146 * @author Gavin King
147 * @see org.hibernate.SessionFactory
148 */
149 public class Configuration implements Serializable {
150
151 private static Logger log = LoggerFactory.getLogger( Configuration.class );
152
153 protected Map classes;
154 protected Map imports;
155 protected Map collections;
156 protected Map tables;
157 protected List auxiliaryDatabaseObjects;
158 protected Map sqlFunctions;
159 protected Map namedQueries;
160 protected Map namedSqlQueries;
161 /**
162 * Map<String, SqlResultSetMapping> result set name, result set description
163 */
164 protected Map sqlResultSetMappings;
165 protected Map filterDefinitions;
166 protected List secondPasses;
167 protected List propertyReferences;
168 // protected List extendsQueue;
169 protected Map extendsQueue;
170 protected Map tableNameBinding;
171 protected Map columnNameBindingPerTable;
172 private Interceptor interceptor;
173 private Properties properties;
174 private EntityResolver entityResolver;
175 private EntityNotFoundDelegate entityNotFoundDelegate;
176
177 protected transient XMLHelper xmlHelper;
178 protected transient Map typeDefs;
179
180 protected NamingStrategy namingStrategy;
181
182 private EventListeners eventListeners;
183
184 protected final SettingsFactory settingsFactory;
185
186 private SessionFactoryObserver sessionFactoryObserver;
187
188 protected void reset() {
189 classes = new HashMap();
190 imports = new HashMap();
191 collections = new HashMap();
192 tables = new TreeMap();
193 namedQueries = new HashMap();
194 namedSqlQueries = new HashMap();
195 sqlResultSetMappings = new HashMap();
196 xmlHelper = new XMLHelper();
197 typeDefs = new HashMap();
198 propertyReferences = new ArrayList();
199 secondPasses = new ArrayList();
200 interceptor = EmptyInterceptor.INSTANCE;
201 properties = Environment.getProperties();
202 entityResolver = XMLHelper.DEFAULT_DTD_RESOLVER;
203 eventListeners = new EventListeners();
204 filterDefinitions = new HashMap();
205 // extendsQueue = new ArrayList();
206 extendsQueue = new HashMap();
207 auxiliaryDatabaseObjects = new ArrayList();
208 tableNameBinding = new HashMap();
209 columnNameBindingPerTable = new HashMap();
210 namingStrategy = DefaultNamingStrategy.INSTANCE;
211 sqlFunctions = new HashMap();
212 }
213
214 private transient Mapping mapping = buildMapping();
215
216
217
218 protected Configuration(SettingsFactory settingsFactory) {
219 this.settingsFactory = settingsFactory;
220 reset();
221 }
222
223 public Configuration() {
224 this( new SettingsFactory() );
225 }
226
227 /**
228 * Iterate the entity mappings
229 *
230 * @return Iterator of the entity mappings currently contained in the configuration.
231 */
232 public Iterator getClassMappings() {
233 return classes.values().iterator();
234 }
235
236 /**
237 * Iterate the collection mappings
238 *
239 * @return Iterator of the collection mappings currently contained in the configuration.
240 */
241 public Iterator getCollectionMappings() {
242 return collections.values().iterator();
243 }
244
245 /**
246 * Iterate the table mappings
247 *
248 * @return Iterator of the table mappings currently contained in the configuration.
249 */
250 public Iterator getTableMappings() {
251 return tables.values().iterator();
252 }
253
254 /**
255 * Get the mapping for a particular entity
256 *
257 * @param entityName An entity name.
258 * @return the entity mapping information
259 */
260 public PersistentClass getClassMapping(String entityName) {
261 return (PersistentClass) classes.get( entityName );
262 }
263
264 /**
265 * Get the mapping for a particular collection role
266 *
267 * @param role a collection role
268 * @return The collection mapping information
269 */
270 public Collection getCollectionMapping(String role) {
271 return (Collection) collections.get( role );
272 }
273
274 /**
275 * Set a custom entity resolver. This entity resolver must be
276 * set before addXXX(misc) call.
277 * Default value is {@link org.hibernate.util.DTDEntityResolver}
278 *
279 * @param entityResolver entity resolver to use
280 */
281 public void setEntityResolver(EntityResolver entityResolver) {
282 this.entityResolver = entityResolver;
283 }
284
285 public EntityResolver getEntityResolver() {
286 return entityResolver;
287 }
288
289 /**
290 * Retrieve the user-supplied delegate to handle non-existent entity
291 * scenarios. May be null.
292 *
293 * @return The user-supplied delegate
294 */
295 public EntityNotFoundDelegate getEntityNotFoundDelegate() {
296 return entityNotFoundDelegate;
297 }
298
299 /**
300 * Specify a user-supplied delegate to be used to handle scenarios where an entity could not be
301 * located by specified id. This is mainly intended for EJB3 implementations to be able to
302 * control how proxy initialization errors should be handled...
303 *
304 * @param entityNotFoundDelegate The delegate to use
305 */
306 public void setEntityNotFoundDelegate(EntityNotFoundDelegate entityNotFoundDelegate) {
307 this.entityNotFoundDelegate = entityNotFoundDelegate;
308 }
309
310 /**
311 * Read mappings from a particular XML file
312 *
313 * @param xmlFile a path to a file
314 * @return this (for method chaining purposes)
315 * @throws org.hibernate.MappingException Indicates inability to locate or parse
316 * the specified mapping file.
317 * @see #addFile(java.io.File)
318 */
319 public Configuration addFile(String xmlFile) throws MappingException {
320 return addFile( new File( xmlFile ) );
321 }
322
323 /**
324 * Read mappings from a particular XML file
325 *
326 * @param xmlFile a path to a file
327 * @return this (for method chaining purposes)
328 * @throws org.hibernate.MappingException Indicates inability to locate or parse
329 * the specified mapping file.
330 */
331 public Configuration addFile(File xmlFile) throws MappingException {
332 log.info( "Reading mappings from file: " + xmlFile.getPath() );
333 if ( !xmlFile.exists() ) {
334 throw new MappingNotFoundException( "file", xmlFile.toString() );
335 }
336 try {
337 List errors = new ArrayList();
338 org.dom4j.Document doc = xmlHelper.createSAXReader( xmlFile.toString(), errors, entityResolver ).read( xmlFile );
339 if ( errors.size() != 0 ) {
340 throw new InvalidMappingException( "file", xmlFile.toString(), ( Throwable ) errors.get( 0 ) );
341 }
342 add( doc );
343 return this;
344 }
345 catch ( InvalidMappingException e ) {
346 throw e;
347 }
348 catch ( MappingNotFoundException e ) {
349 throw e;
350 }
351 catch ( Exception e ) {
352 throw new InvalidMappingException( "file", xmlFile.toString(), e );
353 }
354 }
355
356 /**
357 * Add a cached mapping file. A cached file is a serialized representation
358 * of the DOM structure of a particular mapping. It is saved from a previous
359 * call as a file with the name <tt>xmlFile + ".bin"</tt> where xmlFile is
360 * the name of the original mapping file.
361 * </p>
362 * If a cached <tt>xmlFile + ".bin"</tt> exists and is newer than
363 * <tt>xmlFile</tt> the <tt>".bin"</tt> file will be read directly. Otherwise
364 * xmlFile is read and then serialized to <tt>xmlFile + ".bin"</tt> for use
365 * the next time.
366 *
367 * @param xmlFile The cacheable mapping file to be added.
368 * @return this (for method chaining purposes)
369 * @throws MappingException Indicates problems reading the cached file or processing
370 * the non-cached file.
371 */
372 public Configuration addCacheableFile(File xmlFile) throws MappingException {
373 try {
374 File cachedFile = new File( xmlFile.getAbsolutePath() + ".bin" );
375 org.dom4j.Document doc = null;
376
377 final boolean useCachedFile = xmlFile.exists() &&
378 cachedFile.exists() &&
379 xmlFile.lastModified() < cachedFile.lastModified();
380
381 if ( useCachedFile ) {
382 try {
383 log.info( "Reading mappings from cache file: " + cachedFile );
384 doc = ( org.dom4j.Document ) SerializationHelper.deserialize( new FileInputStream( cachedFile ) );
385 }
386 catch ( SerializationException e ) {
387 log.warn( "Could not deserialize cache file: " + cachedFile.getPath(), e );
388 }
389 catch ( FileNotFoundException e ) {
390 log.warn( "I/O reported cached file could not be found : " + cachedFile.getPath(), e );
391 }
392 }
393
394 // if doc is null, then for whatever reason, the cached file cannot be used...
395 if ( doc == null ) {
396 if ( !xmlFile.exists() ) {
397 throw new MappingNotFoundException( "file", xmlFile.toString() );
398 }
399
400 log.info( "Reading mappings from file: " + xmlFile );
401 List errors = new ArrayList();
402 try {
403 doc = xmlHelper.createSAXReader( xmlFile.getAbsolutePath(), errors, entityResolver ).read( xmlFile );
404 if ( errors.size() != 0 ) {
405 throw new MappingException( "invalid mapping", ( Throwable ) errors.get( 0 ) );
406 }
407 }
408 catch( DocumentException e){
409 throw new MappingException( "invalid mapping", e );
410 }
411
412 try {
413 log.debug( "Writing cache file for: " + xmlFile + " to: " + cachedFile );
414 SerializationHelper.serialize( ( Serializable ) doc, new FileOutputStream( cachedFile ) );
415 }
416 catch ( SerializationException e ) {
417 log.warn( "Could not write cached file: " + cachedFile, e );
418 }
419 catch ( FileNotFoundException e ) {
420 log.warn( "I/O reported error writing cached file : " + cachedFile.getPath(), e );
421 }
422 }
423
424 add( doc );
425 return this;
426
427 }
428 catch ( InvalidMappingException e ) {
429 throw e;
430 }
431 catch ( MappingNotFoundException e ) {
432 throw e;
433 }
434 catch ( Exception e ) {
435 throw new InvalidMappingException( "file", xmlFile.toString(), e );
436 }
437 }
438
439 /**
440 * Add a cacheable mapping file.
441 *
442 * @param xmlFile The name of the file to be added. This must be in a form
443 * useable to simply construct a {@link java.io.File} instance.
444 * @return this (for method chaining purposes)
445 * @throws MappingException Indicates problems reading the cached file or processing
446 * the non-cached file.
447 * @see #addCacheableFile(java.io.File)
448 */
449 public Configuration addCacheableFile(String xmlFile) throws MappingException {
450 return addCacheableFile( new File( xmlFile ) );
451 }
452
453
454 /**
455 * Read mappings from a <tt>String</tt>
456 *
457 * @param xml an XML string
458 * @return this (for method chaining purposes)
459 * @throws org.hibernate.MappingException Indicates problems parsing the
460 * given XML string
461 */
462 public Configuration addXML(String xml) throws MappingException {
463 if ( log.isDebugEnabled() ) {
464 log.debug( "Mapping XML:\n" + xml );
465 }
466 try {
467 List errors = new ArrayList();
468 org.dom4j.Document doc = xmlHelper.createSAXReader( "XML String", errors, entityResolver )
469 .read( new StringReader( xml ) );
470 if ( errors.size() != 0 ) {
471 throw new MappingException( "invalid mapping", (Throwable) errors.get( 0 ) );
472 }
473 add( doc );
474 }
475 catch (DocumentException e) {
476 throw new MappingException( "Could not parse mapping document in XML string", e );
477 }
478 return this;
479 }
480
481 /**
482 * Read mappings from a <tt>URL</tt>
483 *
484 * @param url The url for the mapping document to be read.
485 * @return this (for method chaining purposes)
486 * @throws MappingException Indicates problems reading the URL or processing
487 * the mapping document.
488 */
489 public Configuration addURL(URL url) throws MappingException {
490 if ( log.isDebugEnabled() ) {
491 log.debug( "Reading mapping document from URL:" + url.toExternalForm() );
492 }
493 try {
494 addInputStream( url.openStream() );
495 }
496 catch ( InvalidMappingException e ) {
497 throw new InvalidMappingException( "URL", url.toExternalForm(), e.getCause() );
498 }
499 catch (Exception e) {
500 throw new InvalidMappingException( "URL", url.toExternalForm(), e );
501 }
502 return this;
503 }
504
505 /**
506 * Read mappings from a DOM <tt>Document</tt>
507 *
508 * @param doc The DOM document
509 * @return this (for method chaining purposes)
510 * @throws MappingException Indicates problems reading the DOM or processing
511 * the mapping document.
512 */
513 public Configuration addDocument(Document doc) throws MappingException {
514 if ( log.isDebugEnabled() ) {
515 log.debug( "Mapping document:\n" + doc );
516 }
517 add( xmlHelper.createDOMReader().read( doc ) );
518 return this;
519 }
520
521 /**
522 * Read mappings from an {@link java.io.InputStream}.
523 *
524 * @param xmlInputStream The input stream containing a DOM.
525 * @return this (for method chaining purposes)
526 * @throws MappingException Indicates problems reading the stream, or
527 * processing the contained mapping document.
528 */
529 public Configuration addInputStream(InputStream xmlInputStream) throws MappingException {
530 try {
531 List errors = new ArrayList();
532 org.dom4j.Document doc = xmlHelper.createSAXReader( "XML InputStream", errors, entityResolver )
533 .read( new InputSource( xmlInputStream ) );
534 if ( errors.size() != 0 ) {
535 throw new InvalidMappingException( "invalid mapping", null, (Throwable) errors.get( 0 ) );
536 }
537 add( doc );
538 return this;
539 }
540 catch (DocumentException e) {
541 throw new InvalidMappingException( "input stream", null, e );
542 }
543 finally {
544 try {
545 xmlInputStream.close();
546 }
547 catch (IOException ioe) {
548 log.warn( "Could not close input stream", ioe );
549 }
550 }
551 }
552
553 /**
554 * Read mappings as a application resource (i.e. classpath lookup).
555 *
556 * @param resourceName The resource name
557 * @param classLoader The class loader to use.
558 * @return this (for method chaining purposes)
559 * @throws MappingException Indicates problems locating the resource or
560 * processing the contained mapping document.
561 */
562 public Configuration addResource(String resourceName, ClassLoader classLoader) throws MappingException {
563 log.info( "Reading mappings from resource: " + resourceName );
564 InputStream rsrc = classLoader.getResourceAsStream( resourceName );
565 if ( rsrc == null ) {
566 throw new MappingNotFoundException( "resource", resourceName );
567 }
568 try {
569 return addInputStream( rsrc );
570 }
571 catch (MappingException me) {
572 throw new InvalidMappingException( "resource", resourceName, me );
573 }
574 }
575
576 /**
577 * Read mappings as a application resourceName (i.e. classpath lookup)
578 * trying different classloaders.
579 *
580 * @param resourceName The resource name
581 * @return this (for method chaining purposes)
582 * @throws MappingException Indicates problems locating the resource or
583 * processing the contained mapping document.
584 */
585 public Configuration addResource(String resourceName) throws MappingException {
586 log.info( "Reading mappings from resource : " + resourceName );
587 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
588 InputStream rsrc = null;
589 if (contextClassLoader!=null) {
590 rsrc = contextClassLoader.getResourceAsStream( resourceName );
591 }
592 if ( rsrc == null ) {
593 rsrc = Environment.class.getClassLoader().getResourceAsStream( resourceName );
594 }
595 if ( rsrc == null ) {
596 throw new MappingNotFoundException( "resource", resourceName );
597 }
598 try {
599 return addInputStream( rsrc );
600 }
601 catch (MappingException me) {
602 throw new InvalidMappingException( "resource", resourceName, me );
603 }
604 }
605
606 /**
607 * Read a mapping as an application resouurce using the convention that a class
608 * named <tt>foo.bar.Foo</tt> is mapped by a file <tt>foo/bar/Foo.hbm.xml</tt>
609 * which can be resolved as a classpath resource.
610 *
611 * @param persistentClass The mapped class
612 * @return this (for method chaining purposes)
613 * @throws MappingException Indicates problems locating the resource or
614 * processing the contained mapping document.
615 */
616 public Configuration addClass(Class persistentClass) throws MappingException {
617 String mappingResourceName = persistentClass.getName().replace( '.', '/' ) + ".hbm.xml";
618 log.info( "Reading mappings from resource: " + mappingResourceName );
619 return addResource( mappingResourceName, persistentClass.getClassLoader() );
620 }
621
622 /**
623 * Read all mappings from a jar file
624 * <p/>
625 * Assumes that any file named <tt>*.hbm.xml</tt> is a mapping document.
626 *
627 * @param jar a jar file
628 * @return this (for method chaining purposes)
629 * @throws MappingException Indicates problems reading the jar file or
630 * processing the contained mapping documents.
631 */
632 public Configuration addJar(File jar) throws MappingException {
633 log.info( "Searching for mapping documents in jar: " + jar.getName() );
634 JarFile jarFile = null;
635 try {
636 try {
637 jarFile = new JarFile( jar );
638 }
639 catch (IOException ioe) {
640 throw new InvalidMappingException(
641 "Could not read mapping documents from jar: " + jar.getName(), "jar", jar.getName(),
642 ioe
643 );
644 }
645 Enumeration jarEntries = jarFile.entries();
646 while ( jarEntries.hasMoreElements() ) {
647 ZipEntry ze = (ZipEntry) jarEntries.nextElement();
648 if ( ze.getName().endsWith( ".hbm.xml" ) ) {
649 log.info( "Found mapping document in jar: " + ze.getName() );
650 try {
651 addInputStream( jarFile.getInputStream( ze ) );
652 }
653 catch (Exception e) {
654 throw new InvalidMappingException(
655 "Could not read mapping documents from jar: " + jar.getName(),
656 "jar",
657 jar.getName(),
658 e
659 );
660 }
661 }
662 }
663 }
664 finally {
665 try {
666 if ( jarFile != null ) {
667 jarFile.close();
668 }
669 }
670 catch (IOException ioe) {
671 log.error("could not close jar", ioe);
672 }
673 }
674
675 return this;
676 }
677
678 /**
679 * Read all mapping documents from a directory tree.
680 * <p/>
681 * Assumes that any file named <tt>*.hbm.xml</tt> is a mapping document.
682 *
683 * @param dir The directory
684 * @return this (for method chaining purposes)
685 * @throws MappingException Indicates problems reading the jar file or
686 * processing the contained mapping documents.
687 */
688 public Configuration addDirectory(File dir) throws MappingException {
689 File[] files = dir.listFiles();
690 for ( int i = 0; i < files.length ; i++ ) {
691 if ( files[i].isDirectory() ) {
692 addDirectory( files[i] );
693 }
694 else if ( files[i].getName().endsWith( ".hbm.xml" ) ) {
695 addFile( files[i] );
696 }
697 }
698 return this;
699 }
700
701 protected void add(org.dom4j.Document doc) throws MappingException {
702 HbmBinder.bindRoot( doc, createMappings(), CollectionHelper.EMPTY_MAP );
703 }
704
705 /**
706 * Create a new <tt>Mappings</tt> to add class and collection
707 * mappings to.
708 */
709 public Mappings createMappings() {
710 return new Mappings(
711 classes,
712 collections,
713 tables,
714 namedQueries,
715 namedSqlQueries,
716 sqlResultSetMappings,
717 imports,
718 secondPasses,
719 propertyReferences,
720 namingStrategy,
721 typeDefs,
722 filterDefinitions,
723 extendsQueue,
724 auxiliaryDatabaseObjects,
725 tableNameBinding,
726 columnNameBindingPerTable
727 );
728 }
729
730
731 private Iterator iterateGenerators(Dialect dialect) throws MappingException {
732
733 TreeMap generators = new TreeMap();
734 String defaultCatalog = properties.getProperty( Environment.DEFAULT_CATALOG );
735 String defaultSchema = properties.getProperty( Environment.DEFAULT_SCHEMA );
736
737 Iterator iter = classes.values().iterator();
738 while ( iter.hasNext() ) {
739 PersistentClass pc = (PersistentClass) iter.next();
740
741 if ( !pc.isInherited() ) {
742
743 IdentifierGenerator ig = pc.getIdentifier()
744 .createIdentifierGenerator(
745 dialect,
746 defaultCatalog,
747 defaultSchema,
748 (RootClass) pc
749 );
750
751 if ( ig instanceof PersistentIdentifierGenerator ) {
752 generators.put( ( (PersistentIdentifierGenerator) ig ).generatorKey(), ig );
753 }
754
755 }
756 }
757
758 iter = collections.values().iterator();
759 while ( iter.hasNext() ) {
760 Collection collection = (Collection) iter.next();
761
762 if ( collection.isIdentified() ) {
763
764 IdentifierGenerator ig = ( (IdentifierCollection) collection ).getIdentifier()
765 .createIdentifierGenerator(
766 dialect,
767 defaultCatalog,
768 defaultSchema,
769 null
770 );
771
772 if ( ig instanceof PersistentIdentifierGenerator ) {
773 generators.put( ( (PersistentIdentifierGenerator) ig ).generatorKey(), ig );
774 }
775
776 }
777 }
778
779 return generators.values().iterator();
780 }
781
782 /**
783 * Generate DDL for dropping tables
784 *
785 * @see org.hibernate.tool.hbm2ddl.SchemaExport
786 */
787 public String[] generateDropSchemaScript(Dialect dialect) throws HibernateException {
788
789 secondPassCompile();
790
791 String defaultCatalog = properties.getProperty( Environment.DEFAULT_CATALOG );
792 String defaultSchema = properties.getProperty( Environment.DEFAULT_SCHEMA );
793
794 ArrayList script = new ArrayList( 50 );
795
796 // drop them in reverse order in case db needs it done that way...
797 ListIterator itr = auxiliaryDatabaseObjects.listIterator( auxiliaryDatabaseObjects.size() );
798 while ( itr.hasPrevious() ) {
799 AuxiliaryDatabaseObject object = (AuxiliaryDatabaseObject) itr.previous();
800 if ( object.appliesToDialect( dialect ) ) {
801 script.add( object.sqlDropString( dialect, defaultCatalog, defaultSchema ) );
802 }
803 }
804
805 if ( dialect.dropConstraints() ) {
806 Iterator iter = getTableMappings();
807 while ( iter.hasNext() ) {
808 Table table = (Table) iter.next();
809 if ( table.isPhysicalTable() ) {
810 Iterator subIter = table.getForeignKeyIterator();
811 while ( subIter.hasNext() ) {
812 ForeignKey fk = (ForeignKey) subIter.next();
813 if ( fk.isPhysicalConstraint() ) {
814 script.add(
815 fk.sqlDropString(
816 dialect,
817 defaultCatalog,
818 defaultSchema
819 )
820 );
821 }
822 }
823 }
824 }
825 }
826
827
828 Iterator iter = getTableMappings();
829 while ( iter.hasNext() ) {
830
831 Table table = (Table) iter.next();
832 if ( table.isPhysicalTable() ) {
833
834 /*Iterator subIter = table.getIndexIterator();
835 while ( subIter.hasNext() ) {
836 Index index = (Index) subIter.next();
837 if ( !index.isForeignKey() || !dialect.hasImplicitIndexForForeignKey() ) {
838 script.add( index.sqlDropString(dialect) );
839 }
840 }*/
841
842 script.add(
843 table.sqlDropString(
844 dialect,
845 defaultCatalog,
846 defaultSchema
847 )
848 );
849
850 }
851
852 }
853
854 iter = iterateGenerators( dialect );
855 while ( iter.hasNext() ) {
856 String[] lines = ( (PersistentIdentifierGenerator) iter.next() ).sqlDropStrings( dialect );
857 for ( int i = 0; i < lines.length ; i++ ) {
858 script.add( lines[i] );
859 }
860 }
861
862 return ArrayHelper.toStringArray( script );
863 }
864
865 /**
866 * Generate DDL for creating tables
867 *
868 * @see org.hibernate.tool.hbm2ddl.SchemaExport
869 */
870 public String[] generateSchemaCreationScript(Dialect dialect) throws HibernateException {
871 secondPassCompile();
872
873 ArrayList script = new ArrayList( 50 );
874 String defaultCatalog = properties.getProperty( Environment.DEFAULT_CATALOG );
875 String defaultSchema = properties.getProperty( Environment.DEFAULT_SCHEMA );
876
877 Iterator iter = getTableMappings();
878 while ( iter.hasNext() ) {
879 Table table = (Table) iter.next();
880 if ( table.isPhysicalTable() ) {
881 script.add(
882 table.sqlCreateString(
883 dialect,
884 mapping,
885 defaultCatalog,
886 defaultSchema
887 )
888 );
889 Iterator comments = table.sqlCommentStrings( dialect, defaultCatalog, defaultSchema );
890 while ( comments.hasNext() ) {
891 script.add( comments.next() );
892 }
893 }
894 }
895
896 iter = getTableMappings();
897 while ( iter.hasNext() ) {
898 Table table = (Table) iter.next();
899 if ( table.isPhysicalTable() ) {
900
901 if ( !dialect.supportsUniqueConstraintInCreateAlterTable() ) {
902 Iterator subIter = table.getUniqueKeyIterator();
903 while ( subIter.hasNext() ) {
904 UniqueKey uk = (UniqueKey) subIter.next();
905 String constraintString = uk.sqlCreateString( dialect, mapping, defaultCatalog, defaultSchema );
906 if (constraintString != null) script.add( constraintString );
907 }
908 }
909
910
911 Iterator subIter = table.getIndexIterator();
912 while ( subIter.hasNext() ) {
913 Index index = (Index) subIter.next();
914 script.add(
915 index.sqlCreateString(
916 dialect,
917 mapping,
918 defaultCatalog,
919 defaultSchema
920 )
921 );
922 }
923
924 if ( dialect.hasAlterTable() ) {
925 subIter = table.getForeignKeyIterator();
926 while ( subIter.hasNext() ) {
927 ForeignKey fk = (ForeignKey) subIter.next();
928 if ( fk.isPhysicalConstraint() ) {
929 script.add(
930 fk.sqlCreateString(
931 dialect, mapping,
932 defaultCatalog,
933 defaultSchema
934 )
935 );
936 }
937 }
938 }
939
940 }
941 }
942
943 iter = iterateGenerators( dialect );
944 while ( iter.hasNext() ) {
945 String[] lines = ( (PersistentIdentifierGenerator) iter.next() ).sqlCreateStrings( dialect );
946 for ( int i = 0; i < lines.length ; i++ ) {
947 script.add( lines[i] );
948 }
949 }
950
951 Iterator itr = auxiliaryDatabaseObjects.iterator();
952 while ( itr.hasNext() ) {
953 AuxiliaryDatabaseObject object = (AuxiliaryDatabaseObject) itr.next();
954 if ( object.appliesToDialect( dialect ) ) {
955 script.add( object.sqlCreateString( dialect, mapping, defaultCatalog, defaultSchema ) );
956 }
957 }
958
959 return ArrayHelper.toStringArray( script );
960 }
961
962 /**
963 * Generate DDL for altering tables
964 *
965 * @see org.hibernate.tool.hbm2ddl.SchemaUpdate
966 */
967 public String[] generateSchemaUpdateScript(Dialect dialect, DatabaseMetadata databaseMetadata)
968 throws HibernateException {
969 secondPassCompile();
970
971 String defaultCatalog = properties.getProperty( Environment.DEFAULT_CATALOG );
972 String defaultSchema = properties.getProperty( Environment.DEFAULT_SCHEMA );
973
974 ArrayList script = new ArrayList( 50 );
975
976 Iterator iter = getTableMappings();
977 while ( iter.hasNext() ) {
978 Table table = (Table) iter.next();
979 if ( table.isPhysicalTable() ) {
980
981 TableMetadata tableInfo = databaseMetadata.getTableMetadata(
982 table.getName(),
983 ( table.getSchema() == null ) ? defaultSchema : table.getSchema(),
984 ( table.getCatalog() == null ) ? defaultCatalog : table.getCatalog(),
985 table.isQuoted()
986
987 );
988 if ( tableInfo == null ) {
989 script.add(
990 table.sqlCreateString(
991 dialect,
992 mapping,
993 defaultCatalog,
994 defaultSchema
995 )
996 );
997 }
998 else {
999 Iterator subiter = table.sqlAlterStrings(
1000 dialect,
1001 mapping,
1002 tableInfo,
1003 defaultCatalog,
1004 defaultSchema
1005 );
1006 while ( subiter.hasNext() ) {
1007 script.add( subiter.next() );
1008 }
1009 }
1010
1011 Iterator comments = table.sqlCommentStrings( dialect, defaultCatalog, defaultSchema );
1012 while ( comments.hasNext() ) {
1013 script.add( comments.next() );
1014 }
1015
1016 }
1017 }
1018
1019 iter = getTableMappings();
1020 while ( iter.hasNext() ) {
1021 Table table = (Table) iter.next();
1022 if ( table.isPhysicalTable() ) {
1023
1024 TableMetadata tableInfo = databaseMetadata.getTableMetadata(
1025 table.getName(),
1026 table.getSchema(),
1027 table.getCatalog(),
1028 table.isQuoted()
1029 );
1030
1031 if ( dialect.hasAlterTable() ) {
1032 Iterator subIter = table.getForeignKeyIterator();
1033 while ( subIter.hasNext() ) {
1034 ForeignKey fk = (ForeignKey) subIter.next();
1035 if ( fk.isPhysicalConstraint() ) {
1036 boolean create = tableInfo == null || (
1037 tableInfo.getForeignKeyMetadata( fk.getName() ) == null && (
1038 //Icky workaround for MySQL bug:
1039 !( dialect instanceof MySQLDialect ) ||
1040 tableInfo.getIndexMetadata( fk.getName() ) == null
1041 )
1042 );
1043 if ( create ) {
1044 script.add(
1045 fk.sqlCreateString(
1046 dialect,
1047 mapping,
1048 defaultCatalog,
1049 defaultSchema
1050 )
1051 );
1052 }
1053 }
1054 }
1055 }
1056
1057 }
1058
1059 /*//broken, 'cos we don't generate these with names in SchemaExport
1060 subIter = table.getIndexIterator();
1061 while ( subIter.hasNext() ) {
1062 Index index = (Index) subIter.next();
1063 if ( !index.isForeignKey() || !dialect.hasImplicitIndexForForeignKey() ) {
1064 if ( tableInfo==null || tableInfo.getIndexMetadata( index.getFilterName() ) == null ) {
1065 script.add( index.sqlCreateString(dialect, mapping) );
1066 }
1067 }
1068 }
1069 //broken, 'cos we don't generate these with names in SchemaExport
1070 subIter = table.getUniqueKeyIterator();
1071 while ( subIter.hasNext() ) {
1072 UniqueKey uk = (UniqueKey) subIter.next();
1073 if ( tableInfo==null || tableInfo.getIndexMetadata( uk.getFilterName() ) == null ) {
1074 script.add( uk.sqlCreateString(dialect, mapping) );
1075 }
1076 }*/
1077 }
1078
1079 iter = iterateGenerators( dialect );
1080 while ( iter.hasNext() ) {
1081 PersistentIdentifierGenerator generator = (PersistentIdentifierGenerator) iter.next();
1082 Object key = generator.generatorKey();
1083 if ( !databaseMetadata.isSequence( key ) && !databaseMetadata.isTable( key ) ) {
1084 String[] lines = generator.sqlCreateStrings( dialect );
1085 for ( int i = 0; i < lines.length ; i++ ) {
1086 script.add( lines[i] );
1087 }
1088 }
1089 }
1090
1091 return ArrayHelper.toStringArray( script );
1092 }
1093
1094 public void validateSchema(Dialect dialect, DatabaseMetadata databaseMetadata)
1095 throws HibernateException {
1096 secondPassCompile();
1097
1098 String defaultCatalog = properties.getProperty( Environment.DEFAULT_CATALOG );
1099 String defaultSchema = properties.getProperty( Environment.DEFAULT_SCHEMA );
1100
1101 Iterator iter = getTableMappings();
1102 while ( iter.hasNext() ) {
1103 Table table = (Table) iter.next();
1104 if ( table.isPhysicalTable() ) {
1105
1106
1107 TableMetadata tableInfo = databaseMetadata.getTableMetadata(
1108 table.getName(),
1109 ( table.getSchema() == null ) ? defaultSchema : table.getSchema(),
1110 ( table.getCatalog() == null ) ? defaultCatalog : table.getCatalog(),
1111 table.isQuoted());
1112 if ( tableInfo == null ) {
1113 throw new HibernateException( "Missing table: " + table.getName() );
1114 }
1115 else {
1116 table.validateColumns( dialect, mapping, tableInfo );
1117 }
1118
1119 }
1120 }
1121
1122 iter = iterateGenerators( dialect );
1123 while ( iter.hasNext() ) {
1124 PersistentIdentifierGenerator generator = (PersistentIdentifierGenerator) iter.next();
1125 Object key = generator.generatorKey();
1126 if ( !databaseMetadata.isSequence( key ) && !databaseMetadata.isTable( key ) ) {
1127 throw new HibernateException( "Missing sequence or table: " + key );
1128 }
1129 }
1130 }
1131
1132 private void validate() throws MappingException {
1133 Iterator iter = classes.values().iterator();
1134 while ( iter.hasNext() ) {
1135 ( (PersistentClass) iter.next() ).validate( mapping );
1136 }
1137 iter = collections.values().iterator();
1138 while ( iter.hasNext() ) {
1139 ( (Collection) iter.next() ).validate( mapping );
1140 }
1141 }
1142
1143 /**
1144 * Call this to ensure the mappings are fully compiled/built. Usefull to ensure getting
1145 * access to all information in the metamodel when calling e.g. getClassMappings().
1146 */
1147 public void buildMappings() {
1148 secondPassCompile();
1149 }
1150
1151 // This method may be called many times!!
1152 protected void secondPassCompile() throws MappingException {
1153 log.debug( "processing extends queue" );
1154
1155 processExtendsQueue();
1156
1157 log.debug( "processing collection mappings" );
1158
1159 Iterator iter = secondPasses.iterator();
1160 while ( iter.hasNext() ) {
1161 SecondPass sp = (SecondPass) iter.next();
1162 if ( ! (sp instanceof QuerySecondPass) ) {
1163 sp.doSecondPass( classes );
1164 iter.remove();
1165 }
1166 }
1167
1168 log.debug( "processing native query and ResultSetMapping mappings" );
1169 iter = secondPasses.iterator();
1170 while ( iter.hasNext() ) {
1171 SecondPass sp = (SecondPass) iter.next();
1172 sp.doSecondPass( classes );
1173 iter.remove();
1174 }
1175
1176 log.debug( "processing association property references" );
1177
1178 iter = propertyReferences.iterator();
1179 while ( iter.hasNext() ) {
1180 Mappings.PropertyReference upr = (Mappings.PropertyReference) iter.next();
1181
1182 PersistentClass clazz = getClassMapping( upr.referencedClass );
1183 if ( clazz == null ) {
1184 throw new MappingException(
1185 "property-ref to unmapped class: " +
1186 upr.referencedClass
1187 );
1188 }
1189
1190 Property prop = clazz.getReferencedProperty( upr.propertyName );
1191 if ( upr.unique ) {
1192 ( (SimpleValue) prop.getValue() ).setAlternateUniqueKey( true );
1193 }
1194 }
1195
1196 //TODO: Somehow add the newly created foreign keys to the internal collection
1197
1198 log.debug( "processing foreign key constraints" );
1199
1200 iter = getTableMappings();
1201 Set done = new HashSet();
1202 while ( iter.hasNext() ) {
1203 secondPassCompileForeignKeys( (Table) iter.next(), done );
1204 }
1205
1206 }
1207
1208 /**
1209 * Try to empty the extends queue.
1210 */
1211 private void processExtendsQueue() {
1212 // todo : would love to have this work on a notification basis
1213 // where the successful binding of an entity/subclass would
1214 // emit a notification which the extendsQueue entries could
1215 // react to...
1216 org.dom4j.Document document = findPossibleExtends();
1217 while ( document != null ) {
1218 add( document );
1219 document = findPossibleExtends();
1220 }
1221
1222 if ( extendsQueue.size() > 0 ) {
1223 // Iterator iterator = extendsQueue.iterator();
1224 Iterator iterator = extendsQueue.keySet().iterator();
1225 StringBuffer buf = new StringBuffer( "Following superclasses referenced in extends not found: " );
1226 while ( iterator.hasNext() ) {
1227 final ExtendsQueueEntry entry = ( ExtendsQueueEntry ) iterator.next();
1228 buf.append( entry.getExplicitName() );
1229 if ( entry.getMappingPackage() != null ) {
1230 buf.append( "[" ).append( entry.getMappingPackage() ).append( "]" );
1231 }
1232 if ( iterator.hasNext() ) {
1233 buf.append( "," );
1234 }
1235 }
1236 throw new MappingException( buf.toString() );
1237 }
1238 }
1239
1240 /**
1241 * Find the first possible element in the queue of extends.
1242 */
1243 protected org.dom4j.Document findPossibleExtends() {
1244 // Iterator iter = extendsQueue.iterator();
1245 Iterator iter = extendsQueue.keySet().iterator();
1246 while ( iter.hasNext() ) {
1247 final ExtendsQueueEntry entry = ( ExtendsQueueEntry ) iter.next();
1248 if ( getClassMapping( entry.getExplicitName() ) != null ) {
1249 // found
1250 iter.remove();
1251 return entry.getDocument();
1252 }
1253 else if ( getClassMapping( HbmBinder.getClassName( entry.getExplicitName(), entry.getMappingPackage() ) ) != null ) {
1254 // found
1255 iter.remove();
1256 return entry.getDocument();
1257 }
1258 }
1259 return null;
1260 }
1261
1262 protected void secondPassCompileForeignKeys(Table table, Set done) throws MappingException {
1263
1264 table.createForeignKeys();
1265
1266 Iterator iter = table.getForeignKeyIterator();
1267 while ( iter.hasNext() ) {
1268
1269 ForeignKey fk = (ForeignKey) iter.next();
1270 if ( !done.contains( fk ) ) {
1271 done.add( fk );
1272 final String referencedEntityName = fk.getReferencedEntityName();
1273 if ( referencedEntityName == null ) {
1274 throw new MappingException(
1275 "An association from the table " +
1276 fk.getTable().getName() +
1277 " does not specify the referenced entity"
1278 );
1279 }
1280 if ( log.isDebugEnabled() ) {
1281 log.debug( "resolving reference to class: " + referencedEntityName );
1282 }
1283 PersistentClass referencedClass = (PersistentClass) classes.get( referencedEntityName );
1284 if ( referencedClass == null ) {
1285 throw new MappingException(
1286 "An association from the table " +
1287 fk.getTable().getName() +
1288 " refers to an unmapped class: " +
1289 referencedEntityName
1290 );
1291 }
1292 if ( referencedClass.isJoinedSubclass() ) {
1293 secondPassCompileForeignKeys( referencedClass.getSuperclass().getTable(), done );
1294 }
1295 fk.setReferencedTable( referencedClass.getTable() );
1296 fk.alignColumns();
1297 }
1298 }
1299 }
1300
1301 /**
1302 * Get the named queries
1303 */
1304 public Map getNamedQueries() {
1305 return namedQueries;
1306 }
1307
1308 /**
1309 * Instantiate a new <tt>SessionFactory</tt>, using the properties and
1310 * mappings in this configuration. The <tt>SessionFactory</tt> will be
1311 * immutable, so changes made to the <tt>Configuration</tt> after
1312 * building the <tt>SessionFactory</tt> will not affect it.
1313 *
1314 * @return a new factory for <tt>Session</tt>s
1315 * @see org.hibernate.SessionFactory
1316 */
1317 public SessionFactory buildSessionFactory() throws HibernateException {
1318 log.debug( "Preparing to build session factory with filters : " + filterDefinitions );
1319 secondPassCompile();
1320 validate();
1321 Environment.verifyProperties( properties );
1322 Properties copy = new Properties();
1323 copy.putAll( properties );
1324 PropertiesHelper.resolvePlaceHolders( copy );
1325 Settings settings = buildSettings( copy );
1326
1327 return new SessionFactoryImpl(
1328 this,
1329 mapping,
1330 settings,
1331 getInitializedEventListeners(),
1332 sessionFactoryObserver
1333 );
1334 }
1335
1336 private EventListeners getInitializedEventListeners() {
1337 EventListeners result = (EventListeners) eventListeners.shallowCopy();
1338 result.initializeListeners( this );
1339 return result;
1340 }
1341
1342 /**
1343 * Return the configured <tt>Interceptor</tt>
1344 */
1345 public Interceptor getInterceptor() {
1346 return interceptor;
1347 }
1348
1349 /**
1350 * Get all properties
1351 */
1352 public Properties getProperties() {
1353 return properties;
1354 }
1355
1356 /**
1357 * Configure an <tt>Interceptor</tt>
1358 */
1359 public Configuration setInterceptor(Interceptor interceptor) {
1360 this.interceptor = interceptor;
1361 return this;
1362 }
1363
1364 /**
1365 * Specify a completely new set of properties
1366 */
1367 public Configuration setProperties(Properties properties) {
1368 this.properties = properties;
1369 return this;
1370 }
1371
1372 /**
1373 * Set the given properties
1374 */
1375 public Configuration addProperties(Properties extraProperties) {
1376 this.properties.putAll( extraProperties );
1377 return this;
1378 }
1379
1380 /**
1381 * Adds the incoming properties to the internap properties structure,
1382 * as long as the internal structure does not already contain an
1383 * entry for the given key.
1384 *
1385 * @param properties
1386 * @return this
1387 */
1388 public Configuration mergeProperties(Properties properties) {
1389 Iterator itr = properties.entrySet().iterator();
1390 while ( itr.hasNext() ) {
1391 final Map.Entry entry = ( Map.Entry ) itr.next();
1392 if ( this.properties.containsKey( entry.getKey() ) ) {
1393 continue;
1394 }
1395 this.properties.setProperty( ( String ) entry.getKey(), ( String ) entry.getValue() );
1396 }
1397 return this;
1398 }
1399
1400 /**
1401 * Set a property
1402 */
1403 public Configuration setProperty(String propertyName, String value) {
1404 properties.setProperty( propertyName, value );
1405 return this;
1406 }
1407
1408 /**
1409 * Get a property
1410 */
1411 public String getProperty(String propertyName) {
1412 return properties.getProperty( propertyName );
1413 }
1414
1415 private void addProperties(Element parent) {
1416 Iterator iter = parent.elementIterator( "property" );
1417 while ( iter.hasNext() ) {
1418 Element node = (Element) iter.next();
1419 String name = node.attributeValue( "name" );
1420 String value = node.getText().trim();
1421 log.debug( name + "=" + value );
1422 properties.setProperty( name, value );
1423 if ( !name.startsWith( "hibernate" ) ) {
1424 properties.setProperty( "hibernate." + name, value );
1425 }
1426 }
1427 Environment.verifyProperties( properties );
1428 }
1429
1430 /**
1431 * Get the configuration file as an <tt>InputStream</tt>. Might be overridden
1432 * by subclasses to allow the configuration to be located by some arbitrary
1433 * mechanism.
1434 */
1435 protected InputStream getConfigurationInputStream(String resource) throws HibernateException {
1436
1437 log.info( "Configuration resource: " + resource );
1438
1439 return ConfigHelper.getResourceAsStream( resource );
1440
1441 }
1442
1443 /**
1444 * Use the mappings and properties specified in an application
1445 * resource named <tt>hibernate.cfg.xml</tt>.
1446 */
1447 public Configuration configure() throws HibernateException {
1448 configure( "/hibernate.cfg.xml" );
1449 return this;
1450 }
1451
1452 /**
1453 * Use the mappings and properties specified in the given application
1454 * resource. The format of the resource is defined in
1455 * <tt>hibernate-configuration-3.0.dtd</tt>.
1456 * <p/>
1457 * The resource is found via <tt>getConfigurationInputStream(resource)</tt>.
1458 */
1459 public Configuration configure(String resource) throws HibernateException {
1460 log.info( "configuring from resource: " + resource );
1461 InputStream stream = getConfigurationInputStream( resource );
1462 return doConfigure( stream, resource );
1463 }
1464
1465 /**
1466 * Use the mappings and properties specified in the given document.
1467 * The format of the document is defined in
1468 * <tt>hibernate-configuration-3.0.dtd</tt>.
1469 *
1470 * @param url URL from which you wish to load the configuration
1471 * @return A configuration configured via the file
1472 * @throws HibernateException
1473 */
1474 public Configuration configure(URL url) throws HibernateException {
1475 log.info( "configuring from url: " + url.toString() );
1476 try {
1477 return doConfigure( url.openStream(), url.toString() );
1478 }
1479 catch (IOException ioe) {
1480 throw new HibernateException( "could not configure from URL: " + url, ioe );
1481 }
1482 }
1483
1484 /**
1485 * Use the mappings and properties specified in the given application
1486 * file. The format of the file is defined in
1487 * <tt>hibernate-configuration-3.0.dtd</tt>.
1488 *
1489 * @param configFile <tt>File</tt> from which you wish to load the configuration
1490 * @return A configuration configured via the file
1491 * @throws HibernateException
1492 */
1493 public Configuration configure(File configFile) throws HibernateException {
1494 log.info( "configuring from file: " + configFile.getName() );
1495 try {
1496 return doConfigure( new FileInputStream( configFile ), configFile.toString() );
1497 }
1498 catch (FileNotFoundException fnfe) {
1499 throw new HibernateException( "could not find file: " + configFile, fnfe );
1500 }
1501 }
1502
1503 /**
1504 * Use the mappings and properties specified in the given application
1505 * resource. The format of the resource is defined in
1506 * <tt>hibernate-configuration-3.0.dtd</tt>.
1507 *
1508 * @param stream Inputstream to be read from
1509 * @param resourceName The name to use in warning/error messages
1510 * @return A configuration configured via the stream
1511 * @throws HibernateException
1512 */
1513 protected Configuration doConfigure(InputStream stream, String resourceName) throws HibernateException {
1514
1515 org.dom4j.Document doc;
1516 try {
1517 List errors = new ArrayList();
1518 doc = xmlHelper.createSAXReader( resourceName, errors, entityResolver )
1519 .read( new InputSource( stream ) );
1520 if ( errors.size() != 0 ) {
1521 throw new MappingException(
1522 "invalid configuration",
1523 (Throwable) errors.get( 0 )
1524 );
1525 }
1526 }
1527 catch (DocumentException e) {
1528 throw new HibernateException(
1529 "Could not parse configuration: " + resourceName,
1530 e
1531 );
1532 }
1533 finally {
1534 try {
1535 stream.close();
1536 }
1537 catch (IOException ioe) {
1538 log.warn( "could not close input stream for: " + resourceName, ioe );
1539 }
1540 }
1541
1542 return doConfigure( doc );
1543
1544 }
1545
1546 /**
1547 * Use the mappings and properties specified in the given XML document.
1548 * The format of the file is defined in
1549 * <tt>hibernate-configuration-3.0.dtd</tt>.
1550 *
1551 * @param document an XML document from which you wish to load the configuration
1552 * @return A configuration configured via the <tt>Document</tt>
1553 * @throws HibernateException if there is problem in accessing the file.
1554 */
1555 public Configuration configure(Document document) throws HibernateException {
1556 log.info( "configuring from XML document" );
1557 return doConfigure( xmlHelper.createDOMReader().read( document ) );
1558 }
1559
1560 protected Configuration doConfigure(org.dom4j.Document doc) throws HibernateException {
1561
1562 Element sfNode = doc.getRootElement().element( "session-factory" );
1563 String name = sfNode.attributeValue( "name" );
1564 if ( name != null ) {
1565 properties.setProperty( Environment.SESSION_FACTORY_NAME, name );
1566 }
1567 addProperties( sfNode );
1568 parseSessionFactory( sfNode, name );
1569
1570 Element secNode = doc.getRootElement().element( "security" );
1571 if ( secNode != null ) {
1572 parseSecurity( secNode );
1573 }
1574
1575 log.info( "Configured SessionFactory: " + name );
1576 log.debug( "properties: " + properties );
1577
1578 return this;
1579
1580 }
1581
1582
1583 private void parseSessionFactory(Element sfNode, String name) {
1584 Iterator elements = sfNode.elementIterator();
1585 while ( elements.hasNext() ) {
1586 Element subelement = (Element) elements.next();
1587 String subelementName = subelement.getName();
1588 if ( "mapping".equals( subelementName ) ) {
1589 parseMappingElement( subelement, name );
1590 }
1591 else if ( "class-cache".equals( subelementName ) ) {
1592 String className = subelement.attributeValue( "class" );
1593 Attribute regionNode = subelement.attribute( "region" );
1594 final String region = ( regionNode == null ) ? className : regionNode.getValue();
1595 boolean includeLazy = !"non-lazy".equals( subelement.attributeValue( "include" ) );
1596 setCacheConcurrencyStrategy( className, subelement.attributeValue( "usage" ), region, includeLazy );
1597 }
1598 else if ( "collection-cache".equals( subelementName ) ) {
1599 String role = subelement.attributeValue( "collection" );
1600 Attribute regionNode = subelement.attribute( "region" );
1601 final String region = ( regionNode == null ) ? role : regionNode.getValue();
1602 setCollectionCacheConcurrencyStrategy( role, subelement.attributeValue( "usage" ), region );
1603 }
1604 else if ( "listener".equals( subelementName ) ) {
1605 parseListener( subelement );
1606 }
1607 else if ( "event".equals( subelementName ) ) {
1608 parseEvent( subelement );
1609 }
1610 }
1611 }
1612
1613 protected void parseMappingElement(Element subelement, String name) {
1614 Attribute rsrc = subelement.attribute( "resource" );
1615 Attribute file = subelement.attribute( "file" );
1616 Attribute jar = subelement.attribute( "jar" );
1617 Attribute pkg = subelement.attribute( "package" );
1618 Attribute clazz = subelement.attribute( "class" );
1619 if ( rsrc != null ) {
1620 log.debug( name + "<-" + rsrc );
1621 addResource( rsrc.getValue() );
1622 }
1623 else if ( jar != null ) {
1624 log.debug( name + "<-" + jar );
1625 addJar( new File( jar.getValue() ) );
1626 }
1627 else if ( pkg != null ) {
1628 throw new MappingException(
1629 "An AnnotationConfiguration instance is required to use <mapping package=\"" +
1630 pkg.getValue() + "\"/>"
1631 );
1632 }
1633 else if ( clazz != null ) {
1634 throw new MappingException(
1635 "An AnnotationConfiguration instance is required to use <mapping class=\"" +
1636 clazz.getValue() + "\"/>"
1637 );
1638 }
1639 else {
1640 if ( file == null ) {
1641 throw new MappingException(
1642 "<mapping> element in configuration specifies no attributes"
1643 );
1644 }
1645 log.debug( name + "<-" + file );
1646 addFile( file.getValue() );
1647 }
1648 }
1649
1650 private void parseSecurity(Element secNode) {
1651 String contextId = secNode.attributeValue( "context" );
1652 setProperty(Environment.JACC_CONTEXTID, contextId);
1653 log.info( "JACC contextID: " + contextId );
1654 JACCConfiguration jcfg = new JACCConfiguration( contextId );
1655 Iterator grantElements = secNode.elementIterator();
1656 while ( grantElements.hasNext() ) {
1657 Element grantElement = (Element) grantElements.next();
1658 String elementName = grantElement.getName();
1659 if ( "grant".equals( elementName ) ) {
1660 jcfg.addPermission(
1661 grantElement.attributeValue( "role" ),
1662 grantElement.attributeValue( "entity-name" ),
1663 grantElement.attributeValue( "actions" )
1664 );
1665 }
1666 }
1667 }
1668
1669 private void parseEvent(Element element) {
1670 String type = element.attributeValue( "type" );
1671 List listeners = element.elements();
1672 String[] listenerClasses = new String[ listeners.size() ];
1673 for ( int i = 0; i < listeners.size() ; i++ ) {
1674 listenerClasses[i] = ( (Element) listeners.get( i ) ).attributeValue( "class" );
1675 }
1676 log.debug( "Event listeners: " + type + "=" + StringHelper.toString( listenerClasses ) );
1677 setListeners( type, listenerClasses );
1678 }
1679
1680 private void parseListener(Element element) {
1681 String type = element.attributeValue( "type" );
1682 if ( type == null ) {
1683 throw new MappingException( "No type specified for listener" );
1684 }
1685 String impl = element.attributeValue( "class" );
1686 log.debug( "Event listener: " + type + "=" + impl );
1687 setListeners( type, new String[]{impl} );
1688 }
1689
1690 public void setListener(String type, String listener) {
1691 String[] listeners = null;
1692 if ( listener != null ) {
1693 listeners = (String[]) Array.newInstance( String.class, 1 );
1694 listeners[0] = listener;
1695 }
1696 setListeners( type, listeners );
1697 }
1698
1699 public void setListeners(String type, String[] listenerClasses) {
1700 Object[] listeners = null;
1701 if ( listenerClasses != null ) {
1702 listeners = (Object[]) Array.newInstance( eventListeners.getListenerClassFor(type), listenerClasses.length );
1703 for ( int i = 0; i < listeners.length ; i++ ) {
1704 try {
1705 listeners[i] = ReflectHelper.classForName( listenerClasses[i] ).newInstance();
1706 }
1707 catch (Exception e) {
1708 throw new MappingException(
1709 "Unable to instantiate specified event (" + type + ") listener class: " + listenerClasses[i],
1710 e
1711 );
1712 }
1713 }
1714 }
1715 setListeners( type, listeners );
1716 }
1717
1718 public void setListener(String type, Object listener) {
1719 Object[] listeners = null;
1720 if ( listener != null ) {
1721 listeners = (Object[]) Array.newInstance( eventListeners.getListenerClassFor(type), 1 );
1722 listeners[0] = listener;
1723 }
1724 setListeners( type, listeners );
1725 }
1726
1727 public void setListeners(String type, Object[] listeners) {
1728 if ( "auto-flush".equals( type ) ) {
1729 if ( listeners == null ) {
1730 eventListeners.setAutoFlushEventListeners( new AutoFlushEventListener[]{} );
1731 }
1732 else {
1733 eventListeners.setAutoFlushEventListeners( (AutoFlushEventListener[]) listeners );
1734 }
1735 }
1736 else if ( "merge".equals( type ) ) {
1737 if ( listeners == null ) {
1738 eventListeners.setMergeEventListeners( new MergeEventListener[]{} );
1739 }
1740 else {
1741 eventListeners.setMergeEventListeners( (MergeEventListener[]) listeners );
1742 }
1743 }
1744 else if ( "create".equals( type ) ) {
1745 if ( listeners == null ) {
1746 eventListeners.setPersistEventListeners( new PersistEventListener[]{} );
1747 }
1748 else {
1749 eventListeners.setPersistEventListeners( (PersistEventListener[]) listeners );
1750 }
1751 }
1752 else if ( "create-onflush".equals( type ) ) {
1753 if ( listeners == null ) {
1754 eventListeners.setPersistOnFlushEventListeners( new PersistEventListener[]{} );
1755 }
1756 else {
1757 eventListeners.setPersistOnFlushEventListeners( (PersistEventListener[]) listeners );
1758 }
1759 }
1760 else if ( "delete".equals( type ) ) {
1761 if ( listeners == null ) {
1762 eventListeners.setDeleteEventListeners( new DeleteEventListener[]{} );
1763 }
1764 else {
1765 eventListeners.setDeleteEventListeners( (DeleteEventListener[]) listeners );
1766 }
1767 }
1768 else if ( "dirty-check".equals( type ) ) {
1769 if ( listeners == null ) {
1770 eventListeners.setDirtyCheckEventListeners( new DirtyCheckEventListener[]{} );
1771 }
1772 else {
1773 eventListeners.setDirtyCheckEventListeners( (DirtyCheckEventListener[]) listeners );
1774 }
1775 }
1776 else if ( "evict".equals( type ) ) {
1777 if ( listeners == null ) {
1778 eventListeners.setEvictEventListeners( new EvictEventListener[]{} );
1779 }
1780 else {
1781 eventListeners.setEvictEventListeners( (EvictEventListener[]) listeners );
1782 }
1783 }
1784 else if ( "flush".equals( type ) ) {
1785 if ( listeners == null ) {
1786 eventListeners.setFlushEventListeners( new FlushEventListener[]{} );
1787 }
1788 else {
1789 eventListeners.setFlushEventListeners( (FlushEventListener[]) listeners );
1790 }
1791 }
1792 else if ( "flush-entity".equals( type ) ) {
1793 if ( listeners == null ) {
1794 eventListeners.setFlushEntityEventListeners( new FlushEntityEventListener[]{} );
1795 }
1796 else {
1797 eventListeners.setFlushEntityEventListeners( (FlushEntityEventListener[]) listeners );
1798 }
1799 }
1800 else if ( "load".equals( type ) ) {
1801 if ( listeners == null ) {
1802 eventListeners.setLoadEventListeners( new LoadEventListener[]{} );
1803 }
1804 else {
1805 eventListeners.setLoadEventListeners( (LoadEventListener[]) listeners );
1806 }
1807 }
1808 else if ( "load-collection".equals( type ) ) {
1809 if ( listeners == null ) {
1810 eventListeners.setInitializeCollectionEventListeners(
1811 new InitializeCollectionEventListener[]{}
1812 );
1813 }
1814 else {
1815 eventListeners.setInitializeCollectionEventListeners(
1816 (InitializeCollectionEventListener[]) listeners
1817 );
1818 }
1819 }
1820 else if ( "lock".equals( type ) ) {
1821 if ( listeners == null ) {
1822 eventListeners.setLockEventListeners( new LockEventListener[]{} );
1823 }
1824 else {
1825 eventListeners.setLockEventListeners( (LockEventListener[]) listeners );
1826 }
1827 }
1828 else if ( "refresh".equals( type ) ) {
1829 if ( listeners == null ) {
1830 eventListeners.setRefreshEventListeners( new RefreshEventListener[]{} );
1831 }
1832 else {
1833 eventListeners.setRefreshEventListeners( (RefreshEventListener[]) listeners );
1834 }
1835 }
1836 else if ( "replicate".equals( type ) ) {
1837 if ( listeners == null ) {
1838 eventListeners.setReplicateEventListeners( new ReplicateEventListener[]{} );
1839 }
1840 else {
1841 eventListeners.setReplicateEventListeners( (ReplicateEventListener[]) listeners );
1842 }
1843 }
1844 else if ( "save-update".equals( type ) ) {
1845 if ( listeners == null ) {
1846 eventListeners.setSaveOrUpdateEventListeners( new SaveOrUpdateEventListener[]{} );
1847 }
1848 else {
1849 eventListeners.setSaveOrUpdateEventListeners( (SaveOrUpdateEventListener[]) listeners );
1850 }
1851 }
1852 else if ( "save".equals( type ) ) {
1853 if ( listeners == null ) {
1854 eventListeners.setSaveEventListeners( new SaveOrUpdateEventListener[]{} );
1855 }
1856 else {
1857 eventListeners.setSaveEventListeners( (SaveOrUpdateEventListener[]) listeners );
1858 }
1859 }
1860 else if ( "update".equals( type ) ) {
1861 if ( listeners == null ) {
1862 eventListeners.setUpdateEventListeners( new SaveOrUpdateEventListener[]{} );
1863 }
1864 else {
1865 eventListeners.setUpdateEventListeners( (SaveOrUpdateEventListener[]) listeners );
1866 }
1867 }
1868 else if ( "pre-load".equals( type ) ) {
1869 if ( listeners == null ) {
1870 eventListeners.setPreLoadEventListeners( new PreLoadEventListener[]{} );
1871 }
1872 else {
1873 eventListeners.setPreLoadEventListeners( (PreLoadEventListener[]) listeners );
1874 }
1875 }
1876 else if ( "pre-update".equals( type ) ) {
1877 if ( listeners == null ) {
1878 eventListeners.setPreUpdateEventListeners( new PreUpdateEventListener[]{} );
1879 }
1880 else {
1881 eventListeners.setPreUpdateEventListeners( (PreUpdateEventListener[]) listeners );
1882 }
1883 }
1884 else if ( "pre-delete".equals( type ) ) {
1885 if ( listeners == null ) {
1886 eventListeners.setPreDeleteEventListeners( new PreDeleteEventListener[]{} );
1887 }
1888 else {
1889 eventListeners.setPreDeleteEventListeners( (PreDeleteEventListener[]) listeners );
1890 }
1891 }
1892 else if ( "pre-insert".equals( type ) ) {
1893 if ( listeners == null ) {
1894 eventListeners.setPreInsertEventListeners( new PreInsertEventListener[]{} );
1895 }
1896 else {
1897 eventListeners.setPreInsertEventListeners( (PreInsertEventListener[]) listeners );
1898 }
1899 }
1900 else if ( "pre-collection-recreate".equals( type ) ) {
1901 if ( listeners == null ) {
1902 eventListeners.setPreCollectionRecreateEventListeners( new PreCollectionRecreateEventListener[]{} );
1903 }
1904 else {
1905 eventListeners.setPreCollectionRecreateEventListeners( (PreCollectionRecreateEventListener[]) listeners );
1906 }
1907 }
1908 else if ( "pre-collection-remove".equals( type ) ) {
1909 if ( listeners == null ) {
1910 eventListeners.setPreCollectionRemoveEventListeners( new PreCollectionRemoveEventListener[]{} );
1911 }
1912 else {
1913 eventListeners.setPreCollectionRemoveEventListeners( ( PreCollectionRemoveEventListener[]) listeners );
1914 }
1915 }
1916 else if ( "pre-collection-update".equals( type ) ) {
1917 if ( listeners == null ) {
1918 eventListeners.setPreCollectionUpdateEventListeners( new PreCollectionUpdateEventListener[]{} );
1919 }
1920 else {
1921 eventListeners.setPreCollectionUpdateEventListeners( ( PreCollectionUpdateEventListener[]) listeners );
1922 }
1923 }
1924 else if ( "post-load".equals( type ) ) {
1925 if ( listeners == null ) {
1926 eventListeners.setPostLoadEventListeners( new PostLoadEventListener[]{} );
1927 }
1928 else {
1929 eventListeners.setPostLoadEventListeners( (PostLoadEventListener[]) listeners );
1930 }
1931 }
1932 else if ( "post-update".equals( type ) ) {
1933 if ( listeners == null ) {
1934 eventListeners.setPostUpdateEventListeners( new PostUpdateEventListener[]{} );
1935 }
1936 else {
1937 eventListeners.setPostUpdateEventListeners( (PostUpdateEventListener[]) listeners );
1938 }
1939 }
1940 else if ( "post-delete".equals( type ) ) {
1941 if ( listeners == null ) {
1942 eventListeners.setPostDeleteEventListeners( new PostDeleteEventListener[]{} );
1943 }
1944 else {
1945 eventListeners.setPostDeleteEventListeners( (PostDeleteEventListener[]) listeners );
1946 }
1947 }
1948 else if ( "post-insert".equals( type ) ) {
1949 if ( listeners == null ) {
1950 eventListeners.setPostInsertEventListeners( new PostInsertEventListener[]{} );
1951 }
1952 else {
1953 eventListeners.setPostInsertEventListeners( (PostInsertEventListener[]) listeners );
1954 }
1955 }
1956 else if ( "post-commit-update".equals( type ) ) {
1957 if ( listeners == null ) {
1958 eventListeners.setPostCommitUpdateEventListeners(
1959 new PostUpdateEventListener[]{}
1960 );
1961 }
1962 else {
1963 eventListeners.setPostCommitUpdateEventListeners( (PostUpdateEventListener[]) listeners );
1964 }
1965 }
1966 else if ( "post-commit-delete".equals( type ) ) {
1967 if ( listeners == null ) {
1968 eventListeners.setPostCommitDeleteEventListeners(
1969 new PostDeleteEventListener[]{}
1970 );
1971 }
1972 else {
1973 eventListeners.setPostCommitDeleteEventListeners( (PostDeleteEventListener[]) listeners );
1974 }
1975 }
1976 else if ( "post-commit-insert".equals( type ) ) {
1977 if ( listeners == null ) {
1978 eventListeners.setPostCommitInsertEventListeners(
1979 new PostInsertEventListener[]{}
1980 );
1981 }
1982 else {
1983 eventListeners.setPostCommitInsertEventListeners( (PostInsertEventListener[]) listeners );
1984 }
1985 }
1986 else if ( "post-collection-recreate".equals( type ) ) {
1987 if ( listeners == null ) {
1988 eventListeners.setPostCollectionRecreateEventListeners( new PostCollectionRecreateEventListener[]{} );
1989 }
1990 else {
1991 eventListeners.setPostCollectionRecreateEventListeners( (PostCollectionRecreateEventListener[]) listeners );
1992 }
1993 }
1994 else if ( "post-collection-remove".equals( type ) ) {
1995 if ( listeners == null ) {
1996 eventListeners.setPostCollectionRemoveEventListeners( new PostCollectionRemoveEventListener[]{} );
1997 }
1998 else {
1999 eventListeners.setPostCollectionRemoveEventListeners( ( PostCollectionRemoveEventListener[]) listeners );
2000 }
2001 }
2002 else if ( "post-collection-update".equals( type ) ) {
2003 if ( listeners == null ) {
2004 eventListeners.setPostCollectionUpdateEventListeners( new PostCollectionUpdateEventListener[]{} );
2005 }
2006 else {
2007 eventListeners.setPostCollectionUpdateEventListeners( ( PostCollectionUpdateEventListener[]) listeners );
2008 }
2009 }
2010 else {
2011 throw new MappingException("Unrecognized listener type [" + type + "]");
2012 }
2013 }
2014
2015 public EventListeners getEventListeners() {
2016 return eventListeners;
2017 }
2018
2019 RootClass getRootClassMapping(String clazz) throws MappingException {
2020 try {
2021 return (RootClass) getClassMapping( clazz );
2022 }
2023 catch (ClassCastException cce) {
2024 throw new MappingException( "You may only specify a cache for root <class> mappings" );
2025 }
2026 }
2027
2028 /**
2029 * Set up a cache for an entity class
2030 *
2031 * @param clazz
2032 * @param concurrencyStrategy
2033 * @return Configuration
2034 * @throws MappingException
2035 */
2036 public Configuration setCacheConcurrencyStrategy(String clazz, String concurrencyStrategy)
2037 throws MappingException {
2038 setCacheConcurrencyStrategy( clazz, concurrencyStrategy, clazz );
2039 return this;
2040 }
2041
2042 public void setCacheConcurrencyStrategy(String clazz, String concurrencyStrategy, String region)
2043 throws MappingException {
2044 setCacheConcurrencyStrategy( clazz, concurrencyStrategy, region, true );
2045 }
2046
2047 void setCacheConcurrencyStrategy(String clazz, String concurrencyStrategy, String region, boolean includeLazy)
2048 throws MappingException {
2049 RootClass rootClass = getRootClassMapping( clazz );
2050 if ( rootClass == null ) {
2051 throw new MappingException( "Cannot cache an unknown entity: " + clazz );
2052 }
2053 rootClass.setCacheConcurrencyStrategy( concurrencyStrategy );
2054 rootClass.setCacheRegionName( region );
2055 rootClass.setLazyPropertiesCacheable( includeLazy );
2056 }
2057
2058 /**
2059 * Set up a cache for a collection role
2060 *
2061 * @param collectionRole
2062 * @param concurrencyStrategy
2063 * @return Configuration
2064 * @throws MappingException
2065 */
2066 public Configuration setCollectionCacheConcurrencyStrategy(String collectionRole, String concurrencyStrategy)
2067 throws MappingException {
2068 setCollectionCacheConcurrencyStrategy( collectionRole, concurrencyStrategy, collectionRole );
2069 return this;
2070 }
2071
2072 public void setCollectionCacheConcurrencyStrategy(String collectionRole, String concurrencyStrategy, String region)
2073 throws MappingException {
2074 Collection collection = getCollectionMapping( collectionRole );
2075 if ( collection == null ) {
2076 throw new MappingException( "Cannot cache an unknown collection: " + collectionRole );
2077 }
2078 collection.setCacheConcurrencyStrategy( concurrencyStrategy );
2079 collection.setCacheRegionName( region );
2080 }
2081
2082 /**
2083 * Get the query language imports
2084 *
2085 * @return a mapping from "import" names to fully qualified class names
2086 */
2087 public Map getImports() {
2088 return imports;
2089 }
2090
2091 /**
2092 * Create an object-oriented view of the configuration properties
2093 */
2094 public Settings buildSettings() throws HibernateException {
2095 Properties clone = ( Properties ) properties.clone();
2096 PropertiesHelper.resolvePlaceHolders( clone );
2097 return settingsFactory.buildSettings( clone );
2098 }
2099
2100 public Settings buildSettings(Properties props) throws HibernateException {
2101 return settingsFactory.buildSettings( props );
2102 }
2103
2104 public Map getNamedSQLQueries() {
2105 return namedSqlQueries;
2106 }
2107
2108 public Map getSqlResultSetMappings() {
2109 return sqlResultSetMappings;
2110 }
2111
2112 /**
2113 * @return the NamingStrategy.
2114 */
2115 public NamingStrategy getNamingStrategy() {
2116 return namingStrategy;
2117 }
2118
2119 /**
2120 * Set a custom naming strategy
2121 *
2122 * @param namingStrategy the NamingStrategy to set
2123 */
2124 public Configuration setNamingStrategy(NamingStrategy namingStrategy) {
2125 this.namingStrategy = namingStrategy;
2126 return this;
2127 }
2128
2129 public Mapping buildMapping() {
2130 return new Mapping() {
2131 /**
2132 * Returns the identifier type of a mapped class
2133 */
2134 public Type getIdentifierType(String persistentClass) throws MappingException {
2135 PersistentClass pc = ( (PersistentClass) classes.get( persistentClass ) );
2136 if ( pc == null ) {
2137 throw new MappingException( "persistent class not known: " + persistentClass );
2138 }
2139 return pc.getIdentifier().getType();
2140 }
2141
2142 public String getIdentifierPropertyName(String persistentClass) throws MappingException {
2143 final PersistentClass pc = (PersistentClass) classes.get( persistentClass );
2144 if ( pc == null ) {
2145 throw new MappingException( "persistent class not known: " + persistentClass );
2146 }
2147 if ( !pc.hasIdentifierProperty() ) {
2148 return null;
2149 }
2150 return pc.getIdentifierProperty().getName();
2151 }
2152
2153 public Type getReferencedPropertyType(String persistentClass, String propertyName) throws MappingException {
2154 final PersistentClass pc = (PersistentClass) classes.get( persistentClass );
2155 if ( pc == null ) {
2156 throw new MappingException( "persistent class not known: " + persistentClass );
2157 }
2158 Property prop = pc.getReferencedProperty( propertyName );
2159 if ( prop == null ) {
2160 throw new MappingException(
2161 "property not known: " +
2162 persistentClass + '.' + propertyName
2163 );
2164 }
2165 return prop.getType();
2166 }
2167 };
2168 }
2169
2170 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
2171 ois.defaultReadObject();
2172 this.mapping = buildMapping();
2173 xmlHelper = new XMLHelper();
2174 }
2175
2176 public Map getFilterDefinitions() {
2177 return filterDefinitions;
2178 }
2179
2180 public void addFilterDefinition(FilterDefinition definition) {
2181 filterDefinitions.put( definition.getFilterName(), definition );
2182 }
2183
2184 public void addAuxiliaryDatabaseObject(AuxiliaryDatabaseObject object) {
2185 auxiliaryDatabaseObjects.add( object );
2186 }
2187
2188 public Map getSqlFunctions() {
2189 return sqlFunctions;
2190 }
2191
2192 public void addSqlFunction(String functionName, SQLFunction function) {
2193 sqlFunctions.put( functionName, function );
2194 }
2195
2196 public SessionFactoryObserver getSessionFactoryObserver() {
2197 return sessionFactoryObserver;
2198 }
2199
2200 public void setSessionFactoryObserver(SessionFactoryObserver sessionFactoryObserver) {
2201 this.sessionFactoryObserver = sessionFactoryObserver;
2202 }
2203 }