001package org.dcm4che3.conf.core;
002
003import org.dcm4che3.conf.core.api.Configuration;
004import org.dcm4che3.conf.core.api.ConfigurationException;
005import org.dcm4che3.conf.core.api.Path;
006import org.dcm4che3.conf.core.api.internal.ConfigProperty;
007import org.dcm4che3.conf.core.api.internal.ConfigReflection;
008import org.dcm4che3.conf.core.util.ConfigNodeTraverser;
009import org.slf4j.Logger;
010import org.slf4j.LoggerFactory;
011
012import java.util.List;
013import java.util.Map;
014
015/**
016 * Ensures that extensions are not deleted, even if they are unknown to the caller of persistNode
017 */
018public class ExtensionMergingConfiguration extends DelegatingConfiguration {
019
020    private static Logger log = LoggerFactory.getLogger(ExtensionMergingConfiguration.class);
021
022    protected List<Class> allExtensionClasses;
023
024    public ExtensionMergingConfiguration(Configuration delegate, List<Class> allExtensionClasses) {
025        super(delegate);
026        this.allExtensionClasses = allExtensionClasses;
027    }
028
029    @Override
030    public void persistNode(Path path, Map<String, Object> configNode, Class configurableClass) throws ConfigurationException {
031
032        // make sure we don't delete the extensions we are not aware of
033
034        if (configurableClass != null) {
035            Object currentConfigurationNode = super.getConfigurationNode(path, configurableClass);
036
037            ConfigNodeTraverser.dualTraverseNodeTypesafe(configNode, currentConfigurationNode, ConfigReflection.getDummyPropertyForClass(configurableClass), allExtensionClasses, new ConfigNodeTraverser.ConfigNodesTypesafeFilter() {
038                @Override
039                public void beforeNodes(Map<String, Object> containerNode1, Map<String, Object> containerNode2, Class containerNodeClass, ConfigProperty property) throws ConfigurationException {
040
041                if (property.isExtensionsProperty()) {
042                        //Preserve each key of the current configuration that do not belong to the new configuration
043                        Map<String, Object> extensionsMap1 = (Map<String, Object>) containerNode1.get(property.getAnnotatedName());
044                        Map<String, Object> extensionsMap2 = (Map<String, Object>) containerNode2.get(property.getAnnotatedName());
045
046                        if(extensionsMap1 == null && extensionsMap2 == null) return;
047
048                        if(extensionsMap1 == null){
049                            containerNode1.put(property.getAnnotatedName(), extensionsMap2);
050                            return;
051                        }
052
053                        if(extensionsMap2 == null) return;
054
055                        for (String key : extensionsMap2.keySet()) {
056                            if(!extensionsMap1.containsKey(key)){
057                                extensionsMap1.put(key,extensionsMap2.get(key));
058                            }
059                        }
060                    }
061                }
062            });
063        }
064        super.persistNode(path, configNode, configurableClass);
065    }
066}