HHH-12872 Reduce memory consumption of XSD schema validations

This commit is contained in:
Sanne Grinovero 2018-07-30 14:17:43 +01:00 committed by Guillaume Smet
parent 7da105be0a
commit d67278a6d2
3 changed files with 106 additions and 51 deletions

View File

@ -6,74 +6,47 @@
*/
package org.hibernate.boot.xsd;
import org.jboss.logging.Logger;
/**
* Support for XSD handling related to Hibernate's `cfg.xml` and
* JPA's `persistence.xml`.
* The implementation attempts to not load XsdDescriptor instances which are not
* necessary and favours memory efficiency over CPU efficiency, as this is expected
* to be used only during bootstrap.
*
* @author Steve Ebersole
* @author Sanne Grinovero
*/
@SuppressWarnings("unused")
public class ConfigXsdSupport {
private static final Logger log = Logger.getLogger( ConfigXsdSupport.class );
/**
* Singleton access
* Needs synchronization on any access.
* Custom keys:
* 0: cfgXml
* 1: JPA 1.0
* 2: JPA 2.0
* 3: JPA 2.1
* 4: JPA 2.2
*/
public static final ConfigXsdSupport INSTANCE = new ConfigXsdSupport();
private ConfigXsdSupport() {
//Do not construct new instances
}
private final XsdDescriptor jpa10 = LocalXsdResolver.buildXsdDescriptor(
"org/hibernate/jpa/persistence_1_0.xsd",
"1.0",
"http://java.sun.com/xml/ns/persistence"
);
private final XsdDescriptor jpa20 = LocalXsdResolver.buildXsdDescriptor(
"org/hibernate/jpa/persistence_2_0.xsd",
"2.0" ,
"http://java.sun.com/xml/ns/persistence"
);
private final XsdDescriptor jpa21 = LocalXsdResolver.buildXsdDescriptor(
"org/hibernate/jpa/persistence_2_1.xsd",
"2.1",
"http://xmlns.jcp.org/xml/ns/persistence"
);
private final XsdDescriptor jpa22 = LocalXsdResolver.buildXsdDescriptor(
"org/hibernate/jpa/persistence_2_2.xsd",
"2.2" ,
"http://xmlns.jcp.org/xml/ns/persistence"
);
private final XsdDescriptor cfgXml = LocalXsdResolver.buildXsdDescriptor(
"org/hibernate/xsd/cfg/legacy-configuration-4.0.xsd",
"4.0" ,
"http://www.hibernate.org/xsd/orm/cfg"
);
private static final XsdDescriptor[] xsdCache = new XsdDescriptor[5];
public XsdDescriptor latestJpaDescriptor() {
return jpa22;
return getJPA22();
}
public XsdDescriptor jpaXsd(String version) {
switch ( version ) {
case "1.0": {
return jpa10;
return getJPA10();
}
case "2.0": {
return jpa20;
return getJPA20();
}
case "2.1": {
return jpa21;
return getJPA21();
}
case "2.2": {
return jpa22;
return getJPA22();
}
default: {
throw new IllegalArgumentException( "Unrecognized JPA persistence.xml XSD version : `" + version + "`" );
@ -82,6 +55,83 @@ public class ConfigXsdSupport {
}
public XsdDescriptor cfgXsd() {
return cfgXml;
final int index = 0;
synchronized ( xsdCache ) {
XsdDescriptor cfgXml = xsdCache[index];
if ( cfgXml == null ) {
cfgXml = LocalXsdResolver.buildXsdDescriptor(
"org/hibernate/xsd/cfg/legacy-configuration-4.0.xsd",
"4.0" ,
"http://www.hibernate.org/xsd/orm/cfg"
);
xsdCache[index] = cfgXml;
}
return cfgXml;
}
}
private XsdDescriptor getJPA10() {
final int index = 1;
synchronized ( xsdCache ) {
XsdDescriptor jpa10 = xsdCache[index];
if ( jpa10 == null ) {
jpa10 = LocalXsdResolver.buildXsdDescriptor(
"org/hibernate/jpa/persistence_1_0.xsd",
"1.0",
"http://java.sun.com/xml/ns/persistence"
);
xsdCache[index] = jpa10;
}
return jpa10;
}
}
private XsdDescriptor getJPA20() {
final int index = 2;
synchronized ( xsdCache ) {
XsdDescriptor jpa20 = xsdCache[index];
if ( jpa20 == null ) {
jpa20 = LocalXsdResolver.buildXsdDescriptor(
"org/hibernate/jpa/persistence_2_0.xsd",
"2.0" ,
"http://java.sun.com/xml/ns/persistence"
);
xsdCache[index] = jpa20;
}
return jpa20;
}
}
private XsdDescriptor getJPA21() {
final int index = 3;
synchronized ( xsdCache ) {
XsdDescriptor jpa21 = xsdCache[index];
if ( jpa21 == null ) {
jpa21 = LocalXsdResolver.buildXsdDescriptor(
"org/hibernate/jpa/persistence_2_1.xsd",
"2.1",
"http://xmlns.jcp.org/xml/ns/persistence"
);
xsdCache[index] = jpa21;
}
return jpa21;
}
}
private XsdDescriptor getJPA22() {
final int index = 4;
synchronized ( xsdCache ) {
XsdDescriptor jpa22 = xsdCache[index];
if ( jpa22 == null ) {
jpa22 = LocalXsdResolver.buildXsdDescriptor(
"org/hibernate/jpa/persistence_2_2.xsd",
"2.2",
"http://xmlns.jcp.org/xml/ns/persistence"
);
xsdCache[index] = jpa22;
}
return jpa22;
}
}
}

View File

@ -32,16 +32,21 @@ import org.xml.sax.SAXException;
*/
@SuppressWarnings("WeakerAccess")
public class LocalXsdResolver {
private static final Logger log = Logger.getLogger( LocalXsdResolver.class );
private static final List<String> VALID_JPA_VERSIONS = Arrays.asList( "1.0", "2.0", "2.1", "2.2" );
public static String latestJpaVerison() {
return "2.2";
}
public static boolean isValidJpaVersion(String version) {
return VALID_JPA_VERSIONS.contains( version );
switch ( version ) {
case "1.0":
case "2.0":
case "2.1":
case "2.2":
return true;
default:
return false;
}
}
public static URL resolveLocalXsdUrl(String resourceName) {
@ -98,7 +103,7 @@ public class LocalXsdResolver {
schemaStream.close();
}
catch ( IOException e ) {
log.debugf( "Problem closing schema stream [%s]", e.toString() );
Logger.getLogger( LocalXsdResolver.class ).debugf( "Problem closing schema stream [%s]", e.toString() );
}
}
}

View File

@ -464,7 +464,7 @@ public class PersistenceXmlParser {
// todo : add ability to disable validation...
final String version = document.getDocumentElement().getAttribute( "version" );
final Validator validator = ConfigXsdSupport.INSTANCE.jpaXsd( version ).getSchema().newValidator();
final Validator validator = new ConfigXsdSupport().jpaXsd( version ).getSchema().newValidator();
List<SAXException> errors = new ArrayList<>();
validator.setErrorHandler( new ErrorHandlerImpl( errors ) );