Prechádzať zdrojové kódy

improve PwmSetting parsing/caching performance

Jason Rivard 7 rokov pred
rodič
commit
aefb58a670

+ 150 - 153
server/src/main/java/password/pwm/config/PwmSetting.java

@@ -26,8 +26,6 @@ import org.jdom2.Attribute;
 import org.jdom2.Element;
 import password.pwm.config.value.PasswordValue;
 import password.pwm.config.value.ValueFactory;
-import password.pwm.error.PwmOperationalException;
-import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.i18n.Config;
 import password.pwm.util.LocaleHelper;
 import password.pwm.util.java.JavaHelper;
@@ -38,7 +36,6 @@ import password.pwm.util.macro.MacroMachine;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -1216,96 +1213,17 @@ public enum PwmSetting
     private final PwmSettingSyntax syntax;
     private final PwmSettingCategory category;
 
-    private static final Map<PwmSetting, List<TemplateSetAssociation>> DEFAULT_VALUES;
-    private static final Map<PwmSetting, Map<String, String>> OPTIONS;
-    private static final Map<PwmSetting, List<TemplateSetAssociation>> EXAMPLES;
-    private Collection<PwmSettingFlag> flags;
-    private Boolean required;
-    private Boolean hidden;
-    private Integer level;
-    private Pattern pattern;
-
-    static
-    {
-        final Map<PwmSetting, List<TemplateSetAssociation>> returnMap = new HashMap<>();
-        for ( final PwmSetting pwmSetting : PwmSetting.values() )
-        {
-            final List<TemplateSetAssociation> returnObj = new ArrayList<>();
-            final Element settingElement = PwmSettingXml.readSettingXml( pwmSetting );
-            final List<Element> defaultElements = settingElement.getChildren( PwmSettingXml.XML_ELEMENT_DEFAULT );
-            if ( pwmSetting.getSyntax() == PwmSettingSyntax.PASSWORD )
-            {
-                returnObj.add( new TemplateSetAssociation( new PasswordValue( null ), Collections.emptySet() ) );
-            }
-            else
-            {
-                for ( final Element defaultElement : defaultElements )
-                {
-                    final Set<PwmSettingTemplate> definedTemplates = PwmSettingXml.parseTemplateAttribute( defaultElement );
-                    final StoredValue storedValue = ValueFactory.fromXmlValues( pwmSetting, defaultElement, null );
-                    returnObj.add( new TemplateSetAssociation( storedValue, definedTemplates ) );
-                }
-            }
-            if ( returnObj.isEmpty() )
-            {
-                throw new IllegalStateException( "no default value for setting " + pwmSetting.getKey() );
-            }
-            returnMap.put( pwmSetting, returnObj );
-        }
-        DEFAULT_VALUES = Collections.unmodifiableMap( returnMap );
-    }
-
-    static
-    {
-        final Map<PwmSetting, Map<String, String>> returnObj = new HashMap<>();
-        for ( final PwmSetting pwmSetting : PwmSetting.values() )
-        {
-            final Map<String, String> returnList = new LinkedHashMap<>();
-            final Element settingElement = PwmSettingXml.readSettingXml( pwmSetting );
-            final Element optionsElement = settingElement.getChild( "options" );
-            if ( optionsElement != null )
-            {
-                final List<Element> optionElements = optionsElement.getChildren( "option" );
-                if ( optionElements != null )
-                {
-                    for ( final Element optionElement : optionElements )
-                    {
-                        if ( optionElement.getAttribute( "value" ) == null )
-                        {
-                            throw new IllegalStateException( "option element is missing 'value' attribute for key " + pwmSetting.getKey() );
-                        }
-                        returnList.put( optionElement.getAttribute( "value" ).getValue(), optionElement.getValue() );
-                    }
-                }
-            }
-            returnObj.put( pwmSetting, Collections.unmodifiableMap( returnList ) );
-        }
-        OPTIONS = Collections.unmodifiableMap( returnObj );
-    }
-
-    static
-    {
-        final Map<PwmSetting, List<TemplateSetAssociation>> returnMap = new HashMap<>();
-        for ( final PwmSetting pwmSetting : PwmSetting.values() )
-        {
-            final List<TemplateSetAssociation> returnObj = new ArrayList<>();
-            final MacroMachine macroMachine = MacroMachine.forStatic();
-            final Element settingElement = PwmSettingXml.readSettingXml( pwmSetting );
-            final List<Element> exampleElements = settingElement.getChildren( PwmSettingXml.XML_ELEMENT_EXAMPLE );
-            for ( final Element exampleElement : exampleElements )
-            {
-                final Set<PwmSettingTemplate> definedTemplates = PwmSettingXml.parseTemplateAttribute( exampleElement );
-                final String exampleString = macroMachine.expandMacros( exampleElement.getText() );
-                returnObj.add( new TemplateSetAssociation( exampleString, Collections.unmodifiableSet( definedTemplates ) ) );
-            }
-            if ( returnObj.isEmpty() )
-            {
-                returnObj.add( new TemplateSetAssociation( "", Collections.emptySet() ) );
-            }
-            returnMap.put( pwmSetting, Collections.unmodifiableList( returnObj ) );
-        }
-        EXAMPLES = Collections.unmodifiableMap( returnMap );
-    }
+    // cached values read from XML file
+    private JavaHelper.SimpleReference<List<TemplateSetAssociation>> defaultValues;
+    private JavaHelper.SimpleReference<List<TemplateSetAssociation>> examples;
+    private JavaHelper.SimpleReference<Map<String, String>> options;
+    private JavaHelper.SimpleReference<Collection<PwmSettingFlag>> flags;
+    private JavaHelper.SimpleReference<Map<PwmSettingProperty, String>> properties;
+    private JavaHelper.SimpleReference<Collection<LDAPPermissionInfo>> ldapPermissionInfos;
+    private JavaHelper.SimpleReference<Boolean> required;
+    private JavaHelper.SimpleReference<Boolean> hidden;
+    private JavaHelper.SimpleReference<Integer> level;
+    private JavaHelper.SimpleReference<Pattern> pattern;
 
     PwmSetting(
             final String key,
@@ -1338,18 +1256,45 @@ public enum PwmSetting
         return syntax;
     }
 
+    private List<TemplateSetAssociation> getDefaultValue()
+    {
+        if ( defaultValues == null )
+        {
+            final List<TemplateSetAssociation> returnObj = new ArrayList<>();
+            final Element settingElement = PwmSettingXml.readSettingXml( this );
+            final List<Element> defaultElements = settingElement.getChildren( PwmSettingXml.XML_ELEMENT_DEFAULT );
+            if ( this.getSyntax() == PwmSettingSyntax.PASSWORD )
+            {
+                returnObj.add( new TemplateSetAssociation( new PasswordValue( null ), Collections.emptySet() ) );
+            }
+            else
+            {
+                for ( final Element defaultElement : defaultElements )
+                {
+                    final Set<PwmSettingTemplate> definedTemplates = PwmSettingXml.parseTemplateAttribute( defaultElement );
+                    final StoredValue storedValue = ValueFactory.fromXmlValues( this, defaultElement, null );
+                    returnObj.add( new TemplateSetAssociation( storedValue, definedTemplates ) );
+                }
+            }
+            if ( returnObj.isEmpty() )
+            {
+                throw new IllegalStateException( "no default value for setting " + this.getKey() );
+            }
+            defaultValues = new JavaHelper.SimpleReference<>( Collections.unmodifiableList( returnObj ) );
+        }
+        return defaultValues.get();
+    }
+
     public StoredValue getDefaultValue( final PwmSettingTemplateSet templateSet )
-            throws PwmOperationalException, PwmUnrecoverableException
     {
-        final List<TemplateSetAssociation> defaultValues = DEFAULT_VALUES.get( this );
+        final List<TemplateSetAssociation> defaultValues = getDefaultValue();
         return ( StoredValue ) associationForTempleSet( defaultValues, templateSet ).getObject();
     }
 
     public Map<String, String> getDefaultValueDebugStrings( final Locale locale )
-            throws PwmOperationalException, PwmUnrecoverableException
     {
         final Map<String, String> returnObj = new LinkedHashMap<>();
-        for ( final TemplateSetAssociation templateSetAssociation : DEFAULT_VALUES.get( this ) )
+        for ( final TemplateSetAssociation templateSetAssociation : this.getDefaultValue() )
         {
             returnObj.put(
                     StringUtil.join( templateSetAssociation.getSettingTemplates(), "," ),
@@ -1361,36 +1306,63 @@ public enum PwmSetting
 
     public Map<String, String> getOptions( )
     {
-        return OPTIONS.get( this );
+        if ( options == null )
+        {
+            final Map<String, String> returnList = new LinkedHashMap<>();
+            final Element settingElement = PwmSettingXml.readSettingXml( this );
+            final Element optionsElement = settingElement.getChild( "options" );
+            if ( optionsElement != null )
+            {
+                final List<Element> optionElements = optionsElement.getChildren( "option" );
+                if ( optionElements != null )
+                {
+                    for ( final Element optionElement : optionElements )
+                    {
+                        if ( optionElement.getAttribute( "value" ) == null )
+                        {
+                            throw new IllegalStateException( "option element is missing 'value' attribute for key " + this.getKey() );
+                        }
+                        returnList.put( optionElement.getAttribute( "value" ).getValue(), optionElement.getValue() );
+                    }
+                }
+            }
+            options = new JavaHelper.SimpleReference<>( Collections.unmodifiableMap( returnList ) );
+        }
+
+        return options.get( );
     }
 
     public Map<PwmSettingProperty, String> getProperties( )
     {
-        final Map<PwmSettingProperty, String> properties = new LinkedHashMap<>();
-        final Element settingElement = PwmSettingXml.readSettingXml( this );
-        final Element propertiesElement = settingElement.getChild( "properties" );
-        if ( propertiesElement != null )
+        if ( properties == null )
         {
-            final List<Element> propertyElements = propertiesElement.getChildren( "property" );
-            if ( propertyElements != null )
+            final Map<PwmSettingProperty, String> newProps = new LinkedHashMap<>();
+            final Element settingElement = PwmSettingXml.readSettingXml( this );
+            final Element propertiesElement = settingElement.getChild( "properties" );
+            if ( propertiesElement != null )
             {
-                for ( final Element propertyElement : propertyElements )
+                final List<Element> propertyElements = propertiesElement.getChildren( "property" );
+                if ( propertyElements != null )
                 {
-                    if ( propertyElement.getAttributeValue( "key" ) == null )
+                    for ( final Element propertyElement : propertyElements )
                     {
-                        throw new IllegalStateException( "property element is missing 'key' attribute for value " + this.getKey() );
-                    }
-                    final PwmSettingProperty property = JavaHelper.readEnumFromString( PwmSettingProperty.class, null, propertyElement.getAttributeValue( "key" ) );
-                    if ( property == null )
-                    {
-                        throw new IllegalStateException( "property element has unknown 'key' attribute for value " + this.getKey() );
+                        if ( propertyElement.getAttributeValue( "key" ) == null )
+                        {
+                            throw new IllegalStateException( "property element is missing 'key' attribute for value " + this.getKey() );
+                        }
+                        final PwmSettingProperty property = JavaHelper.readEnumFromString( PwmSettingProperty.class, null, propertyElement.getAttributeValue( "key" ) );
+                        if ( property == null )
+                        {
+                            throw new IllegalStateException( "property element has unknown 'key' attribute for value " + this.getKey() );
+                        }
+                        newProps.put( property, propertyElement.getValue() );
                     }
-                    properties.put( property, propertyElement.getValue() );
                 }
             }
+            properties = new JavaHelper.SimpleReference<>( Collections.unmodifiableMap( newProps ) );
         }
 
-        return properties;
+        return properties.get();
     }
 
     public Collection<PwmSettingFlag> getFlags( )
@@ -1407,10 +1379,7 @@ public enum PwmSetting
                 try
                 {
                     final PwmSettingFlag flag = PwmSettingFlag.valueOf( value );
-                    if ( flag != null )
-                    {
-                        returnObj.add( flag );
-                    }
+                    returnObj.add( flag );
                 }
                 catch ( IllegalArgumentException e )
                 {
@@ -1418,38 +1387,43 @@ public enum PwmSetting
                 }
 
             }
-            flags = Collections.unmodifiableCollection( returnObj );
+            flags = new JavaHelper.SimpleReference<>( Collections.unmodifiableCollection( returnObj ) );
         }
-        return flags;
+        return flags.get();
     }
 
     public Collection<LDAPPermissionInfo> getLDAPPermissionInfo( )
     {
-        final Element settingElement = PwmSettingXml.readSettingXml( this );
-        final List<Element> permissionElements = settingElement.getChildren( PwmSettingXml.XML_ELEMENT_LDAP_PERMISSION );
-        final List<LDAPPermissionInfo> returnObj = new ArrayList<>();
-        if ( permissionElements != null )
+        if ( ldapPermissionInfos == null )
         {
-            for ( final Element permissionElement : permissionElements )
+            final Element settingElement = PwmSettingXml.readSettingXml( this );
+            final List<Element> permissionElements = settingElement.getChildren( PwmSettingXml.XML_ELEMENT_LDAP_PERMISSION );
+            final List<LDAPPermissionInfo> returnObj = new ArrayList<>();
+            if ( permissionElements != null )
             {
-                final LDAPPermissionInfo.Actor actor = JavaHelper.readEnumFromString(
-                        LDAPPermissionInfo.Actor.class,
-                        null,
-                        permissionElement.getAttributeValue( PwmSettingXml.XML_ATTRIBUTE_PERMISSION_ACTOR )
-                );
-                final LDAPPermissionInfo.Access type = JavaHelper.readEnumFromString(
-                        LDAPPermissionInfo.Access.class,
-                        null,
-                        permissionElement.getAttributeValue( PwmSettingXml.XML_ATTRIBUTE_PERMISSION_ACCESS )
-                );
-                if ( actor != null && type != null )
+                for ( final Element permissionElement : permissionElements )
                 {
-                    final LDAPPermissionInfo permissionInfo = new LDAPPermissionInfo( type, actor );
-                    returnObj.add( permissionInfo );
+                    final LDAPPermissionInfo.Actor actor = JavaHelper.readEnumFromString(
+                            LDAPPermissionInfo.Actor.class,
+                            null,
+                            permissionElement.getAttributeValue( PwmSettingXml.XML_ATTRIBUTE_PERMISSION_ACTOR )
+                    );
+                    final LDAPPermissionInfo.Access type = JavaHelper.readEnumFromString(
+                            LDAPPermissionInfo.Access.class,
+                            null,
+                            permissionElement.getAttributeValue( PwmSettingXml.XML_ATTRIBUTE_PERMISSION_ACCESS )
+                    );
+                    if ( actor != null && type != null )
+                    {
+                        final LDAPPermissionInfo permissionInfo = new LDAPPermissionInfo( type, actor );
+                        returnObj.add( permissionInfo );
+                    }
                 }
             }
+            ldapPermissionInfos = new JavaHelper.SimpleReference<>( Collections.unmodifiableList( returnObj ) );
         }
-        return Collections.unmodifiableList( returnObj );
+
+        return ldapPermissionInfos.get();
     }
 
     public String getLabel( final Locale locale )
@@ -1468,8 +1442,26 @@ public enum PwmSetting
 
     public String getExample( final PwmSettingTemplateSet template )
     {
-        final List<TemplateSetAssociation> examples = EXAMPLES.get( this );
-        return ( String ) associationForTempleSet( examples, template ).getObject();
+        if ( examples == null )
+        {
+            final List<TemplateSetAssociation> returnObj = new ArrayList<>();
+            final MacroMachine macroMachine = MacroMachine.forStatic();
+            final Element settingElement = PwmSettingXml.readSettingXml( this );
+            final List<Element> exampleElements = settingElement.getChildren( PwmSettingXml.XML_ELEMENT_EXAMPLE );
+            for ( final Element exampleElement : exampleElements )
+            {
+                final Set<PwmSettingTemplate> definedTemplates = PwmSettingXml.parseTemplateAttribute( exampleElement );
+                final String exampleString = macroMachine.expandMacros( exampleElement.getText() );
+                returnObj.add( new TemplateSetAssociation( exampleString, Collections.unmodifiableSet( definedTemplates ) ) );
+            }
+            if ( returnObj.isEmpty() )
+            {
+                returnObj.add( new TemplateSetAssociation( "", Collections.emptySet() ) );
+            }
+            examples = new JavaHelper.SimpleReference<>( Collections.unmodifiableList( returnObj ) );
+        }
+
+        return ( String ) associationForTempleSet( examples.get(), template ).getObject();
     }
 
     public boolean isRequired( )
@@ -1478,9 +1470,9 @@ public enum PwmSetting
         {
             final Element settingElement = PwmSettingXml.readSettingXml( this );
             final Attribute requiredAttribute = settingElement.getAttribute( "required" );
-            required = requiredAttribute != null && "true".equalsIgnoreCase( requiredAttribute.getValue() );
+            required = new JavaHelper.SimpleReference<>( requiredAttribute != null && "true".equalsIgnoreCase( requiredAttribute.getValue() ) );
         }
-        return required;
+        return required.get();
     }
 
     public boolean isHidden( )
@@ -1489,9 +1481,10 @@ public enum PwmSetting
         {
             final Element settingElement = PwmSettingXml.readSettingXml( this );
             final Attribute requiredAttribute = settingElement.getAttribute( "hidden" );
-            hidden = requiredAttribute != null && "true".equalsIgnoreCase( requiredAttribute.getValue() ) || this.getCategory().isHidden();
+            final boolean hidden = requiredAttribute != null && "true".equalsIgnoreCase( requiredAttribute.getValue() ) || this.getCategory().isHidden();
+            this.hidden = new JavaHelper.SimpleReference<>( hidden );
         }
-        return hidden;
+        return hidden.get();
     }
 
     public int getLevel( )
@@ -1500,9 +1493,9 @@ public enum PwmSetting
         {
             final Element settingElement = PwmSettingXml.readSettingXml( this );
             final Attribute levelAttribute = settingElement.getAttribute( "level" );
-            level = levelAttribute != null ? Integer.parseInt( levelAttribute.getValue() ) : 0;
+            level = new JavaHelper.SimpleReference<>( levelAttribute != null ? Integer.parseInt( levelAttribute.getValue() ) : 0 );
         }
-        return level;
+        return level.get();
     }
 
     public Pattern getRegExPattern( )
@@ -1515,7 +1508,7 @@ public enum PwmSetting
             {
                 try
                 {
-                    pattern = Pattern.compile( regexNode.getText() );
+                    pattern = new JavaHelper.SimpleReference<>( Pattern.compile( regexNode.getText() ) );
                 }
                 catch ( PatternSyntaxException e )
                 {
@@ -1526,10 +1519,11 @@ public enum PwmSetting
             }
             if ( pattern == null )
             {
-                pattern = Pattern.compile( ".*", Pattern.DOTALL );
+                pattern = new JavaHelper.SimpleReference<>( Pattern.compile( ".*", Pattern.DOTALL ) );
             }
         }
-        return pattern;
+
+        return pattern.get();
 
     }
 
@@ -1598,7 +1592,7 @@ public enum PwmSetting
         private final Object object;
         private final Set<PwmSettingTemplate> settingTemplates;
 
-        public TemplateSetAssociation( final Object association, final Set<PwmSettingTemplate> settingTemplates )
+        TemplateSetAssociation( final Object association, final Set<PwmSettingTemplate> settingTemplates )
         {
             this.object = association;
             this.settingTemplates = settingTemplates;
@@ -1609,13 +1603,16 @@ public enum PwmSetting
             return object;
         }
 
-        public Set<PwmSettingTemplate> getSettingTemplates( )
+        Set<PwmSettingTemplate> getSettingTemplates( )
         {
             return settingTemplates;
         }
     }
 
-    static TemplateSetAssociation associationForTempleSet( final List<TemplateSetAssociation> associationSets, final PwmSettingTemplateSet pwmSettingTemplate )
+    private static TemplateSetAssociation associationForTempleSet(
+            final List<TemplateSetAssociation> associationSets,
+            final PwmSettingTemplateSet pwmSettingTemplate
+    )
     {
         if ( associationSets == null || associationSets.isEmpty() )
         {

+ 29 - 34
server/src/main/java/password/pwm/config/PwmSettingCategory.java

@@ -25,13 +25,12 @@ package password.pwm.config;
 import org.jdom2.Attribute;
 import org.jdom2.Element;
 import password.pwm.i18n.Config;
-import password.pwm.i18n.PwmSetting;
 import password.pwm.util.LocaleHelper;
+import password.pwm.util.java.JavaHelper;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
@@ -181,12 +180,15 @@ public enum PwmSettingCategory
 
     INTERNAL( SETTINGS ),;
 
-    private final PwmSettingCategory parent;
-    private static final Map<PwmSettingCategory, password.pwm.config.PwmSetting> CACHE_PROFILE_SETTING = new HashMap<>();
+
     private static List<PwmSettingCategory> cachedSortedSettings;
 
-    private Integer level;
-    private Boolean hidden;
+    private final PwmSettingCategory parent;
+
+    private JavaHelper.SimpleReference<PwmSetting> profileSetting;
+    private JavaHelper.SimpleReference<Integer> level;
+    private JavaHelper.SimpleReference<Boolean> hidden;
+    private JavaHelper.SimpleReference<Boolean> isTopLevelProfile;
 
 
     PwmSettingCategory( final PwmSettingCategory parent )
@@ -206,11 +208,12 @@ public enum PwmSettingCategory
 
     public password.pwm.config.PwmSetting getProfileSetting( )
     {
-        if ( !CACHE_PROFILE_SETTING.containsKey( this ) )
+        if ( profileSetting == null )
         {
-            CACHE_PROFILE_SETTING.put( this, readProfileSettingFromXml( true ) );
+            final PwmSetting setting = readProfileSettingFromXml( true );
+            profileSetting = new JavaHelper.SimpleReference<>( setting );
         }
-        return CACHE_PROFILE_SETTING.get( this );
+        return profileSetting.get();
     }
 
     public boolean hasProfiles( )
@@ -220,19 +223,23 @@ public enum PwmSettingCategory
 
     public boolean isTopLevelProfile( )
     {
-        return readProfileSettingFromXml( false ) != null;
+        if ( isTopLevelProfile == null )
+        {
+            isTopLevelProfile = new JavaHelper.SimpleReference<>( readProfileSettingFromXml( false ) != null );
+        }
+        return isTopLevelProfile.get();
     }
 
     public String getLabel( final Locale locale )
     {
-        final String key = PwmSetting.CATEGORY_LABEL_PREFIX + this.getKey();
-        return LocaleHelper.getLocalizedMessage( locale, key, null, PwmSetting.class );
+        final String key = password.pwm.i18n.PwmSetting.CATEGORY_LABEL_PREFIX + this.getKey();
+        return LocaleHelper.getLocalizedMessage( locale, key, null, password.pwm.i18n.PwmSetting.class );
     }
 
     public String getDescription( final Locale locale )
     {
-        final String key = PwmSetting.CATEGORY_DESCRIPTION_PREFIX + this.getKey();
-        return LocaleHelper.getLocalizedMessage( locale, key, null, PwmSetting.class );
+        final String key = password.pwm.i18n.PwmSetting.CATEGORY_DESCRIPTION_PREFIX + this.getKey();
+        return LocaleHelper.getLocalizedMessage( locale, key, null, password.pwm.i18n.PwmSetting.class );
     }
 
     public int getLevel( )
@@ -241,9 +248,9 @@ public enum PwmSettingCategory
         {
             final Element settingElement = PwmSettingXml.readCategoryXml( this );
             final Attribute levelAttribute = settingElement.getAttribute( "level" );
-            level = levelAttribute != null ? Integer.parseInt( levelAttribute.getValue() ) : 0;
+            level = new JavaHelper.SimpleReference<>( levelAttribute != null ? Integer.parseInt( levelAttribute.getValue() ) : 0 );
         }
-        return level;
+        return level.get();
     }
 
     public boolean isHidden( )
@@ -254,7 +261,7 @@ public enum PwmSettingCategory
             final Attribute hiddenElement = settingElement.getAttribute( "hidden" );
             if ( hiddenElement != null && "true".equalsIgnoreCase( hiddenElement.getValue() ) )
             {
-                hidden = true;
+                hidden = new JavaHelper.SimpleReference<>( true );
             }
             else
             {
@@ -262,16 +269,16 @@ public enum PwmSettingCategory
                 {
                     if ( parentCategory.isHidden() )
                     {
-                        hidden = true;
+                        hidden = new JavaHelper.SimpleReference<>( true );
                     }
                 }
             }
             if ( hidden == null )
             {
-                hidden = false;
+                hidden = new JavaHelper.SimpleReference<>( false );
             }
         }
-        return hidden;
+        return hidden.get();
     }
 
     public boolean isTopCategory( )
@@ -304,19 +311,6 @@ public enum PwmSettingCategory
         return returnObj;
     }
 
-    public static Collection<PwmSettingCategory> topCategories( )
-    {
-        final ArrayList<PwmSettingCategory> returnObj = new ArrayList<>();
-        for ( final PwmSettingCategory category : values() )
-        {
-            if ( category.isTopCategory() )
-            {
-                returnObj.add( category );
-            }
-        }
-        return returnObj;
-    }
-
     private password.pwm.config.PwmSetting readProfileSettingFromXml( final boolean nested )
     {
         PwmSettingCategory nextCategory = this;
@@ -345,7 +339,7 @@ public enum PwmSettingCategory
         return null;
     }
 
-    public List<password.pwm.config.PwmSetting> getSettings( )
+    public List<PwmSetting> getSettings( )
     {
         final List<password.pwm.config.PwmSetting> returnList = new ArrayList<>();
         for ( final password.pwm.config.PwmSetting setting : password.pwm.config.PwmSetting.values() )
@@ -456,4 +450,5 @@ public enum PwmSettingCategory
 
         return Collections.unmodifiableCollection( returnValues );
     }
+
 }

+ 20 - 3
server/src/main/java/password/pwm/config/PwmSettingXml.java

@@ -28,7 +28,8 @@ import org.jdom2.JDOMException;
 import org.jdom2.input.SAXBuilder;
 import org.jdom2.xpath.XPathExpression;
 import org.jdom2.xpath.XPathFactory;
-import password.pwm.util.java.JavaHelper;
+import password.pwm.util.java.TimeDuration;
+import password.pwm.util.logging.PwmLogger;
 
 import javax.xml.XMLConstants;
 import javax.xml.transform.stream.StreamSource;
@@ -37,9 +38,11 @@ import javax.xml.validation.SchemaFactory;
 import javax.xml.validation.Validator;
 import java.io.IOException;
 import java.io.InputStream;
+import java.time.Instant;
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class PwmSettingXml
 {
@@ -54,8 +57,10 @@ public class PwmSettingXml
     public static final String XML_ATTRIBUTE_PERMISSION_ACCESS = "access";
     public static final String XML_ATTRIBUTE_TEMPLATE = "template";
 
+    private static final PwmLogger LOGGER = PwmLogger.forClass( PwmSettingXml.class );
 
     private static Document xmlDocCache;
+    private static final AtomicInteger LOAD_COUNTER = new AtomicInteger( 0 );
 
     private static Document readXml( )
     {
@@ -67,16 +72,28 @@ public class PwmSettingXml
             final SAXBuilder builder = new SAXBuilder();
             try
             {
+                final Instant startTime = Instant.now();
                 final Document newDoc = builder.build( inputStream );
+                final TimeDuration parseDuration = TimeDuration.fromCurrent( startTime );
+                LOGGER.trace( "parsed PwmSettingXml in " + parseDuration.toString() + ", loads=" + LOAD_COUNTER.getAndIncrement() );
+
                 xmlDocCache = newDoc;
 
                 // clear cached dom after 30 seconds.
-                final Thread t = new Thread( "PwmSettingXml static cache clear thread" )
+                final Thread t = new Thread( "PwmSettingXml static cache thread" )
                 {
                     @Override
                     public void run( )
                     {
-                        JavaHelper.pause( 30 * 1000 );
+                        try
+                        {
+                            Thread.sleep( 30_000 );
+                        }
+                        catch ( InterruptedException e )
+                        {
+                            //ignored
+                        }
+                        LOGGER.trace( "cached PwmSettingXml discarded" );
                         xmlDocCache = null;
                     }
                 };

+ 1 - 10
server/src/main/java/password/pwm/config/stored/StoredConfigurationImpl.java

@@ -411,16 +411,7 @@ public class StoredConfigurationImpl implements StoredConfiguration
 
     private static StoredValue defaultValue( final PwmSetting pwmSetting, final PwmSettingTemplateSet template )
     {
-        try
-        {
-            return pwmSetting.getDefaultValue( template );
-        }
-        catch ( PwmException e )
-        {
-            final String errorMsg = "error reading default value for setting " + pwmSetting.toString() + ", error: " + e.getErrorInformation().toDebugStr();
-            LOGGER.error( errorMsg, e );
-            throw new IllegalStateException( errorMsg );
-        }
+        return pwmSetting.getDefaultValue( template );
     }
 
     public PwmSettingTemplateSet getTemplateSet( )

+ 7 - 11
server/src/main/java/password/pwm/health/ConfigurationChecker.java

@@ -114,20 +114,16 @@ public class ConfigurationChecker implements HealthChecker
 
         final String siteUrl = config.readSettingAsString( PwmSetting.PWM_SITE_URL );
         final String separator = LocaleHelper.getLocalizedMessage( locale, Config.Display_SettingNavigationSeparator, null );
-        try
-        {
-            if ( siteUrl == null || siteUrl.isEmpty() || siteUrl.equals(
-                    PwmSetting.PWM_SITE_URL.getDefaultValue( config.getTemplate() ).toNativeObject() ) )
-            {
-                records.add(
-                        HealthRecord.forMessage( HealthMessage.Config_NoSiteURL, PwmSetting.PWM_SITE_URL.toMenuLocationDebug( null, locale ) ) );
-            }
-        }
-        catch ( PwmException e )
+
+        if ( siteUrl == null || siteUrl.isEmpty() || siteUrl.equals(
+                PwmSetting.PWM_SITE_URL.getDefaultValue( config.getTemplate() ).toNativeObject() ) )
         {
-            LOGGER.error( SessionLabel.HEALTH_SESSION_LABEL, "error while inspecting site URL setting: " + e.getMessage() );
+            records.add(
+                    HealthRecord.forMessage( HealthMessage.Config_NoSiteURL, PwmSetting.PWM_SITE_URL.toMenuLocationDebug( null, locale ) ) );
         }
 
+
+
         if ( config.readSettingAsBoolean( PwmSetting.LDAP_ENABLE_WIRE_TRACE ) )
         {
             records.add(

+ 6 - 13
server/src/main/java/password/pwm/util/LocaleHelper.java

@@ -34,7 +34,6 @@ import password.pwm.config.StoredValue;
 import password.pwm.config.value.ChallengeValue;
 import password.pwm.config.value.StringArrayValue;
 import password.pwm.config.value.data.ChallengeItemConfiguration;
-import password.pwm.error.PwmException;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.PwmRequest;
@@ -602,19 +601,13 @@ public class LocaleHelper
         private static List<Locale> knownLocales( )
         {
             final List<Locale> knownLocales = new ArrayList<>();
-            try
-            {
-                final StringArrayValue stringArrayValue = ( StringArrayValue ) PwmSetting.KNOWN_LOCALES.getDefaultValue( PwmSettingTemplateSet.getDefault() );
-                final List<String> rawValues = stringArrayValue.toNativeObject();
-                final Map<String, String> localeFlagMap = StringUtil.convertStringListToNameValuePair( rawValues, "::" );
-                for ( final String rawValue : localeFlagMap.keySet() )
-                {
-                    knownLocales.add( LocaleHelper.parseLocaleString( rawValue ) );
-                }
-            }
-            catch ( PwmException e )
+
+            final StringArrayValue stringArrayValue = ( StringArrayValue ) PwmSetting.KNOWN_LOCALES.getDefaultValue( PwmSettingTemplateSet.getDefault() );
+            final List<String> rawValues = stringArrayValue.toNativeObject();
+            final Map<String, String> localeFlagMap = StringUtil.convertStringListToNameValuePair( rawValues, "::" );
+            for ( final String rawValue : localeFlagMap.keySet() )
             {
-                throw new IllegalStateException( "error reading default locale list", e );
+                knownLocales.add( LocaleHelper.parseLocaleString( rawValue ) );
             }
 
             final Map<String, Locale> returnMap = new TreeMap<>();

+ 15 - 0
server/src/main/java/password/pwm/util/java/JavaHelper.java

@@ -621,4 +621,19 @@ public class JavaHelper
 
         return Optional.empty();
     }
+
+    public static class SimpleReference<T>
+    {
+        T reference;
+
+        public SimpleReference( final T reference )
+        {
+            this.reference = reference;
+        }
+
+        public T get( )
+        {
+            return reference;
+        }
+    }
 }

+ 4 - 11
server/src/main/java/password/pwm/util/java/XmlUtil.java

@@ -26,6 +26,7 @@ import lombok.Value;
 import org.jdom2.Document;
 import org.jdom2.Element;
 import org.jdom2.input.SAXBuilder;
+import org.jdom2.input.sax.XMLReaders;
 import org.jdom2.output.Format;
 import org.jdom2.output.XMLOutputter;
 import password.pwm.error.ErrorInformation;
@@ -82,26 +83,18 @@ public class XmlUtil
         format.setEncoding( STORAGE_CHARSET.toString() );
         final XMLOutputter outputter = new XMLOutputter();
         outputter.setFormat( format );
-        Writer writer = null;
-        try
+
+        try ( Writer writer = new OutputStreamWriter( outputStream, STORAGE_CHARSET ) )
         {
-            writer = new OutputStreamWriter( outputStream, STORAGE_CHARSET );
             outputter.output( document, writer );
         }
-        finally
-        {
-            if ( writer != null )
-            {
-                writer.close();
-            }
-        }
     }
 
     private static SAXBuilder getBuilder( )
     {
         final SAXBuilder builder = new SAXBuilder();
         builder.setExpandEntities( false );
-        builder.setValidation( false );
+        builder.setXMLReaderFactory( XMLReaders.NONVALIDATING );
         builder.setFeature( "http://xml.org/sax/features/resolve-dtd-uris", false );
         return builder;
     }