Explorar o código

xml refactoring and jdom removal

Jason Rivard %!s(int64=4) %!d(string=hai) anos
pai
achega
ab8c7fb4f3
Modificáronse 42 ficheiros con 411 adicións e 754 borrados
  1. 0 1
      build/checkstyle-import.xml
  2. 0 5
      data-service/pom.xml
  3. 0 5
      server/pom.xml
  4. 9 9
      server/src/main/java/password/pwm/config/PwmSettingCategory.java
  5. 34 34
      server/src/main/java/password/pwm/config/PwmSettingMetaDataReader.java
  6. 3 2
      server/src/main/java/password/pwm/config/PwmSettingTemplate.java
  7. 2 4
      server/src/main/java/password/pwm/config/PwmSettingXml.java
  8. 50 0
      server/src/main/java/password/pwm/config/stored/StoredConfigXmlConstants.java
  9. 83 110
      server/src/main/java/password/pwm/config/stored/StoredConfigXmlSerializer.java
  10. 2 2
      server/src/main/java/password/pwm/config/value/AbstractValue.java
  11. 12 12
      server/src/main/java/password/pwm/config/value/ActionValue.java
  12. 7 4
      server/src/main/java/password/pwm/config/value/BooleanValue.java
  13. 19 20
      server/src/main/java/password/pwm/config/value/ChallengeValue.java
  14. 1 5
      server/src/main/java/password/pwm/config/value/CustomLinkValue.java
  15. 3 7
      server/src/main/java/password/pwm/config/value/EmailValue.java
  16. 6 8
      server/src/main/java/password/pwm/config/value/FileValue.java
  17. 7 7
      server/src/main/java/password/pwm/config/value/FormValue.java
  18. 2 4
      server/src/main/java/password/pwm/config/value/LocalizedStringArrayValue.java
  19. 4 5
      server/src/main/java/password/pwm/config/value/LocalizedStringValue.java
  20. 14 11
      server/src/main/java/password/pwm/config/value/NamedSecretValue.java
  21. 5 3
      server/src/main/java/password/pwm/config/value/NumericArrayValue.java
  22. 9 8
      server/src/main/java/password/pwm/config/value/NumericValue.java
  23. 2 6
      server/src/main/java/password/pwm/config/value/OptionListValue.java
  24. 10 13
      server/src/main/java/password/pwm/config/value/PasswordValue.java
  25. 27 20
      server/src/main/java/password/pwm/config/value/PrivateKeyValue.java
  26. 6 9
      server/src/main/java/password/pwm/config/value/RemoteWebServiceValue.java
  27. 15 18
      server/src/main/java/password/pwm/config/value/StringArrayValue.java
  28. 3 3
      server/src/main/java/password/pwm/config/value/StringValue.java
  29. 10 8
      server/src/main/java/password/pwm/config/value/UserPermissionValue.java
  30. 8 5
      server/src/main/java/password/pwm/config/value/VerificationMethodValue.java
  31. 3 5
      server/src/main/java/password/pwm/config/value/X509CertificateValue.java
  32. 14 11
      server/src/main/java/password/pwm/svc/event/LdapXmlUserHistory.java
  33. 7 7
      server/src/main/java/password/pwm/util/java/LicenseInfoReader.java
  34. 1 59
      server/src/main/java/password/pwm/util/java/XmlDocument.java
  35. 10 186
      server/src/main/java/password/pwm/util/java/XmlElement.java
  36. 1 117
      server/src/main/java/password/pwm/util/java/XmlFactory.java
  37. 3 2
      server/src/main/java/password/pwm/util/logging/PwmLogManager.java
  38. 5 3
      server/src/test/java/password/pwm/config/PwmSettingTest.java
  39. 8 3
      server/src/test/java/password/pwm/config/PwmSettingXmlTest.java
  40. 2 2
      server/src/test/java/password/pwm/svc/event/LdapXmlUserHistoryTest.java
  41. 3 10
      server/src/test/java/password/pwm/util/java/XmlFactoryBenchmarkExtendedTest.java
  42. 1 1
      server/src/test/java/password/pwm/util/java/XmlFactoryTest.java

+ 0 - 1
build/checkstyle-import.xml

@@ -46,7 +46,6 @@
     <allow pkg="org.apache.commons.net.ftp"/>
     <allow pkg="org.apache.commons.net.ftp"/>
 
 
     <!-- xml -->
     <!-- xml -->
-    <allow pkg="org.jdom2"/>
     <allow pkg="javax.xml"/>
     <allow pkg="javax.xml"/>
     <allow pkg="org.w3c"/>
     <allow pkg="org.w3c"/>
     <allow pkg="org.xml"/>
     <allow pkg="org.xml"/>

+ 0 - 5
data-service/pom.xml

@@ -147,11 +147,6 @@
             <artifactId>log4j</artifactId>
             <artifactId>log4j</artifactId>
             <version>1.2.17</version>
             <version>1.2.17</version>
         </dependency>
         </dependency>
-        <dependency>
-            <groupId>org.jdom</groupId>
-            <artifactId>jdom2</artifactId>
-            <version>2.0.6</version>
-        </dependency>
         <dependency>
         <dependency>
             <groupId>com.google.code.gson</groupId>
             <groupId>com.google.code.gson</groupId>
             <artifactId>gson</artifactId>
             <artifactId>gson</artifactId>

+ 0 - 5
server/pom.xml

@@ -303,11 +303,6 @@
             <artifactId>jaxen</artifactId>
             <artifactId>jaxen</artifactId>
             <version>1.2.0</version>
             <version>1.2.0</version>
         </dependency>
         </dependency>
-        <dependency>
-            <groupId>org.jdom</groupId>
-            <artifactId>jdom2</artifactId>
-            <version>2.0.6</version>
-        </dependency>
         <dependency>
         <dependency>
             <groupId>org.xeustechnologies</groupId>
             <groupId>org.xeustechnologies</groupId>
             <artifactId>jcl-core</artifactId>
             <artifactId>jcl-core</artifactId>

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

@@ -25,7 +25,6 @@ import password.pwm.i18n.Config;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.LazySupplier;
 import password.pwm.util.java.LazySupplier;
-import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.macro.MacroRequest;
 
 
@@ -414,10 +413,10 @@ public enum PwmSettingCategory
                 final Optional<XmlElement> profileElement = categoryElement.getChild( "profile" );
                 final Optional<XmlElement> profileElement = categoryElement.getChild( "profile" );
                 if ( profileElement.isPresent() )
                 if ( profileElement.isPresent() )
                 {
                 {
-                    final String settingKey = profileElement.get().getAttributeValue( "setting" );
-                    if ( settingKey != null )
+                    final Optional<String> settingKey = profileElement.get().getAttributeValue( "setting" );
+                    if ( settingKey.isPresent() )
                     {
                     {
-                        return PwmSetting.forKey( settingKey );
+                        return PwmSetting.forKey( settingKey.get() );
                     }
                     }
                 }
                 }
                 if ( nested )
                 if ( nested )
@@ -436,8 +435,9 @@ public enum PwmSettingCategory
         private static int readLevel( final PwmSettingCategory category )
         private static int readLevel( final PwmSettingCategory category )
         {
         {
             final XmlElement settingElement = PwmSettingXml.readCategoryXml( category );
             final XmlElement settingElement = PwmSettingXml.readCategoryXml( category );
-            final String levelAttribute = settingElement.getAttributeValue( PwmSettingXml.XML_ELEMENT_LEVEL );
-            return levelAttribute != null ? Integer.parseInt( levelAttribute ) : 0;
+            return settingElement.getAttributeValue( PwmSettingXml.XML_ELEMENT_LEVEL )
+                    .map( ( value ) -> JavaHelper.silentParseInt( value, 0 ) )
+                    .orElse( 0 );
         }
         }
 
 
         private static PwmSettingScope readScope( final PwmSettingCategory category )
         private static PwmSettingScope readScope( final PwmSettingCategory category )
@@ -462,10 +462,10 @@ public enum PwmSettingCategory
             while ( nextCategory != null )
             while ( nextCategory != null )
             {
             {
                 final XmlElement settingElement = PwmSettingXml.readCategoryXml( category );
                 final XmlElement settingElement = PwmSettingXml.readCategoryXml( category );
-                final String attributeValue = settingElement.getAttributeValue( attribute );
-                if ( !StringUtil.isEmpty( attributeValue ) )
+                final Optional<String> attributeValue = settingElement.getAttributeValue( attribute );
+                if ( attributeValue.isPresent() )
                 {
                 {
-                    return attributeValue;
+                    return attributeValue.get();
                 }
                 }
                 nextCategory = nextCategory.getParent();
                 nextCategory = nextCategory.getParent();
             }
             }

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

@@ -174,7 +174,7 @@ public class PwmSettingMetaDataReader
             final List<XmlElement> flagElements = settingElement.getChildren( "flag" );
             final List<XmlElement> flagElements = settingElement.getChildren( "flag" );
             for ( final XmlElement flagElement : flagElements )
             for ( final XmlElement flagElement : flagElements )
             {
             {
-                final String value = flagElement.getTextTrim();
+                final String value = flagElement.getText().orElse( "" ).trim();
 
 
                 try
                 try
                 {
                 {
@@ -202,11 +202,10 @@ public class PwmSettingMetaDataReader
                 {
                 {
                     for ( final XmlElement optionElement : optionElements )
                     for ( final XmlElement optionElement : optionElements )
                     {
                     {
-                        if ( optionElement.getAttributeValue( PwmSettingXml.XML_ELEMENT_VALUE ) == null )
-                        {
-                            throw new IllegalStateException( "option element is missing 'value' attribute for key " + pwmSetting.getKey() );
-                        }
-                        returnList.put( optionElement.getAttributeValue( PwmSettingXml.XML_ELEMENT_VALUE ), optionElement.getText() );
+                        final String value = optionElement.getAttributeValue( PwmSettingXml.XML_ELEMENT_VALUE )
+                                .orElseThrow( () -> new IllegalStateException( "option element is missing 'value' attribute for key " + pwmSetting.getKey() ) );
+
+                        optionElement.getText().ifPresent( textValue ->  returnList.put( value, textValue ) );
                     }
                     }
                 }
                 }
             }
             }
@@ -225,11 +224,11 @@ public class PwmSettingMetaDataReader
                 {
                 {
                     final Optional<LDAPPermissionInfo.Actor> actor = JavaHelper.readEnumFromString(
                     final Optional<LDAPPermissionInfo.Actor> actor = JavaHelper.readEnumFromString(
                             LDAPPermissionInfo.Actor.class,
                             LDAPPermissionInfo.Actor.class,
-                            permissionElement.getAttributeValue( PwmSettingXml.XML_ATTRIBUTE_PERMISSION_ACTOR )
+                            permissionElement.getAttributeValue( PwmSettingXml.XML_ATTRIBUTE_PERMISSION_ACTOR ).orElse( "" )
                     );
                     );
                     final Optional<LDAPPermissionInfo.Access> type = JavaHelper.readEnumFromString(
                     final Optional<LDAPPermissionInfo.Access> type = JavaHelper.readEnumFromString(
                             LDAPPermissionInfo.Access.class,
                             LDAPPermissionInfo.Access.class,
-                            permissionElement.getAttributeValue( PwmSettingXml.XML_ATTRIBUTE_PERMISSION_ACCESS )
+                            permissionElement.getAttributeValue( PwmSettingXml.XML_ATTRIBUTE_PERMISSION_ACCESS ).orElse( "" )
                     );
                     );
                     if ( actor.isPresent() && type.isPresent() )
                     if ( actor.isPresent() && type.isPresent() )
                     {
                     {
@@ -250,8 +249,11 @@ public class PwmSettingMetaDataReader
             for ( final XmlElement exampleElement : exampleElements )
             for ( final XmlElement exampleElement : exampleElements )
             {
             {
                 final Set<PwmSettingTemplate> definedTemplates = PwmSettingXml.parseTemplateAttribute( exampleElement );
                 final Set<PwmSettingTemplate> definedTemplates = PwmSettingXml.parseTemplateAttribute( exampleElement );
-                final String exampleString = macroRequest.expandMacros( exampleElement.getText() );
-                returnObj.add( new PwmSetting.TemplateSetReference<>( exampleString, Collections.unmodifiableSet( definedTemplates ) ) );
+                exampleElement.getText().ifPresent( textValue ->
+                {
+                    final String exampleString = macroRequest.expandMacros( textValue );
+                    returnObj.add( new PwmSetting.TemplateSetReference<>( exampleString, Collections.unmodifiableSet( definedTemplates ) ) );
+                } );
             }
             }
             if ( returnObj.isEmpty() )
             if ( returnObj.isEmpty() )
             {
             {
@@ -272,19 +274,13 @@ public class PwmSettingMetaDataReader
                 {
                 {
                     for ( final XmlElement propertyElement : propertyElements )
                     for ( final XmlElement propertyElement : propertyElements )
                     {
                     {
-                        if ( propertyElement.getAttributeValue( PwmSettingXml.XML_ATTRIBUTE_KEY ) == null )
-                        {
-                            throw new IllegalStateException( "property element is missing 'key' attribute for value " + pwmSetting.getKey() );
-                        }
-                        final PwmSettingProperty property = JavaHelper.readEnumFromString(
-                                PwmSettingProperty.class,
-                                null,
-                                propertyElement.getAttributeValue( PwmSettingXml.XML_ATTRIBUTE_KEY ) );
-                        if ( property == null )
-                        {
-                            throw new IllegalStateException( "property element has unknown 'key' attribute for value " + pwmSetting.getKey() );
-                        }
-                        newProps.put( property, propertyElement.getText() );
+                        final String keyAttribute = propertyElement.getAttributeValue( PwmSettingXml.XML_ATTRIBUTE_KEY )
+                                .orElseThrow( () -> new IllegalStateException( "property element is missing 'key' attribute for value " + pwmSetting.getKey() ) );
+
+                        final PwmSettingProperty property = JavaHelper.readEnumFromString( PwmSettingProperty.class, keyAttribute )
+                                .orElseThrow( () -> new IllegalStateException( "property element has unknown 'key' attribute for value " + pwmSetting.getKey() ) );
+
+                        propertyElement.getText().ifPresent( value -> newProps.put( property, value ) );
                     }
                     }
                 }
                 }
             }
             }
@@ -320,21 +316,21 @@ public class PwmSettingMetaDataReader
         private static boolean readRequired( final PwmSetting pwmSetting )
         private static boolean readRequired( final PwmSetting pwmSetting )
         {
         {
             final XmlElement settingElement = PwmSettingXml.readSettingXml( pwmSetting );
             final XmlElement settingElement = PwmSettingXml.readSettingXml( pwmSetting );
-            final String requiredAttribute = settingElement.getAttributeValue( PwmSettingXml.XML_ELEMENT_REQUIRED );
+            final String requiredAttribute = settingElement.getAttributeValue( PwmSettingXml.XML_ELEMENT_REQUIRED ).orElse( "" );
             return "true".equalsIgnoreCase( requiredAttribute );
             return "true".equalsIgnoreCase( requiredAttribute );
         }
         }
 
 
         private static boolean readHidden( final PwmSetting pwmSetting )
         private static boolean readHidden( final PwmSetting pwmSetting )
         {
         {
             final XmlElement settingElement = PwmSettingXml.readSettingXml( pwmSetting );
             final XmlElement settingElement = PwmSettingXml.readSettingXml( pwmSetting );
-            final String requiredAttribute = settingElement.getAttributeValue( PwmSettingXml.XML_ELEMENT_HIDDEN );
+            final String requiredAttribute = settingElement.getAttributeValue( PwmSettingXml.XML_ELEMENT_HIDDEN ).orElse( "" );
             return "true".equalsIgnoreCase( requiredAttribute ) || pwmSetting.getCategory().isHidden();
             return "true".equalsIgnoreCase( requiredAttribute ) || pwmSetting.getCategory().isHidden();
         }
         }
 
 
         private static int readLevel( final PwmSetting pwmSetting )
         private static int readLevel( final PwmSetting pwmSetting )
         {
         {
             final XmlElement settingElement = PwmSettingXml.readSettingXml( pwmSetting );
             final XmlElement settingElement = PwmSettingXml.readSettingXml( pwmSetting );
-            final String levelAttribute = settingElement.getAttributeValue( PwmSettingXml.XML_ELEMENT_LEVEL );
+            final String levelAttribute = settingElement.getAttributeValue( PwmSettingXml.XML_ELEMENT_LEVEL ).orElse( "" );
             return JavaHelper.silentParseInt( levelAttribute, 0 );
             return JavaHelper.silentParseInt( levelAttribute, 0 );
         }
         }
 
 
@@ -344,15 +340,19 @@ public class PwmSettingMetaDataReader
             final Optional<XmlElement> regexNode = settingNode.getChild( PwmSettingXml.XML_ELEMENT_REGEX );
             final Optional<XmlElement> regexNode = settingNode.getChild( PwmSettingXml.XML_ELEMENT_REGEX );
             if ( regexNode.isPresent() )
             if ( regexNode.isPresent() )
             {
             {
-                try
+                final Optional<String> regexText = regexNode.get().getText();
+                if ( regexText.isPresent() )
                 {
                 {
-                    return Pattern.compile( regexNode.get().getText() );
-                }
-                catch ( final PatternSyntaxException e )
-                {
-                    final String errorMsg = "error compiling regex constraints for setting " + pwmSetting.toString() + ", error: " + e.getMessage();
-                    LOGGER.error( () -> errorMsg, e );
-                    throw new IllegalStateException( errorMsg, e );
+                    try
+                    {
+                        return Pattern.compile( regexText.get() );
+                    }
+                    catch ( final PatternSyntaxException e )
+                    {
+                        final String errorMsg = "error compiling regex constraints for setting " + pwmSetting.toString() + ", error: " + e.getMessage();
+                        LOGGER.error( () -> errorMsg, e );
+                        throw new IllegalStateException( errorMsg, e );
+                    }
                 }
                 }
             }
             }
             return Pattern.compile( ".*", Pattern.DOTALL );
             return Pattern.compile( ".*", Pattern.DOTALL );

+ 3 - 2
server/src/main/java/password/pwm/config/PwmSettingTemplate.java

@@ -25,6 +25,7 @@ import password.pwm.util.java.XmlElement;
 
 
 import java.util.EnumMap;
 import java.util.EnumMap;
 import java.util.Map;
 import java.util.Map;
+import java.util.Optional;
 
 
 public enum PwmSettingTemplate
 public enum PwmSettingTemplate
 {
 {
@@ -63,8 +64,8 @@ public enum PwmSettingTemplate
     public boolean isHidden( )
     public boolean isHidden( )
     {
     {
         final XmlElement templateElement = readTemplateElement( this );
         final XmlElement templateElement = readTemplateElement( this );
-        final String requiredAttribute = templateElement.getAttributeValue( "hidden" );
-        return requiredAttribute != null && "true".equalsIgnoreCase( requiredAttribute );
+        final Optional<String> requiredAttribute = templateElement.getAttributeValue( "hidden" );
+        return requiredAttribute.isPresent() && "true".equalsIgnoreCase( requiredAttribute.get() );
     }
     }
 
 
     private static XmlElement readTemplateElement( final PwmSettingTemplate pwmSettingTemplate )
     private static XmlElement readTemplateElement( final PwmSettingTemplate pwmSettingTemplate )

+ 2 - 4
server/src/main/java/password/pwm/config/PwmSettingXml.java

@@ -133,10 +133,8 @@ public class PwmSettingXml
         {
         {
             return Collections.emptySet();
             return Collections.emptySet();
         }
         }
-        final String templateStrValues = element.getAttributeValue( XML_ATTRIBUTE_TEMPLATE );
-        final String[] templateSplitValues = templateStrValues == null
-                ? new String[ 0 ]
-                : templateStrValues.split( "," );
+        final String templateStrValues = element.getAttributeValue( XML_ATTRIBUTE_TEMPLATE ).orElse( "" );
+        final String[] templateSplitValues = templateStrValues.split( "," );
         final Set<PwmSettingTemplate> definedTemplates = new LinkedHashSet<>();
         final Set<PwmSettingTemplate> definedTemplates = new LinkedHashSet<>();
         for ( final String templateStrValue : templateSplitValues )
         for ( final String templateStrValue : templateSplitValues )
         {
         {

+ 50 - 0
server/src/main/java/password/pwm/config/stored/StoredConfigXmlConstants.java

@@ -0,0 +1,50 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2020 The PWM Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package password.pwm.config.stored;
+
+public class StoredConfigXmlConstants
+{
+    public static final String XML_ATTRIBUTE_TYPE = "type";
+    public static final String XML_ELEMENT_ROOT = "PwmConfiguration";
+    public static final String XML_ELEMENT_PROPERTIES = "properties";
+    public static final String XML_ELEMENT_PROPERTY = "property";
+    public static final String XML_ELEMENT_SETTINGS = "settings";
+    public static final String XML_ELEMENT_SETTING = "setting";
+    public static final String XML_ELEMENT_DEFAULT = "default";
+    public static final String XML_ELEMENT_LOCALE_BUNDLE = "localeBundle";
+    public static final String XML_ELEMENT_LABEL = "label";
+    public static final String XML_ELEMENT_VALUE = "value";
+
+    public static final String XML_ATTRIBUTE_KEY = "key";
+    public static final String XML_ATTRIBUTE_SYNTAX = "syntax";
+    public static final String XML_ATTRIBUTE_PROFILE = "profile";
+    public static final String XML_ATTRIBUTE_VALUE_APP = "app";
+    public static final String XML_ATTRIBUTE_VALUE_CONFIG = "config";
+    public static final String XML_ATTRIBUTE_CREATE_TIME = "createTime";
+    public static final String XML_ATTRIBUTE_MODIFY_TIME = "modifyTime";
+    public static final String XML_ATTRIBUTE_MODIFY_USER = "modifyUser";
+    public static final String XML_ATTRIBUTE_SYNTAX_VERSION = "syntaxVersion";
+    public static final String XML_ATTRIBUTE_BUNDLE = "bundle";
+    public static final String XML_ATTRIBUTE_XML_VERSION = "xmlVersion";
+    public static final String XML_ATTRIBUTE_PWM_BUILD = "pwmBuild";
+    public static final String XML_ATTRIBUTE_PWM_VERSION = "pwmVersion";
+    public static final String XML_ATTRIBUTE_LOCALE = "locale";
+}

+ 83 - 110
server/src/main/java/password/pwm/config/stored/StoredConfigXmlSerializer.java

@@ -107,7 +107,7 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
             throws PwmUnrecoverableException, IOException
             throws PwmUnrecoverableException, IOException
     {
     {
         final XmlFactory xmlFactory = XmlFactory.getFactory();
         final XmlFactory xmlFactory = XmlFactory.getFactory();
-        final XmlDocument xmlDocument = xmlFactory.newDocument( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_ROOT );
+        final XmlDocument xmlDocument = xmlFactory.newDocument( StoredConfigXmlConstants.XML_ELEMENT_ROOT );
 
 
         XmlOutputHandler.makeXmlOutput( storedConfiguration, xmlDocument.getRootElement(), outputSettings );
         XmlOutputHandler.makeXmlOutput( storedConfiguration, xmlDocument.getRootElement(), outputSettings );
 
 
@@ -170,14 +170,13 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
             final List<StoredConfigData.ValueAndMetaCarrier> valueAndMetaWrapper = new ArrayList<>();
             final List<StoredConfigData.ValueAndMetaCarrier> valueAndMetaWrapper = new ArrayList<>();
             for ( final ConfigurationProperty configurationProperty : ConfigurationProperty.values() )
             for ( final ConfigurationProperty configurationProperty : ConfigurationProperty.values() )
             {
             {
-                final Optional<XmlElement> propertyElement = xpathForConfigProperty( configurationProperty );
-                if ( propertyElement.isPresent() && !StringUtil.isEmpty( propertyElement.get().getText() ) )
+                xpathForConfigProperty( configurationProperty ).ifPresent( propertyElement -> propertyElement.getText().ifPresent( propertyText ->
                 {
                 {
                     final StoredConfigItemKey key = StoredConfigItemKey.fromConfigurationProperty( configurationProperty );
                     final StoredConfigItemKey key = StoredConfigItemKey.fromConfigurationProperty( configurationProperty );
-                    final StoredValue storedValue = new StringValue( propertyElement.get().getText() );
-                    final ValueMetaData metaData = readMetaDataFromXmlElement( key, propertyElement.get() ).orElse( null );
+                    final StoredValue storedValue = new StringValue( propertyText );
+                    final ValueMetaData metaData = readMetaDataFromXmlElement( key, propertyElement ).orElse( null );
                     valueAndMetaWrapper.add( new StoredConfigData.ValueAndMetaCarrier( key, storedValue, metaData ) );
                     valueAndMetaWrapper.add( new StoredConfigData.ValueAndMetaCarrier( key, storedValue, metaData ) );
-                }
+                } ) );
             }
             }
             perfLog( "startReadProperties", startReadProperties );
             perfLog( "startReadProperties", startReadProperties );
             return valueAndMetaWrapper;
             return valueAndMetaWrapper;
@@ -212,21 +211,25 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
 
 
         Optional<StoredConfigData.ValueAndMetaCarrier> readSetting( final XmlElement settingElement )
         Optional<StoredConfigData.ValueAndMetaCarrier> readSetting( final XmlElement settingElement )
         {
         {
-            final String settingKey = settingElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_KEY );
-            final String profileID = settingElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_PROFILE );
-            final Optional<PwmSetting> optionalPwmSetting = PwmSetting.forKey( settingKey );
-            if ( optionalPwmSetting.isPresent() )
+            final Optional<String> settingKey = settingElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_KEY );
+            final Optional<String> profileID = settingElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_PROFILE );
+
+            if ( settingKey.isPresent() )
             {
             {
-                final PwmSetting pwmSetting = optionalPwmSetting.get();
-                final boolean defaultValueSaved = settingElement.getChild( StoredConfigXmlConstants.XML_ELEMENT_DEFAULT ).isPresent();
-                final StoredConfigItemKey key = StoredConfigItemKey.fromSetting( pwmSetting, profileID );
-                final ValueMetaData metaData = readMetaDataFromXmlElement( key, settingElement ).orElse( null );
+                final Optional<PwmSetting> optionalPwmSetting = PwmSetting.forKey( settingKey.get() );
+                if ( optionalPwmSetting.isPresent() )
+                {
+                    final PwmSetting pwmSetting = optionalPwmSetting.get();
+                    final boolean defaultValueSaved = settingElement.getChild( StoredConfigXmlConstants.XML_ELEMENT_DEFAULT ).isPresent();
+                    final StoredConfigItemKey key = StoredConfigItemKey.fromSetting( pwmSetting, profileID.orElse( null ) );
+                    final ValueMetaData metaData = readMetaDataFromXmlElement( key, settingElement ).orElse( null );
 
 
-                final StoredValue storedValue = defaultValueSaved
-                        ? null
-                        : ValueFactory.fromXmlValues( pwmSetting, settingElement, pwmSecurityKey );
+                    final StoredValue storedValue = defaultValueSaved
+                            ? null
+                            : ValueFactory.fromXmlValues( pwmSetting, settingElement, pwmSecurityKey );
 
 
-                return Optional.of( new StoredConfigData.ValueAndMetaCarrier( key, storedValue, metaData ) );
+                    return Optional.of( new StoredConfigData.ValueAndMetaCarrier( key, storedValue, metaData ) );
+                }
             }
             }
 
 
             return Optional.empty();
             return Optional.empty();
@@ -240,26 +243,19 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
         String readCreateTime()
         String readCreateTime()
         {
         {
             final XmlElement rootElement = document.getRootElement();
             final XmlElement rootElement = document.getRootElement();
-            final String createTimeString = rootElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_CREATE_TIME );
-            if ( StringUtil.isEmpty( createTimeString ) )
-            {
-                throw new IllegalStateException( "missing createTime timestamp" );
-            }
-            else
-            {
-                return createTimeString;
-            }
+            return rootElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_CREATE_TIME )
+                    .orElseThrow( () -> new IllegalStateException( "missing createTime timestamp" ) );
         }
         }
 
 
         Instant readModifyTime()
         Instant readModifyTime()
         {
         {
             final XmlElement rootElement = document.getRootElement();
             final XmlElement rootElement = document.getRootElement();
-            final String modifyTimeString = rootElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_MODIFY_TIME );
-            if ( !StringUtil.isEmpty( modifyTimeString ) )
+            final Optional<String> modifyTimeString = rootElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_MODIFY_TIME );
+            if ( modifyTimeString.isPresent() )
             {
             {
                 try
                 try
                 {
                 {
-                    return JavaHelper.parseIsoToInstant( modifyTimeString );
+                    return JavaHelper.parseIsoToInstant( modifyTimeString.get() );
                 }
                 }
                 catch ( final Exception e )
                 catch ( final Exception e )
                 {
                 {
@@ -302,25 +298,31 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
             final Instant startReadLocaleBundles = Instant.now();
             final Instant startReadLocaleBundles = Instant.now();
             final Function<XmlElement, Stream<StoredConfigData.ValueAndMetaCarrier>> xmlToLocaleBundleReader = xmlElement ->
             final Function<XmlElement, Stream<StoredConfigData.ValueAndMetaCarrier>> xmlToLocaleBundleReader = xmlElement ->
             {
             {
-                final String bundleName = xmlElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_BUNDLE );
-                final Optional<PwmLocaleBundle> pwmLocaleBundle = PwmLocaleBundle.forKey( bundleName );
-                if ( pwmLocaleBundle.isPresent() )
+                final Optional<String> bundleName = xmlElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_BUNDLE );
+                if ( bundleName.isPresent() )
                 {
                 {
-                    final String key = xmlElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_KEY );
-                    if ( pwmLocaleBundle.get().getDisplayKeys().contains( key ) )
+                    final Optional<PwmLocaleBundle> pwmLocaleBundle = PwmLocaleBundle.forKey( bundleName.get() );
+                    if ( pwmLocaleBundle.isPresent() )
                     {
                     {
-                        final Map<String, String> bundleMap = new LinkedHashMap<>();
-                        for ( final XmlElement valueElement : xmlElement.getChildren( StoredConfigXmlConstants.XML_ELEMENT_VALUE ) )
+                        final Optional<String> key = xmlElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_KEY );
+                        if ( key.isPresent() )
                         {
                         {
-                            final String localeStrValue = valueElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_LOCALE );
-                            bundleMap.put( localeStrValue == null ? "" : localeStrValue, valueElement.getText() );
-                        }
-                        if ( !bundleMap.isEmpty() )
-                        {
-                            final StoredConfigItemKey storedConfigItemKey = StoredConfigItemKey.fromLocaleBundle( pwmLocaleBundle.get(), key );
-                            final StoredValue storedValue = new LocalizedStringValue( bundleMap );
-                            final ValueMetaData metaData = readMetaDataFromXmlElement( storedConfigItemKey, xmlElement ).orElse( null );
-                            return Stream.of( new StoredConfigData.ValueAndMetaCarrier( storedConfigItemKey, storedValue, metaData ) );
+                            if ( pwmLocaleBundle.get().getDisplayKeys().contains( key.get() ) )
+                            {
+                                final Map<String, String> bundleMap = new LinkedHashMap<>();
+                                for ( final XmlElement valueElement : xmlElement.getChildren( StoredConfigXmlConstants.XML_ELEMENT_VALUE ) )
+                                {
+                                    final String localeStrValue = valueElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_LOCALE ).orElse( "" );
+                                    valueElement.getText().ifPresent( text -> bundleMap.put( localeStrValue, text ) );
+                                }
+                                if ( !bundleMap.isEmpty() )
+                                {
+                                    final StoredConfigItemKey storedConfigItemKey = StoredConfigItemKey.fromLocaleBundle( pwmLocaleBundle.get(), key.get() );
+                                    final StoredValue storedValue = new LocalizedStringValue( bundleMap );
+                                    final ValueMetaData metaData = readMetaDataFromXmlElement( storedConfigItemKey, xmlElement ).orElse( null );
+                                    return Stream.of( new StoredConfigData.ValueAndMetaCarrier( storedConfigItemKey, storedValue, metaData ) );
+                                }
+                            }
                         }
                         }
                     }
                     }
                 }
                 }
@@ -340,28 +342,28 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
         {
         {
             Instant instant = null;
             Instant instant = null;
             {
             {
-                final String modifyTimeValue = xmlElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_MODIFY_TIME );
-                if ( !StringUtil.isEmpty( modifyTimeValue ) )
+                final Optional<String> modifyTimeValue = xmlElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_MODIFY_TIME );
+                if ( modifyTimeValue.isPresent() )
                 {
                 {
                     try
                     try
                     {
                     {
-                        instant = JavaHelper.parseIsoToInstant( modifyTimeValue );
+                        instant = JavaHelper.parseIsoToInstant( modifyTimeValue.get() );
                     }
                     }
                     catch ( final DateTimeParseException e )
                     catch ( final DateTimeParseException e )
                     {
                     {
-                        e.printStackTrace();
+                        LOGGER.warn( () -> "error parsing modifyTime for key '" + key.toString() + "', error: " + e.getMessage() );
                     }
                     }
                 }
                 }
             }
             }
 
 
             UserIdentity userIdentity = null;
             UserIdentity userIdentity = null;
             {
             {
-                final String modifyUserValue = xmlElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_MODIFY_USER );
-                if ( !StringUtil.isEmpty( modifyUserValue ) )
+                final Optional<String> modifyUserValue = xmlElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_MODIFY_USER );
+                if ( modifyUserValue.isPresent() )
                 {
                 {
                     try
                     try
                     {
                     {
-                        userIdentity = UserIdentity.fromDelimitedKey( modifyUserValue );
+                        userIdentity = UserIdentity.fromDelimitedKey( modifyUserValue.get() );
                     }
                     }
                     catch ( final DateTimeParseException | PwmUnrecoverableException e )
                     catch ( final DateTimeParseException | PwmUnrecoverableException e )
                     {
                     {
@@ -644,35 +646,6 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
         }
         }
     }
     }
 
 
-    public static class StoredConfigXmlConstants
-    {
-        public static final String XML_ATTRIBUTE_TYPE = "type";
-        public static final String XML_ELEMENT_ROOT = "PwmConfiguration";
-        public static final String XML_ELEMENT_PROPERTIES = "properties";
-        public static final String XML_ELEMENT_PROPERTY = "property";
-        public static final String XML_ELEMENT_SETTINGS = "settings";
-        public static final String XML_ELEMENT_SETTING = "setting";
-        public static final String XML_ELEMENT_DEFAULT = "default";
-        public static final String XML_ELEMENT_LOCALE_BUNDLE = "localeBundle";
-        public static final String XML_ELEMENT_LABEL = "label";
-        public static final String XML_ELEMENT_VALUE = "value";
-
-        public static final String XML_ATTRIBUTE_KEY = "key";
-        public static final String XML_ATTRIBUTE_SYNTAX = "syntax";
-        public static final String XML_ATTRIBUTE_PROFILE = "profile";
-        public static final String XML_ATTRIBUTE_VALUE_APP = "app";
-        public static final String XML_ATTRIBUTE_VALUE_CONFIG = "config";
-        public static final String XML_ATTRIBUTE_CREATE_TIME = "createTime";
-        public static final String XML_ATTRIBUTE_MODIFY_TIME = "modifyTime";
-        public static final String XML_ATTRIBUTE_MODIFY_USER = "modifyUser";
-        public static final String XML_ATTRIBUTE_SYNTAX_VERSION = "syntaxVersion";
-        public static final String XML_ATTRIBUTE_BUNDLE = "bundle";
-        public static final String XML_ATTRIBUTE_XML_VERSION = "xmlVersion";
-        public static final String XML_ATTRIBUTE_PWM_BUILD = "pwmBuild";
-        public static final String XML_ATTRIBUTE_PWM_VERSION = "pwmVersion";
-        public static final String XML_ATTRIBUTE_LOCALE = "locale";
-    }
-
     static class XmlCleaner
     static class XmlCleaner
     {
     {
         private static final List<PwmExceptionLoggingConsumer<XmlDocument>> XML_PRE_PROCESSORS = List.of(
         private static final List<PwmExceptionLoggingConsumer<XmlDocument>> XML_PRE_PROCESSORS = List.of(
@@ -705,20 +678,20 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
                 }
                 }
 
 
                 final List<XmlElement> settingElements = xmlDocument.evaluateXpathToElements( "//"
                 final List<XmlElement> settingElements = xmlDocument.evaluateXpathToElements( "//"
-                        + StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_SETTING );
+                        + StoredConfigXmlConstants.XML_ELEMENT_SETTING );
                 for ( final XmlElement settingElement : settingElements )
                 for ( final XmlElement settingElement : settingElements )
                 {
                 {
-                    final Optional<XmlElement> valueElement = settingElement.getChild( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
-                    final Optional<XmlElement> defaultElement = settingElement.getChild( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_DEFAULT );
+                    final Optional<XmlElement> valueElement = settingElement.getChild( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+                    final Optional<XmlElement> defaultElement = settingElement.getChild( StoredConfigXmlConstants.XML_ELEMENT_DEFAULT );
                     if ( valueElement.isPresent() && defaultElement.isPresent() )
                     if ( valueElement.isPresent() && defaultElement.isPresent() )
                     {
                     {
-                        final String textValue = settingElement.getTextTrim();
-                        if ( !StringUtil.isEmpty( textValue ) )
+                        final Optional<String> textValue = settingElement.getText();
+                        if ( textValue.isPresent() )
                         {
                         {
-                            final XmlElement newValueElement = XmlFactory.getFactory().newElement( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
-                            newValueElement.addText( textValue );
+                            final XmlElement newValueElement = XmlFactory.getFactory().newElement( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+                            newValueElement.addText( textValue.get().trim() );
                             settingElement.addContent( newValueElement );
                             settingElement.addContent( newValueElement );
-                            final String key = settingElement.getAttributeValue( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_KEY );
+                            final String key = settingElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_KEY ).orElse( "" );
                             LOGGER.info( () -> "migrating pre-xml 'value' tag format to use value element for key: " + key );
                             LOGGER.info( () -> "migrating pre-xml 'value' tag format to use value element for key: " + key );
                         }
                         }
                     }
                     }
@@ -732,15 +705,15 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
             public void accept( final XmlDocument xmlDocument )
             public void accept( final XmlDocument xmlDocument )
             {
             {
                 // read correct (new) //properties[@type="config"]
                 // read correct (new) //properties[@type="config"]
-                final String configPropertiesXpath = "//" + StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_PROPERTIES
-                        + "[@" + StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_TYPE + "=\""
-                        + StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_VALUE_CONFIG + "\"]";
+                final String configPropertiesXpath = "//" + StoredConfigXmlConstants.XML_ELEMENT_PROPERTIES
+                        + "[@" + StoredConfigXmlConstants.XML_ATTRIBUTE_TYPE + "=\""
+                        + StoredConfigXmlConstants.XML_ATTRIBUTE_VALUE_CONFIG + "\"]";
                 final Optional<XmlElement> configPropertiesElement = xmlDocument.evaluateXpathToElement( configPropertiesXpath );
                 final Optional<XmlElement> configPropertiesElement = xmlDocument.evaluateXpathToElement( configPropertiesXpath );
 
 
                 // read list of old //properties[not (@type)]/property
                 // read list of old //properties[not (@type)]/property
-                final String nonAttributedPropertyXpath = "//" + StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_PROPERTIES
-                        + "[not (@" + StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_TYPE + ")]/"
-                        + StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_PROPERTY;
+                final String nonAttributedPropertyXpath = "//" + StoredConfigXmlConstants.XML_ELEMENT_PROPERTIES
+                        + "[not (@" + StoredConfigXmlConstants.XML_ATTRIBUTE_TYPE + ")]/"
+                        + StoredConfigXmlConstants.XML_ELEMENT_PROPERTY;
                 final List<XmlElement> nonAttributedProperties = xmlDocument.evaluateXpathToElements( nonAttributedPropertyXpath );
                 final List<XmlElement> nonAttributedProperties = xmlDocument.evaluateXpathToElements( nonAttributedPropertyXpath );
 
 
                 if ( configPropertiesElement.isPresent() && nonAttributedProperties != null )
                 if ( configPropertiesElement.isPresent() && nonAttributedProperties != null )
@@ -753,8 +726,8 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
                 }
                 }
 
 
                 // remove old //properties[not (@type] element
                 // remove old //properties[not (@type] element
-                final String oldPropertiesXpath = "//" + StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_PROPERTIES
-                        + "[not (@" + StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_TYPE + ")]";
+                final String oldPropertiesXpath = "//" + StoredConfigXmlConstants.XML_ELEMENT_PROPERTIES
+                        + "[not (@" + StoredConfigXmlConstants.XML_ATTRIBUTE_TYPE + ")]";
                 final List<XmlElement> oldPropertiesElements = xmlDocument.evaluateXpathToElements( oldPropertiesXpath );
                 final List<XmlElement> oldPropertiesElements = xmlDocument.evaluateXpathToElements( oldPropertiesXpath );
                 if ( oldPropertiesElements != null )
                 if ( oldPropertiesElements != null )
                 {
                 {
@@ -776,7 +749,7 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
                     final List<XmlElement> propertyElement = xmlDocument.evaluateXpathToElements( xpathString );
                     final List<XmlElement> propertyElement = xmlDocument.evaluateXpathToElements( xpathString );
                     if ( propertyElement != null && !propertyElement.isEmpty() )
                     if ( propertyElement != null && !propertyElement.isEmpty() )
                     {
                     {
-                        final String value = propertyElement.get( 0 ).getText();
+                        final String value = propertyElement.get( 0 ).getText().orElse( "" );
                         propertyElement.get( 0 ).detach();
                         propertyElement.get( 0 ).detach();
                         attachStringSettingElement( xmlDocument, PwmSetting.TEMPLATE_LDAP, value );
                         attachStringSettingElement( xmlDocument, PwmSetting.TEMPLATE_LDAP, value );
 
 
@@ -787,7 +760,7 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
                     final List<XmlElement> propertyElement = xmlDocument.evaluateXpathToElements( xpathString );
                     final List<XmlElement> propertyElement = xmlDocument.evaluateXpathToElements( xpathString );
                     if ( propertyElement != null && !propertyElement.isEmpty() )
                     if ( propertyElement != null && !propertyElement.isEmpty() )
                     {
                     {
-                        final String value = propertyElement.get( 0 ).getText();
+                        final String value = propertyElement.get( 0 ).getText().orElse( "" );
                         propertyElement.get( 0 ).detach();
                         propertyElement.get( 0 ).detach();
                         attachStringSettingElement( xmlDocument, PwmSetting.NOTES, value );
                         attachStringSettingElement( xmlDocument, PwmSetting.NOTES, value );
                     }
                     }
@@ -811,7 +784,7 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
                         null,
                         null,
                         new StringValue( stringValue ),
                         new StringValue( stringValue ),
                         XmlOutputProcessData.builder().storedValueEncoderMode( StoredValueEncoder.Mode.PLAIN ).pwmSecurityKey( pwmSecurityKey ).build() );
                         XmlOutputProcessData.builder().storedValueEncoderMode( StoredValueEncoder.Mode.PLAIN ).pwmSecurityKey( pwmSecurityKey ).build() );
-                final Optional<XmlElement> settingsElement = xmlDocument.getRootElement().getChild( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_SETTING );
+                final Optional<XmlElement> settingsElement = xmlDocument.getRootElement().getChild( StoredConfigXmlConstants.XML_ELEMENT_SETTING );
                 settingsElement.ifPresent( xmlElement -> xmlElement.addContent( settingElement ) );
                 settingsElement.ifPresent( xmlElement -> xmlElement.addContent( settingElement ) );
             }
             }
         }
         }
@@ -826,8 +799,8 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
                 for ( final XmlElement propertiesElement : propertiesElements )
                 for ( final XmlElement propertiesElement : propertiesElements )
                 {
                 {
                     propertiesElement.setAttribute(
                     propertiesElement.setAttribute(
-                            StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_TYPE,
-                            StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_VALUE_CONFIG );
+                            StoredConfigXmlConstants.XML_ATTRIBUTE_TYPE,
+                            StoredConfigXmlConstants.XML_ATTRIBUTE_VALUE_CONFIG );
                 }
                 }
             }
             }
         }
         }
@@ -844,12 +817,12 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
                     final List<XmlElement> properties = element.getChildren();
                     final List<XmlElement> properties = element.getChildren();
                     for ( final XmlElement property : properties )
                     for ( final XmlElement property : properties )
                     {
                     {
-                        final String key = property.getAttributeValue( "key" );
-                        final String value = property.getText();
-                        if ( key != null && !key.isEmpty() && value != null && !value.isEmpty() )
+                        final Optional<String> key = property.getAttributeValue( "key" );
+                        final Optional<String> value = property.getText();
+                        if ( key.isPresent() && value.isPresent() )
                         {
                         {
-                            LOGGER.info( () -> "migrating app-property config element '" + key + "' to setting " + PwmSetting.APP_PROPERTY_OVERRIDES.getKey() );
-                            final String newValue = key + "=" + value;
+                            LOGGER.info( () -> "migrating app-property config element '" + key.get() + "' to setting " + PwmSetting.APP_PROPERTY_OVERRIDES.getKey() );
+                            final String newValue = key.get() + "=" + value.get();
 
 
                             final List<String> existingValues = new ArrayList<>();
                             final List<String> existingValues = new ArrayList<>();
                             {
                             {
@@ -888,14 +861,14 @@ public class StoredConfigXmlSerializer implements StoredConfigSerializer
                         null,
                         null,
                         new StringArrayValue( newValues ),
                         new StringArrayValue( newValues ),
                         XmlOutputProcessData.builder().storedValueEncoderMode( StoredValueEncoder.Mode.PLAIN ).pwmSecurityKey( pwmSecurityKey ).build() );
                         XmlOutputProcessData.builder().storedValueEncoderMode( StoredValueEncoder.Mode.PLAIN ).pwmSecurityKey( pwmSecurityKey ).build() );
-                final Optional<XmlElement> settingsElement = xmlDocument.getRootElement().getChild( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_SETTING );
+                final Optional<XmlElement> settingsElement = xmlDocument.getRootElement().getChild( StoredConfigXmlConstants.XML_ELEMENT_SETTING );
                 settingsElement.ifPresent( ( s ) -> s.addContent( settingElement ) );
                 settingsElement.ifPresent( ( s ) -> s.addContent( settingElement ) );
             }
             }
         }
         }
 
 
         private static int readDocVersion( final XmlDocument xmlDocument )
         private static int readDocVersion( final XmlDocument xmlDocument )
         {
         {
-            final String xmlVersionStr = xmlDocument.getRootElement().getAttributeValue( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_XML_VERSION );
+            final String xmlVersionStr = xmlDocument.getRootElement().getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_XML_VERSION ).orElse( "0" );
             return JavaHelper.silentParseInt( xmlVersionStr, 0 );
             return JavaHelper.silentParseInt( xmlVersionStr, 0 );
         }
         }
     }
     }

+ 2 - 2
server/src/main/java/password/pwm/config/value/AbstractValue.java

@@ -21,7 +21,7 @@
 package password.pwm.config.value;
 package password.pwm.config.value;
 
 
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.JsonUtil;
@@ -81,7 +81,7 @@ public abstract class AbstractValue implements StoredValue
                     .pwmSecurityKey( testingKey )
                     .pwmSecurityKey( testingKey )
                     .storedValueEncoderMode( StoredValueEncoder.Mode.PLAIN )
                     .storedValueEncoderMode( StoredValueEncoder.Mode.PLAIN )
                     .build();
                     .build();
-            final List<XmlElement> xmlValues = storedValue.toXmlValues( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE, xmlOutputProcessData );
+            final List<XmlElement> xmlValues = storedValue.toXmlValues( StoredConfigXmlConstants.XML_ELEMENT_VALUE, xmlOutputProcessData );
             final XmlDocument document = XmlFactory.getFactory().newDocument( "root" );
             final XmlDocument document = XmlFactory.getFactory().newDocument( "root" );
             document.getRootElement().addContent( xmlValues );
             document.getRootElement().addContent( xmlValues );
             final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
             final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

+ 12 - 12
server/src/main/java/password/pwm/config/value/ActionValue.java

@@ -24,7 +24,7 @@ import com.google.gson.reflect.TypeToken;
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSettingSyntax;
 import password.pwm.config.PwmSettingSyntax;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.value.data.ActionConfiguration;
 import password.pwm.config.value.data.ActionConfiguration;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmOperationalException;
@@ -100,28 +100,28 @@ public class ActionValue extends AbstractValue implements StoredValue
                 final List<ActionConfiguration> values = new ArrayList<>();
                 final List<ActionConfiguration> values = new ArrayList<>();
 
 
                 final boolean oldType = PwmSettingSyntax.STRING_ARRAY.toString().equals(
                 final boolean oldType = PwmSettingSyntax.STRING_ARRAY.toString().equals(
-                        settingElement.getAttributeValue( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_SYNTAX ) );
-                final List<XmlElement> valueElements = settingElement.getChildren( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+                        settingElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_SYNTAX ).orElse( "" ) );
+                final List<XmlElement> valueElements = settingElement.getChildren( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
                 for ( final XmlElement loopValueElement : valueElements )
                 for ( final XmlElement loopValueElement : valueElements )
                 {
                 {
-                    final String stringValue = loopValueElement.getText();
-                    if ( !StringUtil.isEmpty( stringValue ) )
+                    final Optional<String> stringValue = loopValueElement.getText();
+                    if ( stringValue.isPresent() )
                     {
                     {
                         if ( syntaxVersion < 2 )
                         if ( syntaxVersion < 2 )
                         {
                         {
                             if ( oldType )
                             if ( oldType )
                             {
                             {
-                                if ( loopValueElement.getAttributeValue( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_LOCALE ) == null )
+                                if ( loopValueElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_LOCALE ).isEmpty() )
                                 {
                                 {
                                     final ActionConfiguration.ActionConfigurationOldVersion1 oldVersion1 = ActionConfiguration.ActionConfigurationOldVersion1
                                     final ActionConfiguration.ActionConfigurationOldVersion1 oldVersion1 = ActionConfiguration.ActionConfigurationOldVersion1
-                                            .parseOldConfigString( stringValue );
+                                            .parseOldConfigString( stringValue.get() );
                                     values.add( convertOldVersion1Values( oldVersion1 ) );
                                     values.add( convertOldVersion1Values( oldVersion1 ) );
                                 }
                                 }
                             }
                             }
                             else
                             else
                             {
                             {
                                 final ActionConfiguration.ActionConfigurationOldVersion1 parsedAc = JsonUtil
                                 final ActionConfiguration.ActionConfigurationOldVersion1 parsedAc = JsonUtil
-                                        .deserialize( stringValue, ActionConfiguration.ActionConfigurationOldVersion1.class );
+                                        .deserialize( stringValue.get(), ActionConfiguration.ActionConfigurationOldVersion1.class );
                                 if ( parsedAc != null )
                                 if ( parsedAc != null )
                                 {
                                 {
                                     final Optional<String> decodedValue = StoredValueEncoder.decode(
                                     final Optional<String> decodedValue = StoredValueEncoder.decode(
@@ -137,7 +137,7 @@ public class ActionValue extends AbstractValue implements StoredValue
                         }
                         }
                         else if ( syntaxVersion == 2 )
                         else if ( syntaxVersion == 2 )
                         {
                         {
-                            final ActionConfiguration value = JsonUtil.deserialize( stringValue, ActionConfiguration.class );
+                            final ActionConfiguration value = JsonUtil.deserialize( stringValue.get(), ActionConfiguration.class );
                             final List<ActionConfiguration.WebAction> clonedWebActions = new ArrayList<>();
                             final List<ActionConfiguration.WebAction> clonedWebActions = new ArrayList<>();
                             for ( final ActionConfiguration.WebAction webAction : value.getWebActions() )
                             for ( final ActionConfiguration.WebAction webAction : value.getWebActions() )
                             {
                             {
@@ -400,12 +400,12 @@ public class ActionValue extends AbstractValue implements StoredValue
 
 
     private static int figureCurrentStoredSyntax( final XmlElement settingElement )
     private static int figureCurrentStoredSyntax( final XmlElement settingElement )
     {
     {
-        final String storedSyntaxVersionString = settingElement.getAttributeValue( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_SYNTAX_VERSION );
-        if ( !StringUtil.isEmpty( storedSyntaxVersionString ) )
+        final Optional<String> storedSyntaxVersionString = settingElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_SYNTAX_VERSION );
+        if ( storedSyntaxVersionString.isPresent() )
         {
         {
             try
             try
             {
             {
-                return Integer.parseInt( storedSyntaxVersionString );
+                return Integer.parseInt( storedSyntaxVersionString.get() );
             }
             }
             catch ( final NumberFormatException e )
             catch ( final NumberFormatException e )
             {
             {

+ 7 - 4
server/src/main/java/password/pwm/config/value/BooleanValue.java

@@ -22,7 +22,7 @@ package password.pwm.config.value;
 
 
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.i18n.Display;
 import password.pwm.i18n.Display;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.JsonUtil;
@@ -66,11 +66,14 @@ public class BooleanValue implements StoredValue
             @Override
             @Override
             public BooleanValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey input )
             public BooleanValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey input )
             {
             {
-                final Optional<XmlElement> valueElement = settingElement.getChild( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+                final Optional<XmlElement> valueElement = settingElement.getChild( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
                 if ( valueElement.isPresent() )
                 if ( valueElement.isPresent() )
                 {
                 {
-                    final String value = valueElement.get().getTextTrim();
-                    return BooleanValue.of( Boolean.parseBoolean( value ) );
+                    final Optional<String> value = valueElement.get().getText();
+                    if ( value.isPresent() )
+                    {
+                        return BooleanValue.of( Boolean.parseBoolean( value.get().trim() ) );
+                    }
                 }
                 }
                 return BooleanValue.of( false );
                 return BooleanValue.of( false );
             }
             }

+ 19 - 20
server/src/main/java/password/pwm/config/value/ChallengeValue.java

@@ -84,29 +84,28 @@ public class ChallengeValue extends AbstractValue implements StoredValue
             {
             {
                 final List<XmlElement> valueElements = settingElement.getChildren( "value" );
                 final List<XmlElement> valueElements = settingElement.getChildren( "value" );
                 final Map<String, List<ChallengeItemConfiguration>> values = new TreeMap<>();
                 final Map<String, List<ChallengeItemConfiguration>> values = new TreeMap<>();
-                final boolean oldStyle = "LOCALIZED_STRING_ARRAY".equals( settingElement.getAttributeValue( "syntax" ) );
+                final boolean oldStyle = "LOCALIZED_STRING_ARRAY".equals( settingElement.getAttributeValue( "syntax" ).orElse( "" ) );
                 for ( final XmlElement loopValueElement : valueElements )
                 for ( final XmlElement loopValueElement : valueElements )
                 {
                 {
-                    final String localeString = loopValueElement.getAttributeValue(
-                            "locale" ) == null ? "" : loopValueElement.getAttributeValue( "locale" );
-                    final String value = loopValueElement.getText();
-                    if ( !values.containsKey( localeString ) )
+                    final String localeString = loopValueElement.getAttributeValue( "locale" ).orElse( "" );
+                    loopValueElement.getText().ifPresent( value ->
                     {
                     {
-                        values.put( localeString, new ArrayList<ChallengeItemConfiguration>() );
-                    }
-                    final ChallengeItemConfiguration challengeItemBean;
-                    if ( oldStyle )
-                    {
-                        challengeItemBean = parseOldVersionString( value );
-                    }
-                    else
-                    {
-                        challengeItemBean = JsonUtil.deserialize( value, ChallengeItemConfiguration.class );
-                    }
-                    if ( challengeItemBean != null )
-                    {
-                        values.get( localeString ).add( challengeItemBean );
-                    }
+                        final ChallengeItemConfiguration challengeItemBean;
+                        if ( oldStyle )
+                        {
+                            challengeItemBean = parseOldVersionString( value );
+                        }
+                        else
+                        {
+                            challengeItemBean = JsonUtil.deserialize( value, ChallengeItemConfiguration.class );
+                        }
+                        if ( challengeItemBean != null )
+                        {
+                            values.computeIfAbsent( localeString, ( s ) -> new ArrayList<>() )
+                                    .add( challengeItemBean );
+                        }
+                    } );
+
                 }
                 }
                 return new ChallengeValue( values );
                 return new ChallengeValue( values );
             }
             }

+ 1 - 5
server/src/main/java/password/pwm/config/value/CustomLinkValue.java

@@ -79,11 +79,7 @@ public class CustomLinkValue extends AbstractValue implements StoredValue
                 final List<CustomLinkConfiguration> values = new ArrayList<>();
                 final List<CustomLinkConfiguration> values = new ArrayList<>();
                 for ( final XmlElement loopValueElement  : valueElements )
                 for ( final XmlElement loopValueElement  : valueElements )
                 {
                 {
-                    final String value = loopValueElement.getText();
-                    if ( value != null && value.length() > 0 && loopValueElement.getAttributeValue( "locale" ) == null )
-                    {
-                        values.add( JsonUtil.deserialize( value, CustomLinkConfiguration.class ) );
-                    }
+                    loopValueElement.getText().ifPresent( value -> values.add( JsonUtil.deserialize( value, CustomLinkConfiguration.class ) ) );
                 }
                 }
                 return new CustomLinkValue( values );
                 return new CustomLinkValue( values );
             }
             }

+ 3 - 7
server/src/main/java/password/pwm/config/value/EmailValue.java

@@ -24,7 +24,6 @@ import com.google.gson.reflect.TypeToken;
 import password.pwm.bean.EmailItemBean;
 import password.pwm.bean.EmailItemBean;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
-import password.pwm.error.PwmOperationalException;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
@@ -81,20 +80,17 @@ public class EmailValue extends AbstractValue implements StoredValue
                     final XmlElement settingElement,
                     final XmlElement settingElement,
                     final PwmSecurityKey input
                     final PwmSecurityKey input
             )
             )
-                    throws PwmOperationalException
             {
             {
                 final Map<String, EmailItemBean> values = new TreeMap<>();
                 final Map<String, EmailItemBean> values = new TreeMap<>();
                 {
                 {
                     final List<XmlElement> valueElements = settingElement.getChildren( "value" );
                     final List<XmlElement> valueElements = settingElement.getChildren( "value" );
                     for ( final XmlElement loopValueElement : valueElements )
                     for ( final XmlElement loopValueElement : valueElements )
                     {
                     {
-                        final String value = loopValueElement.getText();
-                        if ( value != null && value.length() > 0 )
+                        loopValueElement.getText().ifPresent( value ->
                         {
                         {
-                            final String localeValue = loopValueElement.getAttributeValue(
-                                    "locale" ) == null ? "" : loopValueElement.getAttributeValue( "locale" );
+                            final String localeValue = loopValueElement.getAttributeValue( "locale" ).orElse( "" );
                             values.put( localeValue, JsonUtil.deserialize( value, EmailItemBean.class ) );
                             values.put( localeValue, JsonUtil.deserialize( value, EmailItemBean.class ) );
-                        }
+                        } );
                     }
                     }
                 }
                 }
                 return new EmailValue( values );
                 return new EmailValue( values );

+ 6 - 8
server/src/main/java/password/pwm/config/value/FileValue.java

@@ -24,7 +24,7 @@ import lombok.Builder;
 import lombok.Value;
 import lombok.Value;
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.bean.ImmutableByteArray;
 import password.pwm.http.bean.ImmutableByteArray;
@@ -107,21 +107,19 @@ public class FileValue extends AbstractValue implements StoredValue
             @Override
             @Override
             public FileValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey input )
             public FileValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey input )
             {
             {
-                final List<XmlElement> valueElements = settingElement.getChildren( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+                final List<XmlElement> valueElements = settingElement.getChildren( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
                 final Map<FileInformation, FileContent> values = new LinkedHashMap<>();
                 final Map<FileInformation, FileContent> values = new LinkedHashMap<>();
                 for ( final XmlElement loopValueElement : valueElements )
                 for ( final XmlElement loopValueElement : valueElements )
                 {
                 {
                     final Optional<XmlElement> loopFileInformation = loopValueElement.getChild( XML_ELEMENT_FILE_INFORMATION );
                     final Optional<XmlElement> loopFileInformation = loopValueElement.getChild( XML_ELEMENT_FILE_INFORMATION );
-                    if ( loopFileInformation.isPresent() )
+                    loopFileInformation.flatMap( XmlElement::getText ).ifPresent( loopFileInformationJson ->
                     {
                     {
-                        final String loopFileInformationJson = loopFileInformation.get().getText();
                         final FileInformation fileInformation = JsonUtil.deserialize( loopFileInformationJson,
                         final FileInformation fileInformation = JsonUtil.deserialize( loopFileInformationJson,
                                 FileInformation.class );
                                 FileInformation.class );
 
 
                         final Optional<XmlElement> loopFileContentElement = loopValueElement.getChild( XML_ELEMENT_FILE_CONTENT );
                         final Optional<XmlElement> loopFileContentElement = loopValueElement.getChild( XML_ELEMENT_FILE_CONTENT );
-                        if ( loopFileContentElement.isPresent() )
+                        loopFileContentElement.flatMap( XmlElement::getText ).ifPresent( fileContentString ->
                         {
                         {
-                            final String fileContentString = loopFileContentElement.get().getText();
                             final FileContent fileContent;
                             final FileContent fileContent;
                             try
                             try
                             {
                             {
@@ -132,8 +130,8 @@ public class FileValue extends AbstractValue implements StoredValue
                             {
                             {
                                 LOGGER.error( () -> "error reading file contents item: " + e.getMessage(), e );
                                 LOGGER.error( () -> "error reading file contents item: " + e.getMessage(), e );
                             }
                             }
-                        }
-                    }
+                        } );
+                    } );
                 }
                 }
                 return new FileValue( values );
                 return new FileValue( values );
             }
             }

+ 7 - 7
server/src/main/java/password/pwm/config/value/FormValue.java

@@ -38,6 +38,7 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.HashSet;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
+import java.util.Optional;
 import java.util.Set;
 import java.util.Set;
 
 
 public class FormValue extends AbstractValue implements StoredValue
 public class FormValue extends AbstractValue implements StoredValue
@@ -79,26 +80,25 @@ public class FormValue extends AbstractValue implements StoredValue
                     throws PwmOperationalException
                     throws PwmOperationalException
             {
             {
                 final boolean oldType = PwmSettingSyntax.LOCALIZED_STRING_ARRAY.toString().equals(
                 final boolean oldType = PwmSettingSyntax.LOCALIZED_STRING_ARRAY.toString().equals(
-                        settingElement.getAttributeValue( "syntax" ) );
+                        settingElement.getAttributeValue( "syntax" ).orElse( "" ) );
                 final List<XmlElement> valueElements = settingElement.getChildren( "value" );
                 final List<XmlElement> valueElements = settingElement.getChildren( "value" );
                 final List<FormConfiguration> values = new ArrayList<>();
                 final List<FormConfiguration> values = new ArrayList<>();
                 for ( final XmlElement loopValueElement  : valueElements )
                 for ( final XmlElement loopValueElement  : valueElements )
                 {
                 {
-                    final String value = loopValueElement.getText();
-                    if ( value != null && value.length() > 0 && loopValueElement.getAttributeValue( "locale" ) == null )
+                    final Optional<String> value = loopValueElement.getText();
+                    if ( value.isPresent() && loopValueElement.getAttributeValue( "locale" ).isEmpty() )
                     {
                     {
                         if ( oldType )
                         if ( oldType )
                         {
                         {
-                            values.add( FormConfiguration.parseOldConfigString( value ) );
+                            values.add( FormConfiguration.parseOldConfigString( value.get() ) );
                         }
                         }
                         else
                         else
                         {
                         {
-                            values.add( JsonUtil.deserialize( value, FormConfiguration.class ) );
+                            values.add( JsonUtil.deserialize( value.get(), FormConfiguration.class ) );
                         }
                         }
                     }
                     }
                 }
                 }
-                final FormValue formValue = new FormValue( values );
-                return formValue;
+                return new FormValue( values );
             }
             }
         };
         };
     }
     }

+ 2 - 4
server/src/main/java/password/pwm/config/value/LocalizedStringArrayValue.java

@@ -76,10 +76,8 @@ public class LocalizedStringArrayValue extends AbstractValue implements StoredVa
                 final Map<String, List<String>> values = new TreeMap<>();
                 final Map<String, List<String>> values = new TreeMap<>();
                 for ( final XmlElement loopValueElement  : valueElements )
                 for ( final XmlElement loopValueElement  : valueElements )
                 {
                 {
-                    final String localeString = loopValueElement.getAttributeValue(
-                            "locale" ) == null ? "" : loopValueElement.getAttributeValue( "locale" );
-                    final String value = loopValueElement.getText();
-                    values.computeIfAbsent( localeString, s -> new ArrayList<>() ).add( value );
+                    final String localeString = loopValueElement.getAttributeValue( "locale" ).orElse( "" );
+                    loopValueElement.getText().ifPresent( value -> values.computeIfAbsent( localeString, s -> new ArrayList<>() ).add( value ) );
                 }
                 }
 
 
                 return new LocalizedStringArrayValue( values );
                 return new LocalizedStringArrayValue( values );

+ 4 - 5
server/src/main/java/password/pwm/config/value/LocalizedStringValue.java

@@ -22,7 +22,7 @@ package password.pwm.config.value;
 
 
 import com.google.gson.reflect.TypeToken;
 import com.google.gson.reflect.TypeToken;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.JsonUtil;
@@ -72,13 +72,12 @@ public class LocalizedStringValue extends AbstractValue implements StoredValue
             @Override
             @Override
             public LocalizedStringValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey key )
             public LocalizedStringValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey key )
             {
             {
-                final List<XmlElement> elements = settingElement.getChildren( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+                final List<XmlElement> elements = settingElement.getChildren( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
                 final Map<String, String> values = new TreeMap<>();
                 final Map<String, String> values = new TreeMap<>();
                 for ( final XmlElement loopValueElement : elements )
                 for ( final XmlElement loopValueElement : elements )
                 {
                 {
-                    final String localeString = loopValueElement.getAttributeValue( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_LOCALE );
-                    final String value = loopValueElement.getText();
-                    values.put( localeString == null ? "" : localeString, value );
+                    final String localeString = loopValueElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_LOCALE ).orElse( "" );
+                    loopValueElement.getText().ifPresent( value -> values.put( localeString, value ) );
                 }
                 }
                 return new LocalizedStringValue( values );
                 return new LocalizedStringValue( values );
             }
             }

+ 14 - 11
server/src/main/java/password/pwm/config/value/NamedSecretValue.java

@@ -23,7 +23,7 @@ package password.pwm.config.value;
 import com.google.gson.reflect.TypeToken;
 import com.google.gson.reflect.TypeToken;
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.value.data.NamedSecretData;
 import password.pwm.config.value.data.NamedSecretData;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.ErrorInformation;
@@ -102,7 +102,7 @@ public class NamedSecretValue implements StoredValue
                     throws PwmOperationalException, PwmUnrecoverableException
                     throws PwmOperationalException, PwmUnrecoverableException
             {
             {
                 final Map<String, NamedSecretData> values = new LinkedHashMap<>();
                 final Map<String, NamedSecretData> values = new LinkedHashMap<>();
-                final List<XmlElement> valueElements = settingElement.getChildren( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+                final List<XmlElement> valueElements = settingElement.getChildren( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
 
 
                 try
                 try
                 {
                 {
@@ -112,19 +112,22 @@ public class NamedSecretValue implements StoredValue
                         final Optional<XmlElement> passwordElement = value.getChild( ELEMENT_PASSWORD );
                         final Optional<XmlElement> passwordElement = value.getChild( ELEMENT_PASSWORD );
                         if ( nameElement.isPresent() && passwordElement.isPresent() )
                         if ( nameElement.isPresent() && passwordElement.isPresent() )
                         {
                         {
-                            final String name = nameElement.get().getText();
-                            final String encodedValue = passwordElement.get().getText();
-                            final PasswordData passwordData = new PasswordData( SecureEngine.decryptStringValue( encodedValue, key, PwmBlockAlgorithm.CONFIG ) );
-                            final List<XmlElement> usages = value.getChildren( ELEMENT_USAGE );
-                            final List<String> strUsages = new ArrayList<>();
-                            if ( usages != null )
+                            final Optional<String> name = nameElement.get().getText();
+                            final Optional<String> encodedValue = passwordElement.get().getText();
+                            if ( name.isPresent() && encodedValue.isPresent() )
                             {
                             {
-                                for ( final XmlElement usageElement : usages )
+                                final PasswordData passwordData = new PasswordData( SecureEngine.decryptStringValue( encodedValue.get(), key, PwmBlockAlgorithm.CONFIG ) );
+                                final List<XmlElement> usages = value.getChildren( ELEMENT_USAGE );
+                                final List<String> strUsages = new ArrayList<>();
+                                if ( usages != null )
                                 {
                                 {
-                                    strUsages.add( usageElement.getText() );
+                                    for ( final XmlElement usageElement : usages )
+                                    {
+                                        usageElement.getText().ifPresent( strUsages::add );
+                                    }
                                 }
                                 }
+                                values.put( name.get(), new NamedSecretData( passwordData, Collections.unmodifiableList( strUsages ) ) );
                             }
                             }
-                            values.put( name, new NamedSecretData( passwordData, Collections.unmodifiableList( strUsages ) ) );
                         }
                         }
                     }
                     }
                 }
                 }

+ 5 - 3
server/src/main/java/password/pwm/config/value/NumericArrayValue.java

@@ -64,9 +64,11 @@ public class NumericArrayValue extends AbstractValue implements StoredValue
                 final List<XmlElement> valueElements = settingElement.getChildren( "value" );
                 final List<XmlElement> valueElements = settingElement.getChildren( "value" );
                 for ( final XmlElement element : valueElements )
                 for ( final XmlElement element : valueElements )
                 {
                 {
-                    final String strValue = element.getText();
-                    final Long longValue = Long.parseLong( strValue );
-                    returnList.add( longValue );
+                    element.getText().ifPresent( strValue ->
+                    {
+                        final Long longValue = Long.parseLong( strValue );
+                        returnList.add( longValue );
+                    } );
                 }
                 }
                 return new NumericArrayValue( returnList );
                 return new NumericArrayValue( returnList );
             }
             }

+ 9 - 8
server/src/main/java/password/pwm/config/value/NumericValue.java

@@ -22,7 +22,7 @@ package password.pwm.config.value;
 
 
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSettingProperty;
 import password.pwm.config.PwmSettingProperty;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
@@ -55,16 +55,17 @@ public class NumericValue extends AbstractValue implements StoredValue
             @Override
             @Override
             public NumericValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey input )
             public NumericValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey input )
             {
             {
-                final Optional<XmlElement> valueElement = settingElement.getChild( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+                final Optional<XmlElement> valueElement = settingElement.getChild( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
                 if ( valueElement.isPresent() )
                 if ( valueElement.isPresent() )
                 {
                 {
-                    final String value = valueElement.get().getText();
-                    return new NumericValue( normalizeValue( pwmSetting, Long.parseLong( value ) ) );
-                }
-                else
-                {
-                    return new NumericValue( 0 );
+                    final Optional<String> value = valueElement.get().getText();
+                    if ( value.isPresent() )
+                    {
+                        return new NumericValue( normalizeValue( pwmSetting, Long.parseLong( value.get() ) ) );
+                    }
                 }
                 }
+
+                return new NumericValue( 0 );
             }
             }
         };
         };
     }
     }

+ 2 - 6
server/src/main/java/password/pwm/config/value/OptionListValue.java

@@ -79,13 +79,9 @@ public class OptionListValue extends AbstractValue implements StoredValue
                 final Set<String> values = new TreeSet<>();
                 final Set<String> values = new TreeSet<>();
                 for ( final XmlElement loopValueElement : valueElements )
                 for ( final XmlElement loopValueElement : valueElements )
                 {
                 {
-                    final String value = loopValueElement.getText();
-                    if ( value != null && !value.trim().isEmpty() )
-                    {
-                        values.add( value );
-                    }
+                    loopValueElement.getText().ifPresent( value -> values.add( value.trim() ) );
                 }
                 }
-                return new OptionListValue( values );
+                return new OptionListValue( Collections.unmodifiableSet( values ) );
             }
             }
         };
         };
     }
     }

+ 10 - 13
server/src/main/java/password/pwm/config/value/PasswordValue.java

@@ -23,7 +23,7 @@ package password.pwm.config.value;
 
 
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmError;
@@ -91,32 +91,29 @@ public class PasswordValue implements StoredValue
             )
             )
                     throws PwmOperationalException, PwmUnrecoverableException
                     throws PwmOperationalException, PwmUnrecoverableException
             {
             {
-                final Optional<XmlElement> valueElement = settingElement.getChild( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+                final Optional<XmlElement> valueElement = settingElement.getChild( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
                 if ( valueElement.isPresent() )
                 if ( valueElement.isPresent() )
                 {
                 {
-                    final String rawValue = valueElement.get().getText();
+                    final Optional<String> rawValue = valueElement.get().getText();
 
 
-                    final PasswordValue newPasswordValue = new PasswordValue();
-                    if ( rawValue == null || rawValue.isEmpty() )
+                    if ( rawValue.isEmpty() )
                     {
                     {
-                        return newPasswordValue;
+                        return new PasswordValue();
                     }
                     }
 
 
-                    final boolean plainTextSetting;
-                    {
-                        final String plainTextAttributeStr = valueElement.get().getAttributeValue( "plaintext" );
-                        plainTextSetting = plainTextAttributeStr != null && Boolean.parseBoolean( plainTextAttributeStr );
-                    }
+                    final boolean plainTextSetting = valueElement.get().getAttributeValue( "plaintext" )
+                            .map( Boolean::parseBoolean )
+                            .orElse( false );
 
 
                     if ( plainTextSetting )
                     if ( plainTextSetting )
                     {
                     {
-                        return new PasswordValue( new PasswordData( rawValue ) );
+                        return new PasswordValue( new PasswordData( rawValue.get() ) );
                     }
                     }
                     else
                     else
                     {
                     {
                         try
                         try
                         {
                         {
-                            final Optional<String> encodedValue = StoredValueEncoder.decode( rawValue, StoredValueEncoder.Mode.CONFIG_PW, key );
+                            final Optional<String> encodedValue = StoredValueEncoder.decode( rawValue.get(), StoredValueEncoder.Mode.CONFIG_PW, key );
                             if ( encodedValue.isPresent() )
                             if ( encodedValue.isPresent() )
                             {
                             {
                                 return new PasswordValue( new PasswordData( encodedValue.get() ) );
                                 return new PasswordValue( new PasswordData( encodedValue.get() ) );

+ 27 - 20
server/src/main/java/password/pwm/config/value/PrivateKeyValue.java

@@ -22,7 +22,7 @@ package password.pwm.config.value;
 
 
 import password.pwm.bean.PrivateKeyCertificate;
 import password.pwm.bean.PrivateKeyCertificate;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
@@ -61,26 +61,27 @@ public class PrivateKeyValue extends AbstractValue
             @Override
             @Override
             public PrivateKeyValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey key )
             public PrivateKeyValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey key )
             {
             {
-                if ( settingElement != null && settingElement.getChild( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE  ).isPresent() )
+                if ( settingElement != null && settingElement.getChild( StoredConfigXmlConstants.XML_ELEMENT_VALUE  ).isPresent() )
                 {
                 {
 
 
-                    final Optional<XmlElement> valueElement = settingElement.getChild( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+                    final Optional<XmlElement> valueElement = settingElement.getChild( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
                     if ( valueElement.isPresent() )
                     if ( valueElement.isPresent() )
                     {
                     {
                         final List<X509Certificate> certificates = new ArrayList<>();
                         final List<X509Certificate> certificates = new ArrayList<>();
                         for ( final XmlElement certificateElement : valueElement.get().getChildren( ELEMENT_NAME_CERTIFICATE ) )
                         for ( final XmlElement certificateElement : valueElement.get().getChildren( ELEMENT_NAME_CERTIFICATE ) )
                         {
                         {
-                            try
+                            certificateElement.getText().ifPresent( ( b64Text ) ->
                             {
                             {
-                                final String b64Text = certificateElement.getText();
-                                final X509Certificate cert = X509Utils.certificateFromBase64( b64Text );
-                                certificates.add( cert );
-                            }
-                            catch ( final Exception e )
-                            {
-                                LOGGER.error( () -> "error reading certificate: " + e.getMessage(), e );
-                            }
-
+                                try
+                                {
+                                    final X509Certificate cert = X509Utils.certificateFromBase64( b64Text );
+                                    certificates.add( cert );
+                                }
+                                catch ( final Exception e )
+                                {
+                                    LOGGER.error( () -> "error reading certificate: " + e.getMessage(), e );
+                                }
+                            } );
                         }
                         }
 
 
 
 
@@ -90,12 +91,18 @@ public class PrivateKeyValue extends AbstractValue
                             final Optional<XmlElement> keyElement = valueElement.get().getChild( ELEMENT_NAME_KEY );
                             final Optional<XmlElement> keyElement = valueElement.get().getChild( ELEMENT_NAME_KEY );
                             if ( keyElement.isPresent() )
                             if ( keyElement.isPresent() )
                             {
                             {
-                                final String encryptedText = keyElement.get().getText();
-                                final Optional<String> decryptedText = StoredValueEncoder.decode( encryptedText, StoredValueEncoder.Mode.CONFIG_PW, key );
-                                if ( decryptedText.isPresent() )
+                                final Optional<String> encryptedText = keyElement.get().getText();
+                                if ( encryptedText.isPresent() )
                                 {
                                 {
-                                    final byte[] privateKeyBytes = StringUtil.base64Decode( decryptedText.get() );
-                                    privateKey = KeyFactory.getInstance( "RSA" ).generatePrivate( new PKCS8EncodedKeySpec( privateKeyBytes ) );
+                                    final Optional<String> decryptedText = StoredValueEncoder.decode(
+                                            encryptedText.get(),
+                                            StoredValueEncoder.Mode.CONFIG_PW, key );
+
+                                    if ( decryptedText.isPresent() )
+                                    {
+                                        final byte[] privateKeyBytes = StringUtil.base64Decode( decryptedText.get() );
+                                        privateKey = KeyFactory.getInstance( "RSA" ).generatePrivate( new PKCS8EncodedKeySpec( privateKeyBytes ) );
+                                    }
                                 }
                                 }
                             }
                             }
                             else
                             else
@@ -158,7 +165,7 @@ public class PrivateKeyValue extends AbstractValue
     @Override
     @Override
     public List<XmlElement> toXmlValues( final String valueElementName, final XmlOutputProcessData xmlOutputProcessData )
     public List<XmlElement> toXmlValues( final String valueElementName, final XmlOutputProcessData xmlOutputProcessData )
     {
     {
-        final XmlElement valueElement = XmlFactory.getFactory().newElement( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+        final XmlElement valueElement = XmlFactory.getFactory().newElement( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
         if ( privateKeyCertificate != null )
         if ( privateKeyCertificate != null )
         {
         {
             try
             try
@@ -212,7 +219,7 @@ public class PrivateKeyValue extends AbstractValue
                 ? new X509Utils.DebugInfoFlag[]
                 ? new X509Utils.DebugInfoFlag[]
                 {
                 {
                         X509Utils.DebugInfoFlag.IncludeCertificateDetail,
                         X509Utils.DebugInfoFlag.IncludeCertificateDetail,
-                }
+                        }
                 : null;
                 : null;
         final Map<String, Object> returnMap = new LinkedHashMap<>();
         final Map<String, Object> returnMap = new LinkedHashMap<>();
         returnMap.put( "certificates", X509Utils.makeDebugInfoMap( privateKeyCertificate.getCertificates(), flags ) );
         returnMap.put( "certificates", X509Utils.makeDebugInfoMap( privateKeyCertificate.getCertificates(), flags ) );

+ 6 - 9
server/src/main/java/password/pwm/config/value/RemoteWebServiceValue.java

@@ -23,7 +23,7 @@ package password.pwm.config.value;
 import com.google.gson.reflect.TypeToken;
 import com.google.gson.reflect.TypeToken;
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.value.data.RemoteWebServiceConfiguration;
 import password.pwm.config.value.data.RemoteWebServiceConfiguration;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmOperationalException;
@@ -91,23 +91,20 @@ public class RemoteWebServiceValue extends AbstractValue implements StoredValue
             )
             )
                     throws PwmOperationalException
                     throws PwmOperationalException
             {
             {
-                final List<XmlElement> valueElements = settingElement.getChildren( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+                final List<XmlElement> valueElements = settingElement.getChildren( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
                 final List<RemoteWebServiceConfiguration> values = new ArrayList<>();
                 final List<RemoteWebServiceConfiguration> values = new ArrayList<>();
                 for ( final XmlElement loopValueElement : valueElements )
                 for ( final XmlElement loopValueElement : valueElements )
                 {
                 {
-                    final String value = loopValueElement.getText();
-                    if ( value != null && value.length() > 0 )
+                    final Optional<String> value = loopValueElement.getText();
+                    if ( value.isPresent() )
                     {
                     {
-                        final RemoteWebServiceConfiguration parsedValue = JsonUtil.deserialize( value, RemoteWebServiceConfiguration.class );
+                        final RemoteWebServiceConfiguration parsedValue = JsonUtil.deserialize( value.get(), RemoteWebServiceConfiguration.class );
                         final Optional<String> decodedValue = StoredValueEncoder.decode(
                         final Optional<String> decodedValue = StoredValueEncoder.decode(
                                 parsedValue.getPassword(),
                                 parsedValue.getPassword(),
                                 StoredValueEncoder.Mode.ENCODED,
                                 StoredValueEncoder.Mode.ENCODED,
                                 pwmSecurityKey
                                 pwmSecurityKey
                         );
                         );
-                        decodedValue.ifPresent( ( s ) ->
-                        {
-                            values.add( parsedValue.toBuilder().password( s ).build() );
-                        } );
+                        decodedValue.ifPresent( ( s ) -> values.add( parsedValue.toBuilder().password( s ).build() ) );
                     }
                     }
                 }
                 }
                 return new RemoteWebServiceValue( values );
                 return new RemoteWebServiceValue( values );

+ 15 - 18
server/src/main/java/password/pwm/config/value/StringArrayValue.java

@@ -21,9 +21,10 @@
 package password.pwm.config.value;
 package password.pwm.config.value;
 
 
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.JsonUtil;
+import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.secure.PwmSecurityKey;
 import password.pwm.util.secure.PwmSecurityKey;
@@ -33,8 +34,10 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
+import java.util.Optional;
 import java.util.regex.Matcher;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 
 public class StringArrayValue extends AbstractValue implements StoredValue
 public class StringArrayValue extends AbstractValue implements StoredValue
 {
 {
@@ -42,7 +45,9 @@ public class StringArrayValue extends AbstractValue implements StoredValue
 
 
     public StringArrayValue( final List<String> values )
     public StringArrayValue( final List<String> values )
     {
     {
-        this.values = values == null ? Collections.emptyList() : Collections.unmodifiableList( values );
+        final List<String> copiedValues = new ArrayList<>( values == null ? Collections.emptyList() : values );
+        copiedValues.removeAll( Collections.singleton( null ) );
+        this.values = Collections.unmodifiableList( copiedValues );
     }
     }
 
 
     public static StoredValueFactory factory( )
     public static StoredValueFactory factory( )
@@ -52,32 +57,24 @@ public class StringArrayValue extends AbstractValue implements StoredValue
             @Override
             @Override
             public StringArrayValue fromJson( final String input )
             public StringArrayValue fromJson( final String input )
             {
             {
-                if ( input == null )
+                if ( StringUtil.isEmpty( input ) )
                 {
                 {
                     return new StringArrayValue( Collections.emptyList() );
                     return new StringArrayValue( Collections.emptyList() );
                 }
                 }
                 else
                 else
                 {
                 {
-                    List<String> srcList = JsonUtil.deserializeStringList( input );
-                    srcList = srcList == null ? Collections.emptyList() : srcList;
-                    while ( srcList.contains( null ) )
-                    {
-                        srcList.remove( null );
-                    }
-                    return new StringArrayValue( Collections.unmodifiableList( srcList ) );
+                    return new StringArrayValue( JsonUtil.deserializeStringList( input ) );
                 }
                 }
             }
             }
 
 
             @Override
             @Override
             public StringArrayValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey key )
             public StringArrayValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey key )
             {
             {
-                final List<XmlElement> valueElements = settingElement.getChildren( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
-                final List<String> values = new ArrayList<>();
-                for ( final XmlElement loopValueElement : valueElements )
-                {
-                    final String value = loopValueElement.getText();
-                    values.add( value );
-                }
+                final List<String> values = settingElement.getChildren( StoredConfigXmlConstants.XML_ELEMENT_VALUE ).stream()
+                        .map( XmlElement::getText )
+                        .flatMap( Optional::stream )
+                        .collect( Collectors.toList() );
+
                 return new StringArrayValue( values );
                 return new StringArrayValue( values );
             }
             }
         };
         };
@@ -132,7 +129,7 @@ public class StringArrayValue extends AbstractValue implements StoredValue
         if ( values != null && !values.isEmpty() )
         if ( values != null && !values.isEmpty() )
         {
         {
             final StringBuilder sb = new StringBuilder();
             final StringBuilder sb = new StringBuilder();
-            for ( final Iterator valueIterator = values.iterator(); valueIterator.hasNext(); )
+            for ( final Iterator<String> valueIterator = values.iterator(); valueIterator.hasNext(); )
             {
             {
                 sb.append( valueIterator.next() );
                 sb.append( valueIterator.next() );
                 if ( valueIterator.hasNext() )
                 if ( valueIterator.hasNext() )

+ 3 - 3
server/src/main/java/password/pwm/config/value/StringValue.java

@@ -22,7 +22,7 @@ package password.pwm.config.value;
 
 
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSettingFlag;
 import password.pwm.config.PwmSettingFlag;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.value.data.FormConfiguration;
 import password.pwm.config.value.data.FormConfiguration;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.JsonUtil;
@@ -65,8 +65,8 @@ public class StringValue extends AbstractValue implements StoredValue
             @Override
             @Override
             public StringValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey key )
             public StringValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey key )
             {
             {
-                final Optional<XmlElement> valueElement = settingElement.getChild( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
-                final String value = valueElement.map( XmlElement::getText ).orElse( "" );
+                final Optional<XmlElement> valueElement = settingElement.getChild( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+                final String value = valueElement.flatMap( XmlElement::getText ).orElse( "" );
                 return new StringValue( value );
                 return new StringValue( value );
             }
             }
         };
         };

+ 10 - 8
server/src/main/java/password/pwm/config/value/UserPermissionValue.java

@@ -22,13 +22,13 @@ package password.pwm.config.value;
 
 
 import com.google.gson.reflect.TypeToken;
 import com.google.gson.reflect.TypeToken;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.value.data.UserPermission;
 import password.pwm.config.value.data.UserPermission;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
-import password.pwm.ldap.permission.UserPermissionUtility;
 import password.pwm.ldap.permission.UserPermissionType;
 import password.pwm.ldap.permission.UserPermissionType;
+import password.pwm.ldap.permission.UserPermissionUtility;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
@@ -39,6 +39,7 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
+import java.util.Optional;
 
 
 public class UserPermissionValue extends AbstractValue implements StoredValue
 public class UserPermissionValue extends AbstractValue implements StoredValue
 {
 {
@@ -93,25 +94,26 @@ public class UserPermissionValue extends AbstractValue implements StoredValue
             public UserPermissionValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey key )
             public UserPermissionValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey key )
                     throws PwmOperationalException
                     throws PwmOperationalException
             {
             {
-                final boolean newType = "2".equals(
-                        settingElement.getAttributeValue( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ATTRIBUTE_SYNTAX_VERSION ) );
+                final boolean newType = "2".equals( settingElement.getAttributeValue( StoredConfigXmlConstants.XML_ATTRIBUTE_SYNTAX_VERSION )
+                                .orElse( "" ) );
+
                 final List<XmlElement> valueElements = settingElement.getChildren( "value" );
                 final List<XmlElement> valueElements = settingElement.getChildren( "value" );
                 final List<UserPermission> values = new ArrayList<>();
                 final List<UserPermission> values = new ArrayList<>();
                 for ( final XmlElement loopValueElement : valueElements )
                 for ( final XmlElement loopValueElement : valueElements )
                 {
                 {
-                    final String value = loopValueElement.getText();
-                    if ( value != null && !value.isEmpty() )
+                    final Optional<String> value = loopValueElement.getText();
+                    if ( value.isPresent() )
                     {
                     {
                         if ( newType )
                         if ( newType )
                         {
                         {
-                            final UserPermission userPermission = JsonUtil.deserialize( value, UserPermission.class );
+                            final UserPermission userPermission = JsonUtil.deserialize( value.get(), UserPermission.class );
                             values.add( userPermission );
                             values.add( userPermission );
                         }
                         }
                         else
                         else
                         {
                         {
                             values.add( UserPermission.builder()
                             values.add( UserPermission.builder()
                                     .type( UserPermissionType.ldapQuery )
                                     .type( UserPermissionType.ldapQuery )
-                                    .ldapQuery( value )
+                                    .ldapQuery( value.get() )
                                     .build() );
                                     .build() );
                         }
                         }
                     }
                     }

+ 8 - 5
server/src/main/java/password/pwm/config/value/VerificationMethodValue.java

@@ -23,7 +23,7 @@ package password.pwm.config.value;
 import lombok.Value;
 import lombok.Value;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.option.IdentityVerificationMethod;
 import password.pwm.config.option.IdentityVerificationMethod;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.i18n.Display;
 import password.pwm.i18n.Display;
@@ -142,12 +142,15 @@ public class VerificationMethodValue extends AbstractValue implements StoredValu
             public VerificationMethodValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey key )
             public VerificationMethodValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey key )
                     throws PwmOperationalException
                     throws PwmOperationalException
             {
             {
-                final Optional<XmlElement> valueElement = settingElement.getChild( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+                final Optional<XmlElement> valueElement = settingElement.getChild( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
                 if ( valueElement.isPresent() )
                 if ( valueElement.isPresent() )
                 {
                 {
-                    final String inputStr = valueElement.get().getText();
-                    final VerificationMethodSettings settings = JsonUtil.deserialize( inputStr, VerificationMethodSettings.class );
-                    return new VerificationMethodValue( settings );
+                    final Optional<String> inputStr = valueElement.get().getText();
+                    if ( inputStr.isPresent() )
+                    {
+                        final VerificationMethodSettings settings = JsonUtil.deserialize( inputStr.get(), VerificationMethodSettings.class );
+                        return new VerificationMethodValue( settings );
+                    }
                 }
                 }
                 return  new VerificationMethodValue(  );
                 return  new VerificationMethodValue(  );
             }
             }

+ 3 - 5
server/src/main/java/password/pwm/config/value/X509CertificateValue.java

@@ -22,7 +22,7 @@ package password.pwm.config.value;
 
 
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
@@ -69,12 +69,10 @@ public class X509CertificateValue extends AbstractValue implements StoredValue
             public X509CertificateValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey key )
             public X509CertificateValue fromXmlElement( final PwmSetting pwmSetting, final XmlElement settingElement, final PwmSecurityKey key )
             {
             {
                 final List<String> b64certificates = new ArrayList<>();
                 final List<String> b64certificates = new ArrayList<>();
-                final List<XmlElement> valueElements = settingElement.getChildren( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE );
+                final List<XmlElement> valueElements = settingElement.getChildren( StoredConfigXmlConstants.XML_ELEMENT_VALUE );
                 for ( final XmlElement loopValueElement : valueElements )
                 for ( final XmlElement loopValueElement : valueElements )
                 {
                 {
-                    final String b64encodedStr = loopValueElement.getText();
-
-                    b64certificates.add( b64encodedStr );
+                    loopValueElement.getText().ifPresent( b64certificates::add );
                 }
                 }
                 return new X509CertificateValue( Collections.unmodifiableList( b64certificates ) );
                 return new X509CertificateValue( Collections.unmodifiableList( b64certificates ) );
             }
             }

+ 14 - 11
server/src/main/java/password/pwm/svc/event/LdapXmlUserHistory.java

@@ -25,8 +25,8 @@ import com.novell.ldapchai.exception.ChaiOperationException;
 import com.novell.ldapchai.exception.ChaiUnavailableException;
 import com.novell.ldapchai.exception.ChaiUnavailableException;
 import com.novell.ldapchai.util.ConfigObjectRecord;
 import com.novell.ldapchai.util.ConfigObjectRecord;
 import lombok.Value;
 import lombok.Value;
-import password.pwm.PwmDomain;
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
+import password.pwm.PwmDomain;
 import password.pwm.bean.SessionLabel;
 import password.pwm.bean.SessionLabel;
 import password.pwm.bean.UserIdentity;
 import password.pwm.bean.UserIdentity;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
@@ -309,17 +309,20 @@ class LdapXmlUserHistory implements UserHistoryStore
 
 
                 for ( final XmlElement hrElement : rootElement.getChildren( XML_NODE_RECORD ) )
                 for ( final XmlElement hrElement : rootElement.getChildren( XML_NODE_RECORD ) )
                 {
                 {
-                    final String timeStampStr = hrElement.getAttributeValue( XML_ATTR_TIMESTAMP );
-                    final long timeStamp = Long.parseLong( timeStampStr );
-                    final String transactionCode = hrElement.getAttributeValue( XML_ATTR_TRANSACTION );
-                    AuditEvent.forKey( transactionCode ).ifPresent( ( eventCode ) ->
+                    hrElement.getAttributeValue( XML_ATTR_TIMESTAMP ).ifPresent( ( timeStampStr ->
                     {
                     {
-                        final String srcAddr = hrElement.getAttributeValue( XML_ATTR_SRC_IP ) != null ? hrElement.getAttributeValue( XML_ATTR_SRC_IP ) : "";
-                        final String srcHost = hrElement.getAttributeValue( XML_ATTR_SRC_HOST ) != null ? hrElement.getAttributeValue( XML_ATTR_SRC_HOST ) : "";
-                        final String message = hrElement.getText();
-                        final StoredEvent storedEvent = new StoredEvent( eventCode, timeStamp, message, srcAddr, srcHost );
-                        returnHistory.addEvent( storedEvent );
-                    } );
+                        final long timeStamp = Long.parseLong( timeStampStr );
+                        hrElement.getAttributeValue( XML_ATTR_TRANSACTION )
+                                .flatMap( AuditEvent::forKey )
+                                .ifPresent( ( eventCode ) ->
+                        {
+                            final String srcAddr = hrElement.getAttributeValue( XML_ATTR_SRC_IP ).orElse( "" );
+                            final String srcHost = hrElement.getAttributeValue( XML_ATTR_SRC_HOST ).orElse( "" );
+                            final String message = hrElement.getText().orElse( "" );
+                            final StoredEvent storedEvent = new StoredEvent( eventCode, timeStamp, message, srcAddr, srcHost );
+                            returnHistory.addEvent( storedEvent );
+                        } );
+                    } ) );
                 }
                 }
             }
             }
             catch ( final PwmUnrecoverableException | IOException e )
             catch ( final PwmUnrecoverableException | IOException e )

+ 7 - 7
server/src/main/java/password/pwm/util/java/LicenseInfoReader.java

@@ -74,11 +74,11 @@ public class LicenseInfoReader
 
 
     private static DependencyInfo readDependencyInfo( final XmlElement dependency )
     private static DependencyInfo readDependencyInfo( final XmlElement dependency )
     {
     {
-        final String projectUrl = dependency.getChildText( "projectUrl" );
-        final String name = dependency.getChildText( "name" );
-        final String artifactId = dependency.getChildText( "artifactId" );
-        final String version = dependency.getChildText( "version" );
-        final String type = dependency.getChildText( "type" );
+        final String projectUrl = dependency.getChildText( "projectUrl" ).orElse( null );
+        final String name = dependency.getChildText( "name" ).orElse( null );
+        final String artifactId = dependency.getChildText( "artifactId" ).orElse( null );
+        final String version = dependency.getChildText( "version" ).orElse( null );
+        final String type = dependency.getChildText( "type" ).orElse( null );
 
 
         final List<LicenseInfo> licenseInfos = dependency.getChild( "licenses" )
         final List<LicenseInfo> licenseInfos = dependency.getChild( "licenses" )
                 .map( LicenseInfoReader::readLicenses )
                 .map( LicenseInfoReader::readLicenses )
@@ -97,8 +97,8 @@ public class LicenseInfoReader
 
 
     private static LicenseInfo readLicenseInfo( final XmlElement license )
     private static LicenseInfo readLicenseInfo( final XmlElement license )
     {
     {
-        final String licenseUrl = license.getChildText( "url" );
-        final String licenseName = license.getChildText( "name" );
+        final String licenseUrl = license.getChildText( "url" ).orElse( null );
+        final String licenseName = license.getChildText( "name" ).orElse( null );
         return new LicenseInfo( licenseUrl, licenseName );
         return new LicenseInfo( licenseUrl, licenseName );
     }
     }
 
 

+ 1 - 59
server/src/main/java/password/pwm/util/java/XmlDocument.java

@@ -20,18 +20,11 @@
 
 
 package password.pwm.util.java;
 package password.pwm.util.java;
 
 
-import org.jdom2.Document;
-import org.jdom2.Element;
-import org.jdom2.filter.Filters;
-import org.jdom2.xpath.XPathExpression;
-import org.jdom2.xpath.XPathFactory;
 import org.w3c.dom.NodeList;
 import org.w3c.dom.NodeList;
 
 
 import javax.xml.xpath.XPath;
 import javax.xml.xpath.XPath;
 import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathExpressionException;
 import javax.xml.xpath.XPathExpressionException;
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.List;
 import java.util.Optional;
 import java.util.Optional;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.Lock;
@@ -46,58 +39,7 @@ public interface XmlDocument
     List<XmlElement> evaluateXpathToElements( String xpathExpression );
     List<XmlElement> evaluateXpathToElements( String xpathExpression );
 
 
     XmlDocument copy();
     XmlDocument copy();
-
-    class XmlDocumentJDOM implements XmlDocument
-    {
-        final Document document;
-
-        XmlDocumentJDOM( final Document document )
-        {
-            this.document = document;
-        }
-
-        @Override
-        public XmlElement getRootElement()
-        {
-            return new XmlElement.XmlElementJDOM( document.getRootElement() );
-        }
-
-        @Override
-        public Optional<XmlElement> evaluateXpathToElement(
-                final String xpathExpression
-        )
-        {
-            final XPathFactory xpfac = XPathFactory.instance();
-            final XPathExpression<Element> xp = xpfac.compile( xpathExpression, Filters.element() );
-            final Element element = xp.evaluateFirst( document );
-            return element == null
-                    ? Optional.empty()
-                    : Optional.of( new XmlElement.XmlElementJDOM( element ) );
-        }
-
-        @Override
-        public List<XmlElement> evaluateXpathToElements(
-                final String xpathExpression
-        )
-        {
-            final List<XmlElement> returnList = new ArrayList<>(  );
-
-            final XPathFactory xpfac = XPathFactory.instance();
-            final XPathExpression<Element> xp = xpfac.compile( xpathExpression, Filters.element() );
-            for ( final Element element : xp.evaluate( document ) )
-            {
-                returnList.add( new XmlElement.XmlElementJDOM( element ) );
-            }
-            return Collections.unmodifiableList( returnList );
-        }
-
-        @Override
-        public XmlDocument copy()
-        {
-            return new XmlDocumentJDOM( document.clone() );
-        }
-    }
-
+    
     class XmlDocumentW3c implements XmlDocument
     class XmlDocumentW3c implements XmlDocument
     {
     {
         final org.w3c.dom.Document document;
         final org.w3c.dom.Document document;

+ 10 - 186
server/src/main/java/password/pwm/util/java/XmlElement.java

@@ -20,10 +20,6 @@
 
 
 package password.pwm.util.java;
 package password.pwm.util.java;
 
 
-import org.jdom2.Comment;
-import org.jdom2.Content;
-import org.jdom2.Element;
-import org.jdom2.Text;
 import org.w3c.dom.Node;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.w3c.dom.NodeList;
 
 
@@ -39,15 +35,13 @@ public interface XmlElement
 {
 {
     Optional<XmlElement> getChild( String elementName );
     Optional<XmlElement> getChild( String elementName );
 
 
-    String getAttributeValue( String attribute );
+    Optional<String> getAttributeValue( String attribute );
 
 
     List<XmlElement> getChildren( String elementName );
     List<XmlElement> getChildren( String elementName );
 
 
-    String getText();
-
-    String getTextTrim();
-
-    String getChildText( String elementName );
+    Optional<String> getText();
+    
+    Optional<String> getChildText( String elementName );
 
 
     String getName();
     String getName();
 
 
@@ -73,161 +67,6 @@ public interface XmlElement
 
 
     XmlElement parent();
     XmlElement parent();
 
 
-    class XmlElementJDOM implements XmlElement
-    {
-        private final Element element;
-
-        XmlElementJDOM( final Element element )
-        {
-            this.element = element;
-        }
-
-        @Override
-        public String getName()
-        {
-            return element.getName();
-        }
-
-        @Override
-        public Optional<XmlElement> getChild( final String elementName )
-        {
-            final List<XmlElement> children = getChildren( elementName );
-            if ( JavaHelper.isEmpty( children ) )
-            {
-                return Optional.empty();
-            }
-            return Optional.of( children.iterator().next() );
-        }
-
-        @Override
-        public String getAttributeValue( final String attribute )
-        {
-            return element.getAttributeValue( attribute );
-        }
-
-        @Override
-        public List<XmlElement> getChildren()
-        {
-            return getChildren( null );
-        }
-
-        @Override
-        public List<XmlElement> getChildren( final String elementName )
-        {
-
-            final List<Element> children = elementName == null
-                    ? element.getChildren()
-                    : element.getChildren( elementName );
-            if ( children == null )
-            {
-                return Collections.emptyList();
-            }
-            final List<XmlElement> xmlElements = new ArrayList<>();
-            for ( final Element element : children )
-            {
-                xmlElements.add( new XmlElementJDOM( element ) );
-            }
-            return xmlElements;
-        }
-
-        @Override
-        public String getText()
-        {
-            return element.getText();
-        }
-
-        @Override
-        public String getTextTrim()
-        {
-            return element.getTextTrim();
-        }
-
-        @Override
-        public String getChildText( final String elementName )
-        {
-            final Optional<XmlElement> child = getChild( elementName );
-            return child.map( XmlElement::getText ).orElse( null );
-        }
-
-        @Override
-        public void setAttribute( final String name, final String value )
-        {
-            element.setAttribute( name, value );
-        }
-
-        @Override
-        public void detach()
-        {
-            element.detach();
-        }
-
-        @Override
-        public void removeContent()
-        {
-            element.removeContent();
-        }
-
-        @Override
-        public void removeAttribute( final String attributeName )
-        {
-            element.removeAttribute( attributeName );
-        }
-
-        @Override
-        public void addContent( final XmlElement element )
-        {
-            this.element.addContent( ( ( XmlElementJDOM) element ).element );
-        }
-
-        @Override
-        public void addContent( final List<XmlElement> elements )
-        {
-            for ( final XmlElement loopElement : elements )
-            {
-                final Element jdomElement = ( ( XmlElementJDOM ) loopElement ).element;
-                this.element.addContent( jdomElement );
-            }
-        }
-
-        @Override
-        public void addText( final String text )
-        {
-            element.addContent( new Text( text ) );
-        }
-
-        @Override
-        public void setComment( final List<String> textLines )
-        {
-            final List<Content> contentList = new ArrayList<>( element.getContent() );
-            for ( final Content content : contentList )
-            {
-                if ( content instanceof Comment )
-                {
-                    content.detach();
-                }
-            }
-
-            final List<String> reversedList = new ArrayList<>( textLines );
-            Collections.reverse( reversedList );
-            for ( final String text : textLines )
-            {
-                element.addContent( 0, new Comment( text ) );
-            }
-        }
-
-        @Override
-        public XmlElement copy()
-        {
-            return new XmlElementJDOM( this.element.clone() );
-        }
-
-        @Override
-        public XmlElement parent()
-        {
-            return new XmlElementJDOM( this.element.getParentElement() );
-        }
-    }
-
     class XmlElementW3c implements XmlElement
     class XmlElementW3c implements XmlElement
     {
     {
         private final org.w3c.dom.Element element;
         private final org.w3c.dom.Element element;
@@ -265,13 +104,13 @@ public interface XmlElement
         }
         }
 
 
         @Override
         @Override
-        public String getAttributeValue( final String attribute )
+        public Optional<String> getAttributeValue( final String attribute )
         {
         {
             lock.lock();
             lock.lock();
             try
             try
             {
             {
                 final String attrValue = element.getAttribute( attribute );
                 final String attrValue = element.getAttribute( attribute );
-                return StringUtil.isEmpty( attrValue ) ? null : attrValue;
+                return StringUtil.isEmpty( attrValue ) ? Optional.empty() : Optional.of( attrValue );
             }
             }
             finally
             finally
             {
             {
@@ -310,28 +149,13 @@ public interface XmlElement
         }
         }
 
 
         @Override
         @Override
-        public String getText()
+        public Optional<String> getText()
         {
         {
             lock.lock();
             lock.lock();
             try
             try
             {
             {
                 final String value = element.getTextContent();
                 final String value = element.getTextContent();
-                return value == null ? "" : value;
-            }
-            finally
-            {
-                lock.unlock();
-            }
-        }
-
-        @Override
-        public String getTextTrim()
-        {
-            lock.lock();
-            try
-            {
-                final String result = element.getTextContent();
-                return result == null ? null : result.trim();
+                return StringUtil.isEmpty( value ) ? Optional.empty() : Optional.of( value );
             }
             }
             finally
             finally
             {
             {
@@ -340,10 +164,10 @@ public interface XmlElement
         }
         }
 
 
         @Override
         @Override
-        public String getChildText( final String elementName )
+        public Optional<String> getChildText( final String elementName )
         {
         {
             final Optional<XmlElement> child = getChild( elementName );
             final Optional<XmlElement> child = getChild( elementName );
-            return child.map( XmlElement::getText ).orElse( null );
+            return child.flatMap( XmlElement::getText );
         }
         }
 
 
         @Override
         @Override

+ 1 - 117
server/src/main/java/password/pwm/util/java/XmlFactory.java

@@ -20,11 +20,6 @@
 
 
 package password.pwm.util.java;
 package password.pwm.util.java;
 
 
-import org.jdom2.Document;
-import org.jdom2.input.SAXBuilder;
-import org.jdom2.input.sax.XMLReaders;
-import org.jdom2.output.Format;
-import org.jdom2.output.XMLOutputter;
 import org.w3c.dom.Node;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.w3c.dom.NodeList;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.ErrorInformation;
@@ -43,24 +38,15 @@ import javax.xml.transform.stream.StreamResult;
 import java.io.IOException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
 import java.nio.charset.Charset;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
-import java.util.Objects;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.concurrent.locks.ReentrantLock;
 
 
 public interface XmlFactory
 public interface XmlFactory
 {
 {
-    enum FactoryType
-    {
-        JDOM,
-        W3C,
-    }
-
     enum OutputFlag
     enum OutputFlag
     {
     {
         Compact,
         Compact,
@@ -81,108 +67,6 @@ public interface XmlFactory
         return new XmlFactoryW3c();
         return new XmlFactoryW3c();
     }
     }
 
 
-    static XmlFactory getFactory( final FactoryType factoryType )
-    {
-        switch ( factoryType )
-        {
-            case JDOM:
-                return new XmlFactoryJDOM();
-
-            case W3C:
-                return new XmlFactoryW3c();
-
-            default:
-                JavaHelper.unhandledSwitchStatement( factoryType );
-
-        }
-
-        return null;
-    }
-
-
-    class XmlFactoryJDOM implements XmlFactory
-    {
-        private static final Charset STORAGE_CHARSET = StandardCharsets.UTF_8;
-
-        XmlFactoryJDOM()
-        {
-        }
-
-        @Override
-        public XmlDocument parseXml( final InputStream inputStream )
-                throws PwmUnrecoverableException
-        {
-            Objects.requireNonNull( inputStream );
-
-            final SAXBuilder builder = getBuilder();
-            final Document inputDocument;
-            try
-            {
-                inputDocument = builder.build( inputStream );
-            }
-            catch ( final Exception e )
-            {
-                throw new PwmUnrecoverableException( new ErrorInformation( PwmError.CONFIG_FORMAT_ERROR, null, new String[]
-                        {
-                                "error parsing xml data: " + e.getMessage(),
-                        }
-                ) );
-            }
-            return new XmlDocument.XmlDocumentJDOM( inputDocument );
-        }
-
-        public static void outputJDOMDocument( final Document document, final OutputStream outputStream )
-                throws IOException
-        {
-            new XmlFactoryJDOM().outputDocument( document, outputStream );
-        }
-
-        @Override
-        public void outputDocument( final XmlDocument document, final OutputStream outputStream, final OutputFlag... outputFlags )
-                throws IOException
-        {
-            final Document jdomDoc =  ( ( XmlDocument.XmlDocumentJDOM )  document ).document;
-            this.outputDocument( jdomDoc, outputStream );
-        }
-
-        private void outputDocument( final Document document, final OutputStream outputStream )
-                throws IOException
-        {
-            final Format format = Format.getPrettyFormat();
-            format.setEncoding( STORAGE_CHARSET.toString() );
-            final XMLOutputter outputter = new XMLOutputter();
-            outputter.setFormat( format );
-
-            try ( Writer writer = new OutputStreamWriter( outputStream, STORAGE_CHARSET ) )
-            {
-                outputter.output( document, writer );
-            }
-        }
-
-        private static SAXBuilder getBuilder( )
-        {
-            final SAXBuilder builder = new SAXBuilder();
-            builder.setExpandEntities( false );
-            builder.setXMLReaderFactory( XMLReaders.NONVALIDATING );
-            builder.setFeature( "http://xml.org/sax/features/resolve-dtd-uris", false );
-            return builder;
-        }
-
-        @Override
-        public XmlDocument newDocument( final String rootElementName )
-        {
-            final org.jdom2.Element rootElement = new org.jdom2.Element( rootElementName );
-            final org.jdom2.Document newDoc = new org.jdom2.Document( rootElement );
-            return new XmlDocument.XmlDocumentJDOM( newDoc );
-        }
-
-        @Override
-        public XmlElement newElement( final String name )
-        {
-            return new XmlElement.XmlElementJDOM( new org.jdom2.Element ( name ) );
-        }
-    }
-
     class XmlFactoryW3c implements XmlFactory
     class XmlFactoryW3c implements XmlFactory
     {
     {
         private static final Charset STORAGE_CHARSET = StandardCharsets.UTF_8;
         private static final Charset STORAGE_CHARSET = StandardCharsets.UTF_8;
@@ -206,7 +90,7 @@ public interface XmlFactory
                 throw new PwmUnrecoverableException( new ErrorInformation( PwmError.CONFIG_FORMAT_ERROR, null, new String[]
                 throw new PwmUnrecoverableException( new ErrorInformation( PwmError.CONFIG_FORMAT_ERROR, null, new String[]
                         {
                         {
                                 "error parsing xml data: " + e.getMessage(),
                                 "error parsing xml data: " + e.getMessage(),
-                        }
+                                }
                 ) );
                 ) );
             }
             }
             return new XmlDocument.XmlDocumentW3c( inputDocument );
             return new XmlDocument.XmlDocumentW3c( inputDocument );

+ 3 - 2
server/src/main/java/password/pwm/util/logging/PwmLogManager.java

@@ -29,6 +29,7 @@ import org.apache.log4j.PatternLayout;
 import org.apache.log4j.RollingFileAppender;
 import org.apache.log4j.RollingFileAppender;
 import org.apache.log4j.xml.DOMConfigurator;
 import org.apache.log4j.xml.DOMConfigurator;
 import password.pwm.AppProperty;
 import password.pwm.AppProperty;
+import password.pwm.PwmApplication;
 import password.pwm.PwmApplicationMode;
 import password.pwm.PwmApplicationMode;
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
 import password.pwm.PwmDomain;
 import password.pwm.PwmDomain;
@@ -48,7 +49,7 @@ public class PwmLogManager
     private static final PwmLogger LOGGER = PwmLogger.forClass( PwmLogManager.class );
     private static final PwmLogger LOGGER = PwmLogger.forClass( PwmLogManager.class );
 
 
     public static final List<String> LOGGING_PACKAGES = List.of(
     public static final List<String> LOGGING_PACKAGES = List.of(
-            PwmDomain.class.getPackage().getName(),
+            PwmApplication.class.getPackage().getName(),
             ChaiUser.class.getPackage().getName(),
             ChaiUser.class.getPackage().getName(),
             "org.jasig.cas.client" );
             "org.jasig.cas.client" );
 
 
@@ -245,7 +246,7 @@ public class PwmLogManager
             localDBLog4jAppender.setThreshold( localDBLogLevel.getLog4jLevel() );
             localDBLog4jAppender.setThreshold( localDBLogLevel.getLog4jLevel() );
             for ( final String logPackage : LOGGING_PACKAGES )
             for ( final String logPackage : LOGGING_PACKAGES )
             {
             {
-                if ( logPackage != null && !logPackage.equals( PwmDomain.class.getPackage() ) )
+                if ( logPackage != null && !logPackage.equals( PwmApplication.class.getPackage().getName() ) )
                 {
                 {
                     final Logger logger = Logger.getLogger( logPackage );
                     final Logger logger = Logger.getLogger( logPackage );
                     logger.addAppender( localDBLog4jAppender );
                     logger.addAppender( localDBLog4jAppender );

+ 5 - 3
server/src/test/java/password/pwm/config/PwmSettingTest.java

@@ -25,7 +25,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.junit.rules.TemporaryFolder;
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
-import password.pwm.config.stored.StoredConfigXmlSerializer;
+import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.value.StoredValue;
 import password.pwm.config.value.StoredValue;
 import password.pwm.config.value.StoredValueEncoder;
 import password.pwm.config.value.StoredValueEncoder;
@@ -66,7 +66,7 @@ public class PwmSettingTest
                 storedValue.toNativeObject();
                 storedValue.toNativeObject();
                 storedValue.toDebugString( PwmConstants.DEFAULT_LOCALE );
                 storedValue.toDebugString( PwmConstants.DEFAULT_LOCALE );
                 storedValue.toDebugJsonObject( PwmConstants.DEFAULT_LOCALE );
                 storedValue.toDebugJsonObject( PwmConstants.DEFAULT_LOCALE );
-                storedValue.toXmlValues( StoredConfigXmlSerializer.StoredConfigXmlConstants.XML_ELEMENT_VALUE, outputSettings );
+                storedValue.toXmlValues( StoredConfigXmlConstants.XML_ELEMENT_VALUE, outputSettings );
                 storedValue.validateValue( pwmSetting );
                 storedValue.validateValue( pwmSetting );
                 Assert.assertNotNull( storedValue.valueHash() );
                 Assert.assertNotNull( storedValue.valueHash() );
                 JsonUtil.serialize( (Serializable) storedValue.toNativeObject() );
                 JsonUtil.serialize( (Serializable) storedValue.toNativeObject() );
@@ -112,7 +112,9 @@ public class PwmSettingTest
         final List<XmlElement> results = xmlDoc.evaluateXpathToElements( expression );
         final List<XmlElement> results = xmlDoc.evaluateXpathToElements( expression );
         for ( final XmlElement result : results )
         for ( final XmlElement result : results )
         {
         {
-            final String key = result.getAttributeValue( "key" );
+            final String key = result.getAttributeValue( "key" )
+                    .orElseThrow( () -> new IllegalStateException( "setting element " + result.getName() + " missing key attribute" ) );
+
             Assert.assertFalse( StringUtil.isEmpty( key ) );
             Assert.assertFalse( StringUtil.isEmpty( key ) );
             final Optional<PwmSetting> pwmSetting = PwmSetting.forKey( key );
             final Optional<PwmSetting> pwmSetting = PwmSetting.forKey( key );
             Assert.assertTrue( "unknown PwmSetting.xml setting reference for key " + key, pwmSetting.isPresent() );
             Assert.assertTrue( "unknown PwmSetting.xml setting reference for key " + key, pwmSetting.isPresent() );

+ 8 - 3
server/src/test/java/password/pwm/config/PwmSettingXmlTest.java

@@ -69,7 +69,8 @@ public class PwmSettingXmlTest
         Assert.assertFalse( settingElements.isEmpty() );
         Assert.assertFalse( settingElements.isEmpty() );
         for ( final XmlElement element : settingElements )
         for ( final XmlElement element : settingElements )
         {
         {
-            final String key = element.getAttributeValue( "key" );
+            final String key = element.getAttributeValue( "key" )
+                    .orElseThrow( () -> new IllegalStateException( "setting element " + element.getName() + " missing key attribute" ) );
 
 
             final String errorMsg = "PwmSetting.xml contains setting key of '"
             final String errorMsg = "PwmSetting.xml contains setting key of '"
                     + key + "' which does not exist in PwmSetting.java";
                     + key + "' which does not exist in PwmSetting.java";
@@ -94,7 +95,9 @@ public class PwmSettingXmlTest
         Assert.assertFalse( categoryElements.isEmpty() );
         Assert.assertFalse( categoryElements.isEmpty() );
         for ( final XmlElement element : categoryElements )
         for ( final XmlElement element : categoryElements )
         {
         {
-            final String key = element.getAttributeValue( "key" );
+            final String key = element.getAttributeValue( "key" )
+                    .orElseThrow( () -> new IllegalStateException( "category element " + element.getName() + " missing key attribute" ) );
+
             final PwmSettingCategory category = JavaHelper.readEnumFromString( PwmSettingCategory.class, null, key );
             final PwmSettingCategory category = JavaHelper.readEnumFromString( PwmSettingCategory.class, null, key );
 
 
             final String errorMsg = "PwmSetting.xml contains category key of '"
             final String errorMsg = "PwmSetting.xml contains category key of '"
@@ -110,7 +113,9 @@ public class PwmSettingXmlTest
         Assert.assertFalse( profileElements.isEmpty() );
         Assert.assertFalse( profileElements.isEmpty() );
         for ( final XmlElement element : profileElements )
         for ( final XmlElement element : profileElements )
         {
         {
-            final String settingKey = element.getAttributeValue( "setting" );
+            final String settingKey = element.getAttributeValue( "setting" )
+                    .orElseThrow( () -> new IllegalStateException( "profile element " + element.getName() + " missing setting attribute" ) );
+
             final Optional<PwmSetting> setting = PwmSetting.forKey( settingKey );
             final Optional<PwmSetting> setting = PwmSetting.forKey( settingKey );
 
 
             final String errorMsg = "PwmSetting.xml contains category/profile@setting key of '"
             final String errorMsg = "PwmSetting.xml contains category/profile@setting key of '"

+ 2 - 2
server/src/test/java/password/pwm/svc/event/LdapXmlUserHistoryTest.java

@@ -87,8 +87,8 @@ public class LdapXmlUserHistoryTest
         Assert.assertTrue( optionalRecordElement.isPresent() );
         Assert.assertTrue( optionalRecordElement.isPresent() );
         optionalRecordElement.ifPresent( xmlElement ->
         optionalRecordElement.ifPresent( xmlElement ->
         {
         {
-            Assert.assertEquals( "EventLog_ChangePassword", xmlElement.getAttributeValue( "eventCode" ) );
-            Assert.assertEquals( "1582824390000", xmlElement.getAttributeValue( "timestamp" ) );
+            Assert.assertEquals( "EventLog_ChangePassword", xmlElement.getAttributeValue( "eventCode" ).orElseThrow() );
+            Assert.assertEquals( "1582824390000", xmlElement.getAttributeValue( "timestamp" ).orElseThrow() );
         } );
         } );
     }
     }
 }
 }

+ 3 - 10
server/src/test/java/password/pwm/util/java/XmlFactoryBenchmarkExtendedTest.java

@@ -59,20 +59,13 @@ public class XmlFactoryBenchmarkExtendedTest
     public void benchmarkW3c ()
     public void benchmarkW3c ()
             throws Exception
             throws Exception
     {
     {
-        benchmarkImpl( XmlFactory.FactoryType.W3C );
+        benchmarkImpl( );
     }
     }
 
 
-    @Benchmark
-    public void benchmarkJDom ()
-            throws Exception
-    {
-        benchmarkImpl( XmlFactory.FactoryType.JDOM );
-    }
-
-    private void benchmarkImpl ( final XmlFactory.FactoryType factoryType )
+    private void benchmarkImpl ()
             throws Exception
             throws Exception
     {
     {
-        final XmlFactory xmlFactory = XmlFactory.getFactory( factoryType );
+        final XmlFactory xmlFactory = XmlFactory.getFactory();
         final InputStream xmlFactoryTestXmlFile = XmlFactoryTest.class.getResourceAsStream( "XmlFactoryTest.xml" );
         final InputStream xmlFactoryTestXmlFile = XmlFactoryTest.class.getResourceAsStream( "XmlFactoryTest.xml" );
         final XmlDocument xmlDocument = xmlFactory.parseXml( xmlFactoryTestXmlFile );
         final XmlDocument xmlDocument = xmlFactory.parseXml( xmlFactoryTestXmlFile );
         xmlFactory.outputDocument( xmlDocument, new NullOutputStream() );
         xmlFactory.outputDocument( xmlDocument, new NullOutputStream() );

+ 1 - 1
server/src/test/java/password/pwm/util/java/XmlFactoryTest.java

@@ -39,7 +39,7 @@ public class XmlFactoryTest
         Assert.assertEquals( "PwmConfiguration", xmlDocument.getRootElement().getName() );
         Assert.assertEquals( "PwmConfiguration", xmlDocument.getRootElement().getName() );
         final Optional<XmlElement> configIsEditable = xmlDocument.evaluateXpathToElement( "//property[@key='configIsEditable']" );
         final Optional<XmlElement> configIsEditable = xmlDocument.evaluateXpathToElement( "//property[@key='configIsEditable']" );
         Assert.assertTrue( configIsEditable.isPresent() );
         Assert.assertTrue( configIsEditable.isPresent() );
-        Assert.assertEquals( "false", configIsEditable.get().getText() );
+        Assert.assertEquals( "false", configIsEditable.get().getText().orElseThrow() );
         final List<XmlElement> allSettings = xmlDocument.evaluateXpathToElements( "//setting" );
         final List<XmlElement> allSettings = xmlDocument.evaluateXpathToElements( "//setting" );
         Assert.assertEquals( 279, allSettings.size() );
         Assert.assertEquals( 279, allSettings.size() );
     }
     }