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