public String getProperty(String name, boolean ignoreEmpty) {
        String value = null;
        boolean mustRewrite = false;

        final Lock readLock = readWriteLock.readLock();
        readLock.lock();
        try {
            if (propertyCache.containsKey(name)) {
                return propertyCache.get(name).orElse(null);
            }

            String[] propName = parsePropertyName(name);
            // Search for this property by traversing down the XML hierarchy.
            Element element = document.getRootElement();
            for (String aPropName : propName) {
                element = element.element(aPropName);
                if (element == null) {
                    // This node doesn't match this part of the property name which
                    // indicates this property doesn't exist so return null.
                    propertyCache.put(name, Optional.empty());
                    return null;
                }
            }
            // At this point, we found a matching property, so return its value.
            // Empty strings are returned as null.
            value = element.getTextTrim();
            if (ignoreEmpty && "".equals(value)) {
                propertyCache.put(name, Optional.empty());
                return null;
            } else {
                // check to see if the property is marked as encrypted
                if (JiveGlobals.isXMLPropertyEncrypted(name)) {
                    Attribute encrypted = element.attribute(ENCRYPTED_ATTRIBUTE);
                    if (encrypted != null) {
                        value = JiveGlobals.getPropertyEncryptor().decrypt(value);
                    } else {
                        // rewrite property as an encrypted value
                        Log.info("Rewriting XML property " + name + " as an encrypted value");
                        mustRewrite = true;
                    }
                }
                // Add to cache so that getting property next time is fast.
                propertyCache.put(name, Optional.ofNullable(value));
                return value;
            }
        } finally {
            readLock.unlock();

            // Outside read-lock: ReentrantReadWriteLock does not allow obtaining a write-lock while a read-lock is acquired.
            if (mustRewrite) {
                setProperty(name, value);
            }
        }
    }
Returns the value of the specified property.

@param name the name of the property to get.
@param ignoreEmpty Ignore empty property values (return null)
@return the value of the specified property.
xmppserver/src/main/java/org/jivesoftware/util/XMLProperties.java