diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/EnversService.java b/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/EnversService.java
index 55ba23e1be..bdac75af98 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/EnversService.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/EnversService.java
@@ -17,7 +17,6 @@ import org.hibernate.envers.internal.revisioninfo.RevisionInfoNumberReader;
import org.hibernate.envers.internal.revisioninfo.RevisionInfoQueryCreator;
import org.hibernate.envers.internal.synchronization.AuditProcessManager;
import org.hibernate.envers.strategy.AuditStrategy;
-import org.hibernate.internal.util.xml.XMLHelper;
import org.hibernate.service.Service;
import org.hibernate.service.ServiceRegistry;
@@ -56,8 +55,6 @@ public interface EnversService extends Service {
void initialize(MetadataImplementor metadata, MappingCollector mappingCollector);
- XMLHelper getXmlHelper();
-
GlobalConfiguration getGlobalConfiguration();
AuditEntitiesConfiguration getAuditEntitiesConfiguration();
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/EnversServiceImpl.java b/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/EnversServiceImpl.java
index 7a9cf02bd8..8f68358a81 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/EnversServiceImpl.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/EnversServiceImpl.java
@@ -30,7 +30,6 @@ import org.hibernate.envers.internal.tools.ReflectionTools;
import org.hibernate.envers.strategy.AuditStrategy;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
-import org.hibernate.internal.util.xml.XMLHelper;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.Configurable;
import org.hibernate.service.spi.Stoppable;
@@ -74,8 +73,6 @@ public class EnversServiceImpl implements EnversService, Configurable, Stoppable
private RevisionInfoNumberReader revisionInfoNumberReader;
private ModifiedEntityNamesReader modifiedEntityNamesReader;
- private XMLHelper xmlHelper;
-
@Override
public void configure(Map configurationValues) {
if ( configurationValues.containsKey( LEGACY_AUTO_REGISTER ) ) {
@@ -111,7 +108,6 @@ public class EnversServiceImpl implements EnversService, Configurable, Stoppable
this.serviceRegistry = metadata.getMetadataBuildingOptions().getServiceRegistry();
this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
- this.xmlHelper = new XMLHelper();
doInitialize( metadata, mappingCollector, serviceRegistry );
}
@@ -186,11 +182,6 @@ public class EnversServiceImpl implements EnversService, Configurable, Stoppable
return strategy;
}
- @Override
- public XMLHelper getXmlHelper() {
- return xmlHelper;
- }
-
/**
* Load a class by name, preferring our ClassLoader and then the ClassLoaderService.
*
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/RevisionInfoConfiguration.java b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/RevisionInfoConfiguration.java
index e8b089ec29..97a7c0c35d 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/RevisionInfoConfiguration.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/RevisionInfoConfiguration.java
@@ -55,6 +55,8 @@ public class RevisionInfoConfiguration {
private Type revisionInfoTimestampType;
private GlobalConfiguration globalCfg;
+ private XMLHelper xmlHelper;
+
private String revisionPropType;
private String revisionPropSqlType;
@@ -75,7 +77,7 @@ public class RevisionInfoConfiguration {
}
private Document generateDefaultRevisionInfoXmlMapping() {
- final Document document = globalCfg.getEnversService().getXmlHelper().getDocumentFactory().createDocument();
+ final Document document = getXmlHelper().getDocumentFactory().createDocument();
final Element classMapping = MetadataTools.createEntity(
document,
@@ -120,6 +122,13 @@ public class RevisionInfoConfiguration {
return document;
}
+ private XMLHelper getXmlHelper() {
+ if ( this.xmlHelper == null ) {
+ this.xmlHelper = new XMLHelper();
+ }
+ return this.xmlHelper;
+ }
+
/**
* Generates mapping that represents a set of primitive types.
*
@@ -158,7 +167,7 @@ public class RevisionInfoConfiguration {
}
private Element generateRevisionInfoRelationMapping() {
- final Document document = globalCfg.getEnversService().getXmlHelper().getDocumentFactory().createDocument();
+ final Document document = getXmlHelper().getDocumentFactory().createDocument();
final Element revRelMapping = document.addElement( "key-many-to-one" );
revRelMapping.addAttribute( "type", revisionPropType );
revRelMapping.addAttribute( "class", revisionInfoEntityName );
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/XMLHelper.java b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/XMLHelper.java
new file mode 100644
index 0000000000..655d73602d
--- /dev/null
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/XMLHelper.java
@@ -0,0 +1,79 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or .
+ */
+package org.hibernate.envers.configuration.internal;
+
+import org.dom4j.DocumentFactory;
+import org.dom4j.io.SAXReader;
+import org.hibernate.internal.util.xml.ErrorLogger;
+import org.xml.sax.EntityResolver;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Small helper class that lazily loads DOM and SAX reader and keep them for fast use afterwards.
+ *
+ * This was part of Hibernate ORM core, but moved into the testsuite helpers to not expose
+ * access to the dom4j types. It's also used by Hibernate Envers, so we will need two copies
+ * until Envers is able to remove its reliance on dom4j.
+ * The rest of Hibernate uses StAX now for XML processing. See {@link org.hibernate.boot.jaxb.internal.stax}
+ */
+public final class XMLHelper {
+ private final DocumentFactory documentFactory;
+
+ public XMLHelper() {
+ PrivilegedAction action = new PrivilegedAction() {
+ public DocumentFactory run() {
+ final ClassLoader originalTccl = Thread.currentThread().getContextClassLoader();
+ try {
+ // We need to make sure we get DocumentFactory
+ // loaded from the same ClassLoader that loads
+ // Hibernate classes, to make sure we get the
+ // proper version of DocumentFactory, This class
+ // is "internal", and should only be used for XML
+ // files generated by Envers.
+
+ // Using the (Hibernate) ClassLoader that loads
+ // this Class will avoid collisions in the case
+ // that DocumentFactory can be loaded from,
+ // for example, the application ClassLoader.
+ Thread.currentThread().setContextClassLoader( this.getClass().getClassLoader() );
+ return DocumentFactory.getInstance();
+ }
+ finally {
+ Thread.currentThread().setContextClassLoader( originalTccl );
+ }
+ }
+ };
+
+ this.documentFactory = System.getSecurityManager() != null
+ ? AccessController.doPrivileged( action )
+ : action.run();
+ }
+
+ public DocumentFactory getDocumentFactory() {
+ return documentFactory;
+ }
+
+ public SAXReader createSAXReader(ErrorLogger errorLogger, EntityResolver entityResolver) {
+ SAXReader saxReader = new SAXReader();
+ try {
+ saxReader.setFeature( "http://apache.org/xml/features/nonvalidating/load-external-dtd", false );
+ saxReader.setFeature( "http://xml.org/sax/features/external-general-entities", false );
+ saxReader.setFeature( "http://xml.org/sax/features/external-parameter-entities", false );
+ }
+ catch (Exception e) {
+ throw new RuntimeException( e );
+ }
+ saxReader.setMergeAdjacentText( true );
+ saxReader.setValidation( true );
+ saxReader.setErrorHandler( errorLogger );
+ saxReader.setEntityResolver( entityResolver );
+
+ return saxReader;
+ }
+}