/* * Hibernate, Relational Persistence for Idiomatic Java * * Copyright (c) 2009-2011, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package org.hibernate.ejb; import javax.naming.BinaryRefAddr; import javax.naming.NamingException; import javax.naming.Reference; import javax.naming.Referenceable; import javax.persistence.Embeddable; import javax.persistence.Entity; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityNotFoundException; import javax.persistence.MappedSuperclass; import javax.persistence.PersistenceException; import javax.persistence.spi.PersistenceUnitInfo; import javax.persistence.spi.PersistenceUnitTransactionType; import javax.sql.DataSource; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.annotation.Annotation; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import org.dom4j.Element; import org.jboss.logging.Logger; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.hibernate.HibernateException; import org.hibernate.Interceptor; import org.hibernate.MappingException; import org.hibernate.MappingNotFoundException; import org.hibernate.SessionFactoryObserver; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.cfg.NamingStrategy; import org.hibernate.cfg.annotations.reflection.XMLContext; import org.hibernate.cfg.beanvalidation.BeanValidationIntegrator; import org.hibernate.ejb.cfg.spi.IdentifierGeneratorStrategyProvider; import org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider; import org.hibernate.ejb.event.JpaIntegrator; import org.hibernate.ejb.instrument.InterceptFieldClassFileTransformer; import org.hibernate.ejb.internal.EntityManagerMessageLogger; import org.hibernate.ejb.packaging.JarVisitorFactory; import org.hibernate.ejb.packaging.NamedInputStream; import org.hibernate.ejb.packaging.NativeScanner; import org.hibernate.ejb.packaging.PersistenceMetadata; import org.hibernate.ejb.packaging.PersistenceXmlLoader; import org.hibernate.ejb.packaging.Scanner; import org.hibernate.ejb.util.ConfigurationHelper; import org.hibernate.ejb.util.LogHelper; import org.hibernate.ejb.util.NamingHelper; import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory; import org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory; import org.hibernate.id.factory.spi.MutableIdentifierGeneratorFactory; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.xml.MappingReader; import org.hibernate.internal.util.xml.OriginImpl; import org.hibernate.internal.util.xml.XmlDocument; import org.hibernate.mapping.AuxiliaryDatabaseObject; import org.hibernate.mapping.PersistentClass; import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.secure.internal.JACCConfiguration; import org.hibernate.service.BootstrapServiceRegistryBuilder; import org.hibernate.service.ServiceRegistryBuilder; import org.hibernate.service.internal.BootstrapServiceRegistryImpl; import org.hibernate.service.jdbc.connections.internal.DatasourceConnectionProviderImpl; /** * Allow a fine tuned configuration of an EJB 3.0 EntityManagerFactory * * A Ejb3Configuration object is only guaranteed to create one EntityManagerFactory. * Multiple usage of {@link #buildEntityManagerFactory()} is not guaranteed. * * After #buildEntityManagerFactory() has been called, you no longer can change the configuration * state (no class adding, no property change etc) * * When serialized / deserialized or retrieved from the JNDI, you no longer can change the * configuration state (no class adding, no property change etc) * * Putting the configuration in the JNDI is an expensive operation that requires a partial * serialization * * @author Emmanuel Bernard * * @deprecated Direct usage of this class has never been supported. Instead, the application should obtain reference * to the {@link EntityManagerFactory} as outlined in the JPA specification, section <i>7.3 Obtaining an Entity * Manager Factory</i> based on runtime environment. Additionally this class will be removed in Hibernate release * 5.0 for the same reasoning outlined on {@link Configuration} due to move towards new * {@link org.hibernate.SessionFactory} building methodology. See * <a href="http://opensource.atlassian.com/projects/hibernate/browse/HHH-6181">HHH-6181</a> and * <a href="http://opensource.atlassian.com/projects/hibernate/browse/HHH-6159">HHH-6159</a> for details */ @Deprecated @SuppressWarnings( {"JavaDoc"}) public class Ejb3Configuration implements Serializable, Referenceable { private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger( EntityManagerMessageLogger.class, Ejb3Configuration.class.getName() ); private static final String IMPLEMENTATION_NAME = HibernatePersistence.class.getName(); private static final String META_INF_ORM_XML = "META-INF/orm.xml"; private static final String PARSED_MAPPING_DOMS = "hibernate.internal.mapping_doms"; private static EntityNotFoundDelegate ejb3EntityNotFoundDelegate = new Ejb3EntityNotFoundDelegate(); private static Configuration DEFAULT_CONFIGURATION = new Configuration(); private static class Ejb3EntityNotFoundDelegate implements EntityNotFoundDelegate, Serializable { public void handleEntityNotFound(String entityName, Serializable id) { throw new EntityNotFoundException("Unable to find " + entityName + " with id " + id); } } private String persistenceUnitName; private String cfgXmlResource; private Configuration cfg; //made transient and not restored in deserialization on purpose, should no longer be called after restoration private PersistenceUnitTransactionType transactionType; private boolean discardOnClose; //made transient and not restored in deserialization on purpose, should no longer be called after restoration private transient ClassLoader overridenClassLoader; private boolean isConfigurationProcessed = false; public Ejb3Configuration() { cfg = new Configuration(); cfg.setEntityNotFoundDelegate( ejb3EntityNotFoundDelegate ); } /** * Used to inject a datasource object as the connection provider. * If used, be sure to <b>not override</b> the hibernate.connection.provider_class * property */ @SuppressWarnings({ "JavaDoc", "unchecked" }) public void setDataSource(DataSource ds) { if ( ds != null ) { cfg.getProperties().put( Environment.DATASOURCE, ds ); this.setProperty( Environment.CONNECTION_PROVIDER, DatasourceConnectionProviderImpl.class.getName() ); } } /** * create a factory from a parsed persistence.xml * Especially the scanning of classes and additional jars is done already at this point. * <p/> * NOTE: public only for unit testing purposes; not a public API! * * @param metadata The information parsed from the persistence.xml * @param overridesIn Any explicitly passed config settings * * @return this */ @SuppressWarnings({ "unchecked" }) public Ejb3Configuration configure(PersistenceMetadata metadata, Map overridesIn) { LOG.debugf("Creating Factory: %s", metadata.getName()); Map overrides = new HashMap(); if ( overridesIn != null ) { overrides.putAll( overridesIn ); } Map workingVars = new HashMap(); workingVars.put( AvailableSettings.PERSISTENCE_UNIT_NAME, metadata.getName() ); this.persistenceUnitName = metadata.getName(); if ( StringHelper.isNotEmpty( metadata.getJtaDatasource() ) ) { this.setProperty( Environment.DATASOURCE, metadata.getJtaDatasource() ); } else if ( StringHelper.isNotEmpty( metadata.getNonJtaDatasource() ) ) { this.setProperty( Environment.DATASOURCE, metadata.getNonJtaDatasource() ); } else { final String driver = (String) metadata.getProps().get( AvailableSettings.JDBC_DRIVER ); if ( StringHelper.isNotEmpty( driver ) ) { this.setProperty( Environment.DRIVER, driver ); } final String url = (String) metadata.getProps().get( AvailableSettings.JDBC_URL ); if ( StringHelper.isNotEmpty( url ) ) { this.setProperty( Environment.URL, url ); } final String user = (String) metadata.getProps().get( AvailableSettings.JDBC_USER ); if ( StringHelper.isNotEmpty( user ) ) { this.setProperty( Environment.USER, user ); } final String pass = (String) metadata.getProps().get( AvailableSettings.JDBC_PASSWORD ); if ( StringHelper.isNotEmpty( pass ) ) { this.setProperty( Environment.PASS, pass ); } } defineTransactionType( metadata.getTransactionType(), workingVars ); if ( metadata.getClasses().size() > 0 ) { workingVars.put( AvailableSettings.CLASS_NAMES, metadata.getClasses() ); } if ( metadata.getPackages().size() > 0 ) { workingVars.put( AvailableSettings.PACKAGE_NAMES, metadata.getPackages() ); } if ( metadata.getMappingFiles().size() > 0 ) { workingVars.put( AvailableSettings.XML_FILE_NAMES, metadata.getMappingFiles() ); } if ( metadata.getHbmfiles().size() > 0 ) { workingVars.put( AvailableSettings.HBXML_FILES, metadata.getHbmfiles() ); } Properties props = new Properties(); props.putAll( metadata.getProps() ); // validation factory final Object validationFactory = overrides.get( AvailableSettings.VALIDATION_FACTORY ); if ( validationFactory != null ) { BeanValidationIntegrator.validateFactory( validationFactory ); props.put( AvailableSettings.VALIDATION_FACTORY, validationFactory ); } overrides.remove( AvailableSettings.VALIDATION_FACTORY ); // validation-mode (overrides has precedence) { final Object integrationValue = overrides.get( AvailableSettings.VALIDATION_MODE ); if ( integrationValue != null ) { props.put( AvailableSettings.VALIDATION_MODE, integrationValue.toString() ); } else if ( metadata.getValidationMode() != null ) { props.put( AvailableSettings.VALIDATION_MODE, metadata.getValidationMode() ); } overrides.remove( AvailableSettings.VALIDATION_MODE ); } // shared-cache-mode (overrides has precedence) { final Object integrationValue = overrides.get( AvailableSettings.SHARED_CACHE_MODE ); if ( integrationValue != null ) { props.put( AvailableSettings.SHARED_CACHE_MODE, integrationValue.toString() ); } else if ( metadata.getSharedCacheMode() != null ) { props.put( AvailableSettings.SHARED_CACHE_MODE, metadata.getSharedCacheMode() ); } overrides.remove( AvailableSettings.SHARED_CACHE_MODE ); } for ( Map.Entry entry : (Set<Map.Entry>) overrides.entrySet() ) { Object value = entry.getValue(); props.put( entry.getKey(), value == null ? "" : value ); //alter null, not allowed in properties } configure( props, workingVars ); return this; } /** * Build the configuration from an entity manager name and given the * appropriate extra properties. Those properties override the one get through * the persistence.xml file. * If the persistence unit name is not found or does not match the Persistence Provider, null is returned * * This method is used in a non managed environment * * @param persistenceUnitName persistence unit name * @param integration properties passed to the persistence provider * * @return configured Ejb3Configuration or null if no persistence unit match * * @see HibernatePersistence#createEntityManagerFactory(String, java.util.Map) */ @SuppressWarnings({ "unchecked" }) public Ejb3Configuration configure(String persistenceUnitName, Map integration) { try { LOG.debugf("Look up for persistence unit: %s", persistenceUnitName); integration = integration == null ? CollectionHelper.EMPTY_MAP : Collections.unmodifiableMap( integration ); Enumeration<URL> xmls = Thread.currentThread() .getContextClassLoader() .getResources( "META-INF/persistence.xml" ); if (!xmls.hasMoreElements()) LOG.unableToFindPersistenceXmlInClasspath(); while ( xmls.hasMoreElements() ) { URL url = xmls.nextElement(); LOG.trace("Analyzing persistence.xml: " + url); List<PersistenceMetadata> metadataFiles = PersistenceXmlLoader.deploy( url, integration, cfg.getEntityResolver(), PersistenceUnitTransactionType.RESOURCE_LOCAL ); for ( PersistenceMetadata metadata : metadataFiles ) { LOG.trace(metadata); if ( metadata.getProvider() == null || IMPLEMENTATION_NAME.equalsIgnoreCase( metadata.getProvider() ) ) { //correct provider //lazy load the scanner to avoid unnecessary IOExceptions Scanner scanner = null; URL jarURL = null; if ( metadata.getName() == null ) { scanner = buildScanner( metadata.getProps(), integration ); jarURL = JarVisitorFactory.getJarURLFromURLEntry( url, "/META-INF/persistence.xml" ); metadata.setName( scanner.getUnqualifiedJarName(jarURL) ); } if ( persistenceUnitName == null && xmls.hasMoreElements() ) { throw new PersistenceException( "No name provided and several persistence units found" ); } else if ( persistenceUnitName == null || metadata.getName().equals( persistenceUnitName ) ) { if (scanner == null) { scanner = buildScanner( metadata.getProps(), integration ); jarURL = JarVisitorFactory.getJarURLFromURLEntry( url, "/META-INF/persistence.xml" ); } //scan main JAR ScanningContext mainJarScanCtx = new ScanningContext() .scanner( scanner ) .url( jarURL ) .explicitMappingFiles( metadata.getMappingFiles() ) .searchOrm( true ); setDetectedArtifactsOnScanningContext( mainJarScanCtx, metadata.getProps(), integration, metadata.getExcludeUnlistedClasses() ); addMetadataFromScan( mainJarScanCtx, metadata ); ScanningContext otherJarScanCtx = new ScanningContext() .scanner( scanner ) .explicitMappingFiles( metadata.getMappingFiles() ) .searchOrm( true ); setDetectedArtifactsOnScanningContext( otherJarScanCtx, metadata.getProps(), integration, false ); for ( String jarFile : metadata.getJarFiles() ) { otherJarScanCtx.url( JarVisitorFactory.getURLFromPath( jarFile ) ); addMetadataFromScan( otherJarScanCtx, metadata ); } return configure( metadata, integration ); } } } } return null; } catch (Exception e) { if ( e instanceof PersistenceException) { throw (PersistenceException) e; } else { throw new PersistenceException( getExceptionHeader() + "Unable to configure EntityManagerFactory", e ); } } } private Scanner buildScanner(Properties properties, Map<?,?> integration) { //read the String or Instance from the integration map first and use the properties as a backup. Object scanner = integration.get( AvailableSettings.SCANNER ); if (scanner == null) { scanner = properties.getProperty( AvailableSettings.SCANNER ); } if (scanner != null) { Class<?> scannerClass; if ( scanner instanceof String ) { try { scannerClass = ReflectHelper.classForName( (String) scanner, this.getClass() ); } catch ( ClassNotFoundException e ) { throw new PersistenceException( "Cannot find scanner class. " + AvailableSettings.SCANNER + "=" + scanner, e ); } } else if (scanner instanceof Class) { scannerClass = (Class<? extends Scanner>) scanner; } else if (scanner instanceof Scanner) { return (Scanner) scanner; } else { throw new PersistenceException( "Scanner class configuration error: unknown type on the property. " + AvailableSettings.SCANNER ); } try { return (Scanner) scannerClass.newInstance(); } catch ( InstantiationException e ) { throw new PersistenceException( "Unable to load Scanner class: " + scannerClass, e ); } catch ( IllegalAccessException e ) { throw new PersistenceException( "Unable to load Scanner class: " + scannerClass, e ); } } else { return new NativeScanner(); } } private static class ScanningContext { //boolean excludeUnlistedClasses; private Scanner scanner; private URL url; private List<String> explicitMappingFiles; private boolean detectClasses; private boolean detectHbmFiles; private boolean searchOrm; public ScanningContext scanner(Scanner scanner) { this.scanner = scanner; return this; } public ScanningContext url(URL url) { this.url = url; return this; } public ScanningContext explicitMappingFiles(List<String> explicitMappingFiles) { this.explicitMappingFiles = explicitMappingFiles; return this; } public ScanningContext detectClasses(boolean detectClasses) { this.detectClasses = detectClasses; return this; } public ScanningContext detectHbmFiles(boolean detectHbmFiles) { this.detectHbmFiles = detectHbmFiles; return this; } public ScanningContext searchOrm(boolean searchOrm) { this.searchOrm = searchOrm; return this; } } private static void addMetadataFromScan(ScanningContext scanningContext, PersistenceMetadata metadata) throws IOException { List<String> classes = metadata.getClasses(); List<String> packages = metadata.getPackages(); List<NamedInputStream> hbmFiles = metadata.getHbmfiles(); List<String> mappingFiles = metadata.getMappingFiles(); addScannedEntries( scanningContext, classes, packages, hbmFiles, mappingFiles ); } private static void addScannedEntries(ScanningContext scanningContext, List<String> classes, List<String> packages, List<NamedInputStream> hbmFiles, List<String> mappingFiles) throws IOException { Scanner scanner = scanningContext.scanner; if (scanningContext.detectClasses) { Set<Class<? extends Annotation>> annotationsToExclude = new HashSet<Class<? extends Annotation>>(3); annotationsToExclude.add( Entity.class ); annotationsToExclude.add( MappedSuperclass.class ); annotationsToExclude.add( Embeddable.class ); Set<Class<?>> matchingClasses = scanner.getClassesInJar( scanningContext.url, annotationsToExclude ); for (Class<?> clazz : matchingClasses) { classes.add( clazz.getName() ); } Set<Package> matchingPackages = scanner.getPackagesInJar( scanningContext.url, new HashSet<Class<? extends Annotation>>(0) ); for (Package pkg : matchingPackages) { packages.add( pkg.getName() ); } } Set<String> patterns = new HashSet<String>(); if (scanningContext.searchOrm) { patterns.add( META_INF_ORM_XML ); } if (scanningContext.detectHbmFiles) { patterns.add( "**/*.hbm.xml" ); } if ( mappingFiles != null) patterns.addAll( mappingFiles ); if (patterns.size() !=0) { Set<NamedInputStream> files = scanner.getFilesInJar( scanningContext.url, patterns ); for (NamedInputStream file : files) { hbmFiles.add( file ); if (mappingFiles != null) mappingFiles.remove( file.getName() ); } } } /** * Process configuration from a PersistenceUnitInfo object; typically called by the container * via {@link javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory}. * In Hibernate EM, this correlates to {@link HibernatePersistence#createContainerEntityManagerFactory} * * @param info The persistence unit info passed in by the container (usually from processing a persistence.xml). * @param integration The map of integration properties from the container to configure the provider. * * @return this * * @see HibernatePersistence#createContainerEntityManagerFactory */ @SuppressWarnings({ "unchecked" }) public Ejb3Configuration configure(PersistenceUnitInfo info, Map integration) { if (LOG.isDebugEnabled()) LOG.debugf("Processing %s", LogHelper.logPersistenceUnitInfo(info)); else LOG.processingPersistenceUnitInfoName(info.getPersistenceUnitName()); // Spec says the passed map may be null, so handle that to make further processing easier... integration = integration != null ? Collections.unmodifiableMap( integration ) : CollectionHelper.EMPTY_MAP; // See if we (Hibernate) are the persistence provider String provider = (String) integration.get( AvailableSettings.PROVIDER ); if ( provider == null ) { provider = info.getPersistenceProviderClassName(); } if ( provider != null && ! provider.trim().startsWith( IMPLEMENTATION_NAME ) ) { LOG.requiredDifferentProvider(provider); return null; } // set the classloader, passed in by the container in info, to set as the TCCL so that // Hibernate uses it to properly resolve class references. if ( info.getClassLoader() == null ) { throw new IllegalStateException( "[PersistenceUnit: " + info.getPersistenceUnitName() == null ? "" : info.getPersistenceUnitName() + "] " + "PersistenceUnitInfo.getClassLoader() id null" ); } Thread thread = Thread.currentThread(); ClassLoader contextClassLoader = thread.getContextClassLoader(); boolean sameClassLoader = info.getClassLoader().equals( contextClassLoader ); if ( ! sameClassLoader ) { overridenClassLoader = info.getClassLoader(); thread.setContextClassLoader( overridenClassLoader ); } else { overridenClassLoader = null; } // Best I can tell, 'workingVars' is some form of additional configuration contract. // But it does not correlate 1-1 to EMF/SF settings. It really is like a set of de-typed // additional configuration info. I think it makes better sense to define this as an actual // contract if that was in fact the intent; the code here is pretty confusing. try { Map workingVars = new HashMap(); workingVars.put( AvailableSettings.PERSISTENCE_UNIT_NAME, info.getPersistenceUnitName() ); this.persistenceUnitName = info.getPersistenceUnitName(); List<String> entities = new ArrayList<String>( 50 ); if ( info.getManagedClassNames() != null ) entities.addAll( info.getManagedClassNames() ); List<NamedInputStream> hbmFiles = new ArrayList<NamedInputStream>(); List<String> packages = new ArrayList<String>(); List<String> xmlFiles = new ArrayList<String>( 50 ); List<XmlDocument> xmlDocuments = new ArrayList<XmlDocument>( 50 ); if ( info.getMappingFileNames() != null ) { xmlFiles.addAll( info.getMappingFileNames() ); } //Should always be true if the container is not dump boolean searchForORMFiles = ! xmlFiles.contains( META_INF_ORM_XML ); ScanningContext context = new ScanningContext(); final Properties copyOfProperties = (Properties) info.getProperties().clone(); ConfigurationHelper.overrideProperties( copyOfProperties, integration ); context.scanner( buildScanner( copyOfProperties, integration ) ) .searchOrm( searchForORMFiles ) .explicitMappingFiles( null ); //URLs provided by the container already //context for other JARs setDetectedArtifactsOnScanningContext(context, info.getProperties(), null, false ); for ( URL jar : info.getJarFileUrls() ) { context.url(jar); scanForClasses( context, packages, entities, hbmFiles ); } //main jar context.url( info.getPersistenceUnitRootUrl() ); setDetectedArtifactsOnScanningContext( context, info.getProperties(), null, info.excludeUnlistedClasses() ); scanForClasses( context, packages, entities, hbmFiles ); Properties properties = info.getProperties() != null ? info.getProperties() : new Properties(); ConfigurationHelper.overrideProperties( properties, integration ); //FIXME entities is used to enhance classes and to collect annotated entities this should not be mixed //fill up entities with the on found in xml files addXMLEntities( xmlFiles, info, entities, xmlDocuments ); //FIXME send the appropriate entites. if ( "true".equalsIgnoreCase( properties.getProperty( AvailableSettings.USE_CLASS_ENHANCER ) ) ) { info.addTransformer( new InterceptFieldClassFileTransformer( entities ) ); } workingVars.put( AvailableSettings.CLASS_NAMES, entities ); workingVars.put( AvailableSettings.PACKAGE_NAMES, packages ); workingVars.put( AvailableSettings.XML_FILE_NAMES, xmlFiles ); workingVars.put( PARSED_MAPPING_DOMS, xmlDocuments ); if ( hbmFiles.size() > 0 ) { workingVars.put( AvailableSettings.HBXML_FILES, hbmFiles ); } // validation factory final Object validationFactory = integration.get( AvailableSettings.VALIDATION_FACTORY ); if ( validationFactory != null ) { BeanValidationIntegrator.validateFactory( validationFactory ); properties.put( AvailableSettings.VALIDATION_FACTORY, validationFactory ); } // validation-mode (integration has precedence) { final Object integrationValue = integration.get( AvailableSettings.VALIDATION_MODE ); if ( integrationValue != null ) { properties.put( AvailableSettings.VALIDATION_MODE, integrationValue.toString() ); } else if ( info.getValidationMode() != null ) { properties.put( AvailableSettings.VALIDATION_MODE, info.getValidationMode().name() ); } } // shared-cache-mode (integration has precedence) { final Object integrationValue = integration.get( AvailableSettings.SHARED_CACHE_MODE ); if ( integrationValue != null ) { properties.put( AvailableSettings.SHARED_CACHE_MODE, integrationValue.toString() ); } else if ( info.getSharedCacheMode() != null ) { properties.put( AvailableSettings.SHARED_CACHE_MODE, info.getSharedCacheMode().name() ); } } //datasources Boolean isJTA = null; boolean overridenDatasource = false; if ( integration.containsKey( AvailableSettings.JTA_DATASOURCE ) ) { String dataSource = (String) integration.get( AvailableSettings.JTA_DATASOURCE ); overridenDatasource = true; properties.setProperty( Environment.DATASOURCE, dataSource ); isJTA = Boolean.TRUE; } if ( integration.containsKey( AvailableSettings.NON_JTA_DATASOURCE ) ) { String dataSource = (String) integration.get( AvailableSettings.NON_JTA_DATASOURCE ); overridenDatasource = true; properties.setProperty( Environment.DATASOURCE, dataSource ); if (isJTA == null) isJTA = Boolean.FALSE; } if ( ! overridenDatasource && ( info.getJtaDataSource() != null || info.getNonJtaDataSource() != null ) ) { isJTA = info.getJtaDataSource() != null ? Boolean.TRUE : Boolean.FALSE; this.setDataSource( isJTA ? info.getJtaDataSource() : info.getNonJtaDataSource() ); this.setProperty( Environment.CONNECTION_PROVIDER, InjectedDataSourceConnectionProvider.class.getName() ); } /* * If explicit type => use it * If a JTA DS is used => JTA transaction, * if a non JTA DS is used => RESOURCe_LOCAL * if none, set to JavaEE default => JTA transaction */ PersistenceUnitTransactionType transactionType = info.getTransactionType(); if (transactionType == null) { if (isJTA == Boolean.TRUE) { transactionType = PersistenceUnitTransactionType.JTA; } else if ( isJTA == Boolean.FALSE ) { transactionType = PersistenceUnitTransactionType.RESOURCE_LOCAL; } else { transactionType = PersistenceUnitTransactionType.JTA; } } defineTransactionType( transactionType, workingVars ); configure( properties, workingVars ); } finally { //After EMF, set the CCL back if ( ! sameClassLoader ) { thread.setContextClassLoader( contextClassLoader ); } } return this; } /** * Processes {@code xmlFiles} argument and populates:<ul> * <li>the {@code entities} list with encountered classnames</li> * <li>the {@code xmlDocuments} list with parsed/validated {@link XmlDocument} corrolary to each xml file</li> * </ul> * * @param xmlFiles The XML resource names; these will be resolved by classpath lookup and parsed/validated. * @param info The PUI * @param entities (output) The names of all encountered "mapped" classes * @param xmlDocuments (output) The list of {@link XmlDocument} instances of each entry in {@code xmlFiles} */ @SuppressWarnings({ "unchecked" }) private void addXMLEntities( List<String> xmlFiles, PersistenceUnitInfo info, List<String> entities, List<XmlDocument> xmlDocuments) { //TODO handle inputstream related hbm files ClassLoader classLoaderToUse = info.getNewTempClassLoader(); if ( classLoaderToUse == null ) { LOG.persistenceProviderCallerDoesNotImplementEjb3SpecCorrectly(); return; } for ( final String xmlFile : xmlFiles ) { final InputStream fileInputStream = classLoaderToUse.getResourceAsStream( xmlFile ); if ( fileInputStream == null ) { LOG.unableToResolveMappingFile(xmlFile); continue; } final InputSource inputSource = new InputSource( fileInputStream ); XmlDocument metadataXml = MappingReader.INSTANCE.readMappingDocument( cfg.getEntityResolver(), inputSource, new OriginImpl( "persistence-unit-info", xmlFile ) ); xmlDocuments.add( metadataXml ); try { final Element rootElement = metadataXml.getDocumentTree().getRootElement(); if ( rootElement != null && "entity-mappings".equals( rootElement.getName() ) ) { Element element = rootElement.element( "package" ); String defaultPackage = element != null ? element.getTextTrim() : null; List<Element> elements = rootElement.elements( "entity" ); for (Element subelement : elements ) { String classname = XMLContext.buildSafeClassName( subelement.attributeValue( "class" ), defaultPackage ); if ( ! entities.contains( classname ) ) { entities.add( classname ); } } elements = rootElement.elements( "mapped-superclass" ); for (Element subelement : elements ) { String classname = XMLContext.buildSafeClassName( subelement.attributeValue( "class" ), defaultPackage ); if ( ! entities.contains( classname ) ) { entities.add( classname ); } } elements = rootElement.elements( "embeddable" ); for (Element subelement : elements ) { String classname = XMLContext.buildSafeClassName( subelement.attributeValue( "class" ), defaultPackage ); if ( ! entities.contains( classname ) ) { entities.add( classname ); } } } else if ( rootElement != null && "hibernate-mappings".equals( rootElement.getName() ) ) { //FIXME include hbm xml entities to enhance them but entities is also used to collect annotated entities } } finally { try { fileInputStream.close(); } catch (IOException ioe) { LOG.unableToCloseInputStream(ioe); } } } xmlFiles.clear(); } private void defineTransactionType(Object overridenTxType, Map workingVars) { if ( overridenTxType == null ) { // if ( transactionType == null ) { // transactionType = PersistenceUnitTransactionType.JTA; //this is the default value // } //nothing to override } else if ( overridenTxType instanceof String ) { transactionType = PersistenceXmlLoader.getTransactionType( (String) overridenTxType ); } else if ( overridenTxType instanceof PersistenceUnitTransactionType ) { transactionType = (PersistenceUnitTransactionType) overridenTxType; } else { throw new PersistenceException( getExceptionHeader() + AvailableSettings.TRANSACTION_TYPE + " of the wrong class type" + ": " + overridenTxType.getClass() ); } } public Ejb3Configuration setProperty(String key, String value) { cfg.setProperty( key, value ); return this; } /** * Set ScanningContext detectClasses and detectHbmFiles according to context */ private void setDetectedArtifactsOnScanningContext(ScanningContext context, Properties properties, Map overridenProperties, boolean excludeIfNotOverriden) { boolean detectClasses = false; boolean detectHbm = false; String detectSetting = overridenProperties != null ? (String) overridenProperties.get( AvailableSettings.AUTODETECTION ) : null; detectSetting = detectSetting == null ? properties.getProperty( AvailableSettings.AUTODETECTION) : detectSetting; if ( detectSetting == null && excludeIfNotOverriden) { //not overriden through HibernatePersistence.AUTODETECTION so we comply with the spec excludeUnlistedClasses context.detectClasses( false ).detectHbmFiles( false ); return; } if ( detectSetting == null){ detectSetting = "class,hbm"; } StringTokenizer st = new StringTokenizer( detectSetting, ", ", false ); while ( st.hasMoreElements() ) { String element = (String) st.nextElement(); if ( "class".equalsIgnoreCase( element ) ) detectClasses = true; if ( "hbm".equalsIgnoreCase( element ) ) detectHbm = true; } LOG.debugf("Detect class: %s; detect hbm: %s", detectClasses, detectHbm); context.detectClasses( detectClasses ).detectHbmFiles( detectHbm ); } private void scanForClasses(ScanningContext scanningContext, List<String> packages, List<String> entities, List<NamedInputStream> hbmFiles) { if (scanningContext.url == null) { LOG.containerProvidingNullPersistenceUnitRootUrl(); return; } try { addScannedEntries( scanningContext, entities, packages, hbmFiles, null ); } catch (RuntimeException e) { throw new RuntimeException( "error trying to scan <jar-file>: " + scanningContext.url.toString(), e ); } catch( IOException e ) { throw new RuntimeException( "Error while reading " + scanningContext.url.toString(), e ); } } /** * create a factory from a list of properties and * HibernatePersistence.CLASS_NAMES -> Collection<String> (use to list the classes from config files * HibernatePersistence.PACKAGE_NAMES -> Collection<String> (use to list the mappings from config files * HibernatePersistence.HBXML_FILES -> Collection<InputStream> (input streams of hbm files) * HibernatePersistence.LOADED_CLASSES -> Collection<Class> (list of loaded classes) * <p/> * <b>Used by JBoss AS only</b> * @deprecated use the Java Persistence API */ // This is used directly by JBoss so don't remove until further notice. bill@jboss.org @Deprecated public EntityManagerFactory createEntityManagerFactory(Map workingVars) { configure( workingVars ); return buildEntityManagerFactory(); } /** * Process configuration and build an EntityManagerFactory <b>when</b> the configuration is ready * @deprecated */ @Deprecated public EntityManagerFactory createEntityManagerFactory() { configure( cfg.getProperties(), new HashMap() ); return buildEntityManagerFactory(); } public EntityManagerFactory buildEntityManagerFactory() { return buildEntityManagerFactory( new BootstrapServiceRegistryBuilder() ); } public EntityManagerFactory buildEntityManagerFactory(BootstrapServiceRegistryBuilder builder) { Thread thread = null; ClassLoader contextClassLoader = null; if ( overridenClassLoader != null ) { thread = Thread.currentThread(); contextClassLoader = thread.getContextClassLoader(); thread.setContextClassLoader( overridenClassLoader ); } try { final ServiceRegistryBuilder serviceRegistryBuilder = new ServiceRegistryBuilder( builder.with( new JpaIntegrator() ).build() ); serviceRegistryBuilder.applySettings( cfg.getProperties() ); configure( (Properties) null, null ); NamingHelper.bind( this ); return new EntityManagerFactoryImpl( transactionType, discardOnClose, getSessionInterceptorClass( cfg.getProperties() ), cfg, serviceRegistryBuilder.buildServiceRegistry() ); } catch (HibernateException e) { throw new PersistenceException( getExceptionHeader() + "Unable to build EntityManagerFactory", e ); } finally { if (thread != null) { thread.setContextClassLoader( contextClassLoader ); } } } private Class getSessionInterceptorClass(Properties properties) { String sessionInterceptorClassname = (String) properties.get( AvailableSettings.SESSION_INTERCEPTOR ); if ( StringHelper.isNotEmpty( sessionInterceptorClassname ) ) { try { Class interceptorClass = ReflectHelper.classForName( sessionInterceptorClassname, Ejb3Configuration.class ); interceptorClass.newInstance(); return interceptorClass; } catch (ClassNotFoundException e) { throw new PersistenceException( getExceptionHeader() + "Unable to load " + AvailableSettings.SESSION_INTERCEPTOR + ": " + sessionInterceptorClassname, e); } catch (IllegalAccessException e) { throw new PersistenceException( getExceptionHeader() + "Unable to instanciate " + AvailableSettings.SESSION_INTERCEPTOR + ": " + sessionInterceptorClassname, e); } catch (InstantiationException e) { throw new PersistenceException( getExceptionHeader() + "Unable to instanciate " + AvailableSettings.SESSION_INTERCEPTOR + ": " + sessionInterceptorClassname, e); } } return null; } public Reference getReference() throws NamingException { LOG.debugf( "Returning a Reference to the Ejb3Configuration" ); ByteArrayOutputStream stream = new ByteArrayOutputStream(); ObjectOutput out = null; byte[] serialized; try { out = new ObjectOutputStream( stream ); out.writeObject( this ); out.close(); serialized = stream.toByteArray(); stream.close(); } catch (IOException e) { NamingException namingException = new NamingException( "Unable to serialize Ejb3Configuration" ); namingException.setRootCause( e ); throw namingException; } return new Reference( Ejb3Configuration.class.getName(), new BinaryRefAddr("object", serialized ), Ejb3ConfigurationObjectFactory.class.getName(), null ); } @SuppressWarnings( {"unchecked"}) public Ejb3Configuration configure(Map configValues) { Properties props = new Properties(); if ( configValues != null ) { props.putAll( configValues ); //remove huge non String elements for a clean props props.remove( AvailableSettings.CLASS_NAMES ); props.remove( AvailableSettings.PACKAGE_NAMES ); props.remove( AvailableSettings.HBXML_FILES ); props.remove( AvailableSettings.LOADED_CLASSES ); } return configure( props, configValues ); } /** * Configures this configuration object from 2 distinctly different sources. * * @param properties These are the properties that came from the user, either via * a persistence.xml or explicitly passed in to one of our * {@link javax.persistence.spi.PersistenceProvider}/{@link HibernatePersistence} contracts. * @param workingVars Is collection of settings which need to be handled similarly * between the 2 main bootstrap methods, but where the values are determine very differently * by each bootstrap method. todo eventually make this a contract (class/interface) * * @return The configured configuration * * @see HibernatePersistence */ private Ejb3Configuration configure(Properties properties, Map workingVars) { //TODO check for people calling more than once this method (except buildEMF) if (isConfigurationProcessed) return this; isConfigurationProcessed = true; Properties preparedProperties = prepareProperties( properties, workingVars ); if ( workingVars == null ) workingVars = CollectionHelper.EMPTY_MAP; if ( preparedProperties.containsKey( AvailableSettings.CFG_FILE ) ) { String cfgFileName = preparedProperties.getProperty( AvailableSettings.CFG_FILE ); cfg.configure( cfgFileName ); } cfg.addProperties( preparedProperties ); //persistence.xml has priority over hibernate.cfg.xml addClassesToSessionFactory( workingVars ); //processes specific properties List<String> jaccKeys = new ArrayList<String>(); Interceptor defaultInterceptor = DEFAULT_CONFIGURATION.getInterceptor(); NamingStrategy defaultNamingStrategy = DEFAULT_CONFIGURATION.getNamingStrategy(); Iterator propertyIt = preparedProperties.keySet().iterator(); while ( propertyIt.hasNext() ) { Object uncastObject = propertyIt.next(); //had to be safe if ( uncastObject != null && uncastObject instanceof String ) { String propertyKey = (String) uncastObject; if ( propertyKey.startsWith( AvailableSettings.CLASS_CACHE_PREFIX ) ) { setCacheStrategy( propertyKey, preparedProperties, true, workingVars ); } else if ( propertyKey.startsWith( AvailableSettings.COLLECTION_CACHE_PREFIX ) ) { setCacheStrategy( propertyKey, preparedProperties, false, workingVars ); } else if ( propertyKey.startsWith( AvailableSettings.JACC_PREFIX ) && ! ( propertyKey.equals( AvailableSettings.JACC_CONTEXT_ID ) || propertyKey.equals( AvailableSettings.JACC_ENABLED ) ) ) { jaccKeys.add( propertyKey ); } } } final Interceptor interceptor = instantiateCustomClassFromConfiguration( preparedProperties, defaultInterceptor, cfg.getInterceptor(), AvailableSettings.INTERCEPTOR, "interceptor", Interceptor.class ); if ( interceptor != null ) { cfg.setInterceptor( interceptor ); } final NamingStrategy namingStrategy = instantiateCustomClassFromConfiguration( preparedProperties, defaultNamingStrategy, cfg.getNamingStrategy(), AvailableSettings.NAMING_STRATEGY, "naming strategy", NamingStrategy.class ); if ( namingStrategy != null ) { cfg.setNamingStrategy( namingStrategy ); } final SessionFactoryObserver observer = instantiateCustomClassFromConfiguration( preparedProperties, null, cfg.getSessionFactoryObserver(), AvailableSettings.SESSION_FACTORY_OBSERVER, "SessionFactory observer", SessionFactoryObserver.class ); if ( observer != null ) { cfg.setSessionFactoryObserver( observer ); } final IdentifierGeneratorStrategyProvider strategyProvider = instantiateCustomClassFromConfiguration( preparedProperties, null, null, AvailableSettings.IDENTIFIER_GENERATOR_STRATEGY_PROVIDER, "Identifier generator strategy provider", IdentifierGeneratorStrategyProvider.class ); if ( strategyProvider != null ) { final MutableIdentifierGeneratorFactory identifierGeneratorFactory = cfg.getIdentifierGeneratorFactory(); for ( Map.Entry<String,Class<?>> entry : strategyProvider.getStrategies().entrySet() ) { identifierGeneratorFactory.register( entry.getKey(), entry.getValue() ); } } if ( jaccKeys.size() > 0 ) { addSecurity( jaccKeys, preparedProperties, workingVars ); } //some spec compliance checking //TODO centralize that? if (!"true".equalsIgnoreCase(cfg.getProperty(Environment.AUTOCOMMIT))) LOG.jdbcAutoCommitFalseBreaksEjb3Spec(Environment.AUTOCOMMIT); discardOnClose = preparedProperties.getProperty(AvailableSettings.DISCARD_PC_ON_CLOSE).equals("true"); return this; } private <T> T instantiateCustomClassFromConfiguration( Properties preparedProperties, T defaultObject, T cfgObject, String propertyName, String classDescription, Class<T> objectClass) { if ( preparedProperties.containsKey( propertyName ) && ( cfgObject == null || cfgObject.equals( defaultObject ) ) ) { //cfg.setXxx has precedence over configuration file String className = preparedProperties.getProperty( propertyName ); try { Class<T> clazz = classForName( className ); return clazz.newInstance(); //cfg.setInterceptor( (Interceptor) instance.newInstance() ); } catch (ClassNotFoundException e) { throw new PersistenceException( getExceptionHeader() + "Unable to find " + classDescription + " class: " + className, e ); } catch (IllegalAccessException e) { throw new PersistenceException( getExceptionHeader() + "Unable to access " + classDescription + " class: " + className, e ); } catch (InstantiationException e) { throw new PersistenceException( getExceptionHeader() + "Unable to instantiate " + classDescription + " class: " + className, e ); } catch (ClassCastException e) { throw new PersistenceException( getExceptionHeader() + classDescription + " class does not implement " + objectClass + " interface: " + className, e ); } } return null; } @SuppressWarnings({ "unchecked" }) private void addClassesToSessionFactory(Map workingVars) { if ( workingVars.containsKey( AvailableSettings.CLASS_NAMES ) ) { Collection<String> classNames = (Collection<String>) workingVars.get( AvailableSettings.CLASS_NAMES ); addNamedAnnotatedClasses( this, classNames, workingVars ); } if ( workingVars.containsKey( PARSED_MAPPING_DOMS ) ) { Collection<XmlDocument> xmlDocuments = (Collection<XmlDocument>) workingVars.get( PARSED_MAPPING_DOMS ); for ( XmlDocument xmlDocument : xmlDocuments ) { cfg.add( xmlDocument ); } } //TODO apparently only used for Tests, get rid of it? if ( workingVars.containsKey( AvailableSettings.LOADED_CLASSES ) ) { Collection<Class> classes = (Collection<Class>) workingVars.get( AvailableSettings.LOADED_CLASSES ); for ( Class clazz : classes ) { cfg.addAnnotatedClass( clazz ); } } if ( workingVars.containsKey( AvailableSettings.PACKAGE_NAMES ) ) { Collection<String> packages = (Collection<String>) workingVars.get( AvailableSettings.PACKAGE_NAMES ); for ( String pkg : packages ) { cfg.addPackage( pkg ); } } if ( workingVars.containsKey( AvailableSettings.XML_FILE_NAMES ) ) { Collection<String> xmlFiles = (Collection<String>) workingVars.get( AvailableSettings.XML_FILE_NAMES ); for ( String xmlFile : xmlFiles ) { Boolean useMetaInf = null; try { if ( xmlFile.endsWith( META_INF_ORM_XML ) ) { useMetaInf = true; } cfg.addResource( xmlFile ); } catch( MappingNotFoundException e ) { if ( ! xmlFile.endsWith( META_INF_ORM_XML ) ) { throw new PersistenceException( getExceptionHeader() + "Unable to find XML mapping file in classpath: " + xmlFile); } else { useMetaInf = false; //swallow it, the META-INF/orm.xml is optional } } catch( MappingException me ) { throw new PersistenceException( getExceptionHeader() + "Error while reading JPA XML file: " + xmlFile, me); } if (Boolean.TRUE.equals(useMetaInf)) { LOG.exceptionHeaderFound(getExceptionHeader(), META_INF_ORM_XML); } else if (Boolean.FALSE.equals(useMetaInf)) { LOG.exceptionHeaderNotFound(getExceptionHeader(), META_INF_ORM_XML); } } } if ( workingVars.containsKey( AvailableSettings.HBXML_FILES ) ) { Collection<NamedInputStream> hbmXmlFiles = (Collection<NamedInputStream>) workingVars.get( AvailableSettings.HBXML_FILES ); for ( NamedInputStream is : hbmXmlFiles ) { try { //addInputStream has the responsibility to close the stream cfg.addInputStream( new BufferedInputStream( is.getStream() ) ); } catch (MappingException me) { //try our best to give the file name if ( StringHelper.isEmpty( is.getName() ) ) { throw me; } else { throw new MappingException("Error while parsing file: " + is.getName(), me ); } } } } } private String getExceptionHeader() { return (StringHelper.isNotEmpty(persistenceUnitName)) ? "[PersistenceUnit: " + persistenceUnitName + "] " : ""; } private Properties prepareProperties(Properties properties, Map workingVars) { Properties preparedProperties = new Properties(); //defaults different from Hibernate preparedProperties.setProperty( Environment.RELEASE_CONNECTIONS, "auto" ); preparedProperties.setProperty( Environment.JPAQL_STRICT_COMPLIANCE, "true" ); //settings that always apply to a compliant EJB3 preparedProperties.setProperty( Environment.AUTOCOMMIT, "true" ); preparedProperties.setProperty( Environment.USE_IDENTIFIER_ROLLBACK, "false" ); preparedProperties.setProperty( Environment.FLUSH_BEFORE_COMPLETION, "false" ); preparedProperties.setProperty( AvailableSettings.DISCARD_PC_ON_CLOSE, "false" ); if (cfgXmlResource != null) { preparedProperties.setProperty( AvailableSettings.CFG_FILE, cfgXmlResource ); cfgXmlResource = null; } //override the new defaults with the user defined ones //copy programmatically defined properties if ( cfg.getProperties() != null ) preparedProperties.putAll( cfg.getProperties() ); //copy them coping from configuration if ( properties != null ) preparedProperties.putAll( properties ); //note we don't copy cfg.xml properties, since they have to be overriden if (transactionType == null) { //if it has not been set, the user use a programmatic way transactionType = PersistenceUnitTransactionType.RESOURCE_LOCAL; } defineTransactionType( preparedProperties.getProperty( AvailableSettings.TRANSACTION_TYPE ), workingVars ); boolean hasTxStrategy = StringHelper.isNotEmpty( preparedProperties.getProperty( Environment.TRANSACTION_STRATEGY ) ); if ( ! hasTxStrategy && transactionType == PersistenceUnitTransactionType.JTA ) { preparedProperties.setProperty( Environment.TRANSACTION_STRATEGY, CMTTransactionFactory.class.getName() ); } else if ( ! hasTxStrategy && transactionType == PersistenceUnitTransactionType.RESOURCE_LOCAL ) { preparedProperties.setProperty( Environment.TRANSACTION_STRATEGY, JdbcTransactionFactory.class.getName() ); } if (hasTxStrategy) LOG.overridingTransactionStrategyDangerous(Environment.TRANSACTION_STRATEGY); if ( preparedProperties.getProperty( Environment.FLUSH_BEFORE_COMPLETION ).equals( "true" ) ) { preparedProperties.setProperty( Environment.FLUSH_BEFORE_COMPLETION, "false" ); LOG.definingFlushBeforeCompletionIgnoredInHem(Environment.FLUSH_BEFORE_COMPLETION); } return preparedProperties; } private Class classForName(String className) throws ClassNotFoundException { return ReflectHelper.classForName( className, this.getClass() ); } private void setCacheStrategy(String propertyKey, Map properties, boolean isClass, Map workingVars) { String role = propertyKey.substring( ( isClass ? AvailableSettings.CLASS_CACHE_PREFIX .length() : AvailableSettings.COLLECTION_CACHE_PREFIX.length() ) + 1 ); //dot size added String value = (String) properties.get( propertyKey ); StringTokenizer params = new StringTokenizer( value, ";, " ); if ( !params.hasMoreTokens() ) { StringBuilder error = new StringBuilder( "Illegal usage of " ); error.append( isClass ? AvailableSettings.CLASS_CACHE_PREFIX : AvailableSettings.COLLECTION_CACHE_PREFIX ); error.append( ": " ).append( propertyKey ).append( " " ).append( value ); throw new PersistenceException( getExceptionHeader() + error.toString() ); } String usage = params.nextToken(); String region = null; if ( params.hasMoreTokens() ) { region = params.nextToken(); } if ( isClass ) { boolean lazyProperty = true; if ( params.hasMoreTokens() ) { lazyProperty = "all".equalsIgnoreCase( params.nextToken() ); } cfg.setCacheConcurrencyStrategy( role, usage, region, lazyProperty ); } else { cfg.setCollectionCacheConcurrencyStrategy( role, usage, region ); } } private void addSecurity(List<String> keys, Map properties, Map workingVars) { LOG.debugf("Adding security"); if ( !properties.containsKey( AvailableSettings.JACC_CONTEXT_ID ) ) { throw new PersistenceException( getExceptionHeader() + "Entities have been configured for JACC, but " + AvailableSettings.JACC_CONTEXT_ID + " has not been set" ); } String contextId = (String) properties.get( AvailableSettings.JACC_CONTEXT_ID ); setProperty( Environment.JACC_CONTEXTID, contextId ); int roleStart = AvailableSettings.JACC_PREFIX.length() + 1; for ( String key : keys ) { JACCConfiguration jaccCfg = new JACCConfiguration( contextId ); try { String role = key.substring( roleStart, key.indexOf( '.', roleStart ) ); int classStart = roleStart + role.length() + 1; String clazz = key.substring( classStart, key.length() ); String actions = (String) properties.get( key ); jaccCfg.addPermission( role, clazz, actions ); } catch (IndexOutOfBoundsException e) { throw new PersistenceException( getExceptionHeader() + "Illegal usage of " + AvailableSettings.JACC_PREFIX + ": " + key ); } } } private void addNamedAnnotatedClasses( Ejb3Configuration cfg, Collection<String> classNames, Map workingVars ) { for ( String name : classNames ) { try { Class clazz = classForName( name ); cfg.addAnnotatedClass( clazz ); } catch (ClassNotFoundException cnfe) { Package pkg; try { pkg = classForName( name + ".package-info" ).getPackage(); } catch (ClassNotFoundException e) { pkg = null; } if (pkg == null) throw new PersistenceException(getExceptionHeader() + "class or package not found", cnfe); else cfg.addPackage(name); } } } public Ejb3Configuration addProperties(Properties props) { cfg.addProperties( props ); return this; } public Ejb3Configuration addAnnotatedClass(Class persistentClass) throws MappingException { Thread thread = null; ClassLoader contextClassLoader = null; if (overridenClassLoader != null) { thread = Thread.currentThread(); contextClassLoader = thread.getContextClassLoader(); thread.setContextClassLoader( overridenClassLoader ); } try { cfg.addAnnotatedClass( persistentClass ); return this; } finally { if (thread != null) thread.setContextClassLoader( contextClassLoader ); } } public Ejb3Configuration configure(String resource) throws HibernateException { //delay the call to configure to allow proper addition of all annotated classes (EJB-330) if (cfgXmlResource != null) throw new PersistenceException("configure(String) method already called for " + cfgXmlResource); this.cfgXmlResource = resource; return this; } public Ejb3Configuration addPackage(String packageName) throws MappingException { Thread thread = null; ClassLoader contextClassLoader = null; if (overridenClassLoader != null) { thread = Thread.currentThread(); contextClassLoader = thread.getContextClassLoader(); thread.setContextClassLoader( overridenClassLoader ); } try { cfg.addPackage( packageName ); return this; } finally { if (thread != null) thread.setContextClassLoader( contextClassLoader ); } } public Ejb3Configuration addFile(String xmlFile) throws MappingException { Thread thread = null; ClassLoader contextClassLoader = null; if (overridenClassLoader != null) { thread = Thread.currentThread(); contextClassLoader = thread.getContextClassLoader(); thread.setContextClassLoader( overridenClassLoader ); } try { cfg.addFile( xmlFile ); return this; } finally { if (thread != null) thread.setContextClassLoader( contextClassLoader ); } } public Ejb3Configuration addClass(Class persistentClass) throws MappingException { Thread thread = null; ClassLoader contextClassLoader = null; if (overridenClassLoader != null) { thread = Thread.currentThread(); contextClassLoader = thread.getContextClassLoader(); thread.setContextClassLoader( overridenClassLoader ); } try { cfg.addClass( persistentClass ); return this; } finally { if (thread != null) thread.setContextClassLoader( contextClassLoader ); } } public Ejb3Configuration addFile(File xmlFile) throws MappingException { Thread thread = null; ClassLoader contextClassLoader = null; if (overridenClassLoader != null) { thread = Thread.currentThread(); contextClassLoader = thread.getContextClassLoader(); thread.setContextClassLoader( overridenClassLoader ); } try { cfg.addFile( xmlFile ); return this; } finally { if (thread != null) thread.setContextClassLoader( contextClassLoader ); } } public void buildMappings() { Thread thread = null; ClassLoader contextClassLoader = null; if (overridenClassLoader != null) { thread = Thread.currentThread(); contextClassLoader = thread.getContextClassLoader(); thread.setContextClassLoader( overridenClassLoader ); } try { cfg.buildMappings(); } finally { if (thread != null) thread.setContextClassLoader( contextClassLoader ); } } public Iterator getClassMappings() { Thread thread = null; ClassLoader contextClassLoader = null; if (overridenClassLoader != null) { thread = Thread.currentThread(); contextClassLoader = thread.getContextClassLoader(); thread.setContextClassLoader( overridenClassLoader ); } try { return cfg.getClassMappings(); } finally { if (thread != null) thread.setContextClassLoader( contextClassLoader ); } } public Iterator getTableMappings() { return cfg.getTableMappings(); } public PersistentClass getClassMapping(String persistentClass) { return cfg.getClassMapping( persistentClass ); } public org.hibernate.mapping.Collection getCollectionMapping(String role) { return cfg.getCollectionMapping( role ); } public void setEntityResolver(EntityResolver entityResolver) { cfg.setEntityResolver( entityResolver ); } public Map getNamedQueries() { return cfg.getNamedQueries(); } public Interceptor getInterceptor() { return cfg.getInterceptor(); } public Properties getProperties() { return cfg.getProperties(); } public Ejb3Configuration setInterceptor(Interceptor interceptor) { cfg.setInterceptor( interceptor ); return this; } public Ejb3Configuration setProperties(Properties properties) { cfg.setProperties( properties ); return this; } public Map getFilterDefinitions() { return cfg.getFilterDefinitions(); } public void addFilterDefinition(FilterDefinition definition) { cfg.addFilterDefinition( definition ); } public void addAuxiliaryDatabaseObject(AuxiliaryDatabaseObject object) { cfg.addAuxiliaryDatabaseObject( object ); } public NamingStrategy getNamingStrategy() { return cfg.getNamingStrategy(); } public Ejb3Configuration setNamingStrategy(NamingStrategy namingStrategy) { cfg.setNamingStrategy( namingStrategy ); return this; } public Ejb3Configuration setSessionFactoryObserver(SessionFactoryObserver observer) { cfg.setSessionFactoryObserver( observer ); return this; } /** * This API is intended to give a read-only configuration. * It is sueful when working with SchemaExport or any Configuration based * tool. * DO NOT update configuration through it. */ public Configuration getHibernateConfiguration() { //TODO make it really read only (maybe through proxying) return cfg; } public Ejb3Configuration addInputStream(InputStream xmlInputStream) throws MappingException { Thread thread = null; ClassLoader contextClassLoader = null; if (overridenClassLoader != null) { thread = Thread.currentThread(); contextClassLoader = thread.getContextClassLoader(); thread.setContextClassLoader( overridenClassLoader ); } try { cfg.addInputStream( xmlInputStream ); return this; } finally { if (thread != null) thread.setContextClassLoader( contextClassLoader ); } } public Ejb3Configuration addResource(String path) throws MappingException { Thread thread = null; ClassLoader contextClassLoader = null; if (overridenClassLoader != null) { thread = Thread.currentThread(); contextClassLoader = thread.getContextClassLoader(); thread.setContextClassLoader( overridenClassLoader ); } try { cfg.addResource( path ); return this; } finally { if (thread != null) thread.setContextClassLoader( contextClassLoader ); } } public Ejb3Configuration addResource(String path, ClassLoader classLoader) throws MappingException { cfg.addResource( path, classLoader ); return this; } private enum XML_SEARCH { HBM, ORM_XML, BOTH, NONE; public static XML_SEARCH getType(boolean searchHbm, boolean searchOrm) { return searchHbm ? searchOrm ? XML_SEARCH.BOTH : XML_SEARCH.HBM : searchOrm ? XML_SEARCH.ORM_XML : XML_SEARCH.NONE; } } }