You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tamaya.apache.org by an...@apache.org on 2017/10/16 23:03:21 UTC

[5/7] incubator-tamaya-extensions git commit: TAMAYA-300 Added tests to improve mutation coverage. Movewd OSGI and MP to extensions.

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/a1cd433a/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/TamayaConfigPlugin.java
----------------------------------------------------------------------
diff --git a/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/TamayaConfigPlugin.java b/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/TamayaConfigPlugin.java
new file mode 100644
index 0000000..e095b14
--- /dev/null
+++ b/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/TamayaConfigPlugin.java
@@ -0,0 +1,444 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.tamaya.osgi;
+
+import org.apache.tamaya.osgi.commands.TamayaConfigService;
+import org.osgi.framework.*;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Tamaya plugin that updates/extends the component configurations managed
+ * by {@link ConfigurationAdmin}, based on the configured {@link Policy}.
+ */
+public class TamayaConfigPlugin implements TamayaConfigService,BundleListener, ServiceListener{
+    static final String COMPONENTID = "TamayaConfigPlugin";
+    /** the logger. */
+    private static final Logger LOG = Logger.getLogger(TamayaConfigPlugin.class.getName());
+
+    public static final String TAMAYA_POLICY_PROP = "tamaya-policy";
+    public static final String TAMAYA_POLICY_MANIFEST = "Tamaya-Policy";
+    public static final String TAMAYA_CUSTOM_ROOT_PROP = "tamaya-config-root";
+    public static final String TAMAYA_CUSTOM_ROOT_MANIFEST = "Tamaya-Config-Root";
+    public static final String TAMAYA_ENABLED_PROP = "tamaya-enabled";
+    public static final String TAMAYA_ENABLED_MANIFEST = "Tamaya-Enabled";
+    public static final String TAMAYA_AUTO_UPDATE_ENABLED_PROP = "tamaya-update-enabled";
+    public static final String TAMAYA_AUTO_UPDATE_ENABLED_MANIFEST = "Tamaya-Update-Enabled";
+    private boolean enabledByDefault = false;
+
+    private Policy defaultPolicy = Policy.OVERRIDE;
+
+    private ConfigChanger configChanger;
+    private boolean autoUpdateEnabled;
+
+    @Override
+    public void serviceChanged(ServiceEvent event) {
+        switch(event.getType()){
+            case ServiceEvent.REGISTERED:
+            case ServiceEvent.MODIFIED:
+                configureService(event);
+                break;
+            case ServiceEvent.UNREGISTERING:
+                // unconfigure...? Currently nothing here.
+                break;
+        }
+    }
+
+
+    /**
+     * Create a new getConfig.
+     * @param context the OSGI context
+     */
+    public TamayaConfigPlugin(BundleContext context) {
+        configChanger = new ConfigChanger(context);
+        Dictionary<String,Object> props = getPluginConfig();
+        Backups.restore(props);
+        ConfigHistory.restore(props);
+        initDefaultEnabled(props);
+        initAutoUpdateEnabled(props);
+        initDefaultOpMode(props);
+        initConfigs();
+    }
+
+    @Override
+    public void setAutoUpdateEnabled(boolean enabled){
+        this.autoUpdateEnabled = enabled;
+        setConfigValue(TAMAYA_AUTO_UPDATE_ENABLED_PROP, enabled);
+    }
+
+    @Override
+    public void setTamayaEnabledByDefault(boolean enabledByDefault){
+        this.enabledByDefault = enabledByDefault;
+        setConfigValue(TAMAYA_ENABLED_PROP, enabledByDefault);
+    }
+
+    @Override
+    public boolean isTamayaEnabledByDefault(){
+        return enabledByDefault;
+    }
+
+    @Override
+    public Policy getDefaultPolicy(){
+        return defaultPolicy;
+    }
+
+    @Override
+    public void setDefaultPolicy(Policy mode){
+        this.defaultPolicy = Objects.requireNonNull(mode);
+        setConfigValue(Policy.class.getSimpleName(), defaultPolicy.toString());
+    }
+
+    @Override
+    public void bundleChanged(BundleEvent event) {
+        switch(event.getType()){
+            case BundleEvent.STARTING:
+            case BundleEvent.LAZY_ACTIVATION:
+                configureBundle(event.getBundle());
+                break;
+        }
+    }
+
+    private void initConfigs() {
+        // Check for matching bundles already installed...
+        for(Bundle bundle:configChanger.getContext().getBundles()){
+            switch(bundle.getState()){
+                case Bundle.ACTIVE:
+                    configureBundle(bundle);
+                    break;
+            }
+        }
+    }
+
+    private void configureService(ServiceEvent event) {
+        // Optional MANIFEST entries
+        Bundle bundle = event.getServiceReference().getBundle();
+        if(!isBundleEnabled(bundle)){
+            return;
+        }
+        String pid = (String)event.getServiceReference().getProperty(Constants.SERVICE_PID);
+        if(pid==null){
+            LOG.finest("No service pid for: " + event.getServiceReference());
+            return;
+        }
+        configChanger.configure(pid, event.getServiceReference().getBundle(), defaultPolicy, false, false);
+        Dictionary<String,Object> props = getPluginConfig();
+        Backups.save(props);
+        ConfigHistory.save(props);
+        setPluginConfig(props);
+    }
+
+    @Override
+    public Dictionary<String,Object> updateConfig(String pid) {
+        return updateConfig(pid, defaultPolicy, false, false);
+    }
+
+    @Override
+    public Dictionary<String,Object> updateConfig(String pid, boolean dryRun) {
+        return updateConfig(pid, defaultPolicy, false, dryRun);
+    }
+
+    @Override
+    public Dictionary<String,Object> updateConfig(String pid, Policy opMode, boolean explicitMode, boolean dryRun) {
+        if(dryRun){
+            return configChanger.configure(pid, null, opMode, explicitMode, true);
+        }else {
+            LOG.fine("Updating getConfig for pid...: " + pid);
+            Dictionary<String,Object> result = configChanger.configure(pid, null, opMode, explicitMode, false);
+            Dictionary<String,Object> props = getPluginConfig();
+            Backups.save(props);
+            ConfigHistory.save(props);
+            setPluginConfig(props);
+            return result;
+        }
+    }
+
+    private void configureBundle(Bundle bundle) {
+        if(!isBundleEnabled(bundle)){
+            return;
+        }
+        String tamayaPid = bundle.getHeaders().get(TAMAYA_CUSTOM_ROOT_MANIFEST);
+        String pid = tamayaPid!=null?tamayaPid:bundle.getSymbolicName();
+        if(pid==null){
+            pid = bundle.getLocation();
+        }
+        if(pid==null){
+            LOG.finest(() -> "No PID/location for bundle " + bundle.getSymbolicName() + '('+bundle.getBundleId()+')');
+            return;
+        }
+        configChanger.configure(pid, bundle, defaultPolicy, false, false);
+        Dictionary<String,Object> props = getPluginConfig();
+        Backups.save(props);
+        ConfigHistory.save(props);
+        setPluginConfig(props);
+    }
+
+    @Override
+    public boolean isBundleEnabled(Bundle bundle){
+        // Optional MANIFEST entries
+        String bundleEnabledVal = bundle.getHeaders().get(TAMAYA_ENABLED_MANIFEST);
+        if(bundleEnabledVal==null && !enabledByDefault){
+            LOG.finest("tamaya.enabled=false: not configuring bundle: " + bundle.getSymbolicName());
+            return false;
+        }
+        if(bundleEnabledVal != null && !Boolean.parseBoolean(bundleEnabledVal)){
+            LOG.finest("Bundle is explcitly disabled for Tamaya: " + bundle.getSymbolicName());
+            return false;
+        }
+        if(bundleEnabledVal != null && Boolean.parseBoolean(bundleEnabledVal)){
+            LOG.finest("Bundle is explicitly enabled for Tamaya: " + bundle.getSymbolicName());
+            return true;
+        }
+        return true;
+    }
+
+    private boolean isAutoUpdateEnabled(Bundle bundle, Dictionary<String,Object> props) {
+        Object enabledVal = props.get(TAMAYA_AUTO_UPDATE_ENABLED_PROP);
+        if(enabledVal!=null){
+            return Boolean.parseBoolean(enabledVal.toString());
+        }
+        if(bundle!=null){
+            enabledVal = bundle.getHeaders().get(TAMAYA_AUTO_UPDATE_ENABLED_MANIFEST);
+            if(enabledVal!=null){
+                return Boolean.parseBoolean(enabledVal.toString());
+            }
+        }
+        return this.autoUpdateEnabled;
+    }
+
+    private void initAutoUpdateEnabled(Dictionary<String,Object> props) {
+        Object enabledVal = props.get(TAMAYA_AUTO_UPDATE_ENABLED_PROP);
+        if(enabledVal==null && System.getProperty(TAMAYA_AUTO_UPDATE_ENABLED_PROP)!=null){
+            enabledVal = Boolean.parseBoolean(System.getProperty(TAMAYA_AUTO_UPDATE_ENABLED_PROP));
+        }
+        if(enabledVal!=null){
+            this.autoUpdateEnabled = Boolean.parseBoolean(enabledVal.toString());
+        }
+        if(this.autoUpdateEnabled) {
+            LOG.info("Tamaya Automatic Config Update is enabled by default.");
+        }else{
+            LOG.info("Tamaya Automatic Config Update is disabled by default.");
+        }
+    }
+
+    private void initDefaultEnabled(Dictionary<String,Object> props) {
+        Object enabledVal = props.get(TAMAYA_ENABLED_PROP);
+        if(enabledVal==null && System.getProperty(TAMAYA_ENABLED_PROP)!=null){
+            enabledVal = Boolean.parseBoolean(System.getProperty(TAMAYA_ENABLED_PROP));
+        }
+        if(enabledVal!=null){
+            this.enabledByDefault = Boolean.parseBoolean(enabledVal.toString());
+        }
+        if(this.enabledByDefault) {
+            LOG.info("Tamaya Config is enabledByDefault by default. Add Tamaya-Enabled to your bundle manifests to enable it.");
+        }else{
+            LOG.info("Tamaya Config is enabled by default. Add Tamaya-Disabled to your bundle manifests to disable it.");
+        }
+    }
+
+    private void initDefaultOpMode(Dictionary<String,Object> props) {
+        String opVal = (String)props.get(Policy.class.getSimpleName());
+        if(opVal!=null){
+            try{
+                defaultPolicy = Policy.valueOf(opVal);
+            }catch(Exception e){
+                LOG.warning("Invalid Policy: " + opVal +", using default: " + defaultPolicy);
+            }
+        }
+    }
+
+    Dictionary<String, Object> getPluginConfig(){
+        Configuration config = null;
+        try {
+            config = configChanger.getConfigurationAdmin().getConfiguration(COMPONENTID);
+            Dictionary<String, Object> props = null;
+            if (config != null
+                    && config.getProperties() != null) {
+                props = config.getProperties();
+            } else {
+                props = new Hashtable<String, Object>();
+            }
+            return props;
+        } catch (IOException e) {
+            throw new IllegalStateException("No Tamaya plugin config.", e);
+        }
+    }
+
+    void setPluginConfig(Dictionary<String, Object> props){
+        Configuration config = null;
+        try {
+            config = configChanger.getConfigurationAdmin().getConfiguration(COMPONENTID);
+            if (config != null) {
+                config.update(props);
+            }
+        } catch (IOException e) {
+            LOG.log(Level.WARNING, "Failed to write Tamaya plugin config.", e);
+        }
+    }
+
+    void setConfigValue(String key, Object value){
+        try {
+            Dictionary<String, Object> props = getPluginConfig();
+            if(props!=null) {
+                props.put(key, value);
+                setPluginConfig(props);
+                LOG.finest("Updated Tamaya Plugin value: " + key + "=" + value);
+            }
+        } catch (Exception e) {
+            LOG.log(Level.WARNING, "Error writing Tamaya config value: " + key, e);
+        }
+    }
+
+    Object getConfigValue(String key){
+        try {
+            Dictionary<String, Object> props = getPluginConfig();
+            if(props!=null){
+                return props.get(key);
+            }
+        } catch (Exception e) {
+            LOG.log(Level.WARNING, "Error reading Tamaya config value.", e);
+        }
+        return null;
+    }
+
+
+    public org.apache.tamaya.Configuration getTamayaConfiguration(String root) {
+        return configChanger.getTamayaConfiguration(root);
+    }
+
+    @Override
+    public boolean isAutoUpdateEnabled() {
+        return this.autoUpdateEnabled;
+    }
+
+    @Override
+    public Dictionary<String, ?> getBackup(String pid) {
+        return Backups.get(pid);
+    }
+
+    @Override
+    public Set<String> getBackupPids() {
+        return Backups.getPids();
+    }
+
+    @Override
+    public boolean restoreBackup(String pid){
+        Dictionary<String,Object> config = (Dictionary<String,Object>) Backups.get(pid);
+        if(config==null){
+            return false;
+        }
+        try {
+            this.configChanger.restoreBackup(pid, config);
+            return true;
+        } catch (IOException e) {
+            LOG.log(Level.WARNING, "Error restoring backup for PID: " + pid, e);
+            return false;
+        }
+    }
+
+    @Override
+    public boolean createBackup(String pid) {
+        if(!Backups.contains(pid)) {
+            Backups.set(pid, getOSGIConfiguration(pid, null));
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean deleteBackup(String pid) {
+        if(Backups.contains(pid)) {
+            Backups.remove(pid);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void setMaxHistorySize(int maxHistory) {
+        ConfigHistory.setMaxHistory(maxHistory);
+    }
+
+    @Override
+    public int getMaxHistorySize() {
+        return ConfigHistory.getMaxHistory();
+    }
+
+    @Override
+    public List<ConfigHistory> getHistory() {
+        return ConfigHistory.getHistory();
+    }
+
+    @Override
+    public void clearHistory() {
+        ConfigHistory.clearHistory();
+    }
+
+    @Override
+    public void clearHistory(String pid) {
+        ConfigHistory.clearHistory(pid);
+    }
+
+    @Override
+    public List<ConfigHistory> getHistory(String pid) {
+        return ConfigHistory.getHistory(pid);
+    }
+
+    @Override
+    public Dictionary<String, Object> getOSGIConfiguration(String pid, String section) {
+        try {
+            Configuration config = configChanger.getConfigurationAdmin().getConfiguration(pid);
+            Dictionary<String, Object> props = null;
+            if (config == null
+                    || config.getProperties() == null) {
+                return null;
+            }
+            props = config.getProperties();
+            if(section!=null){
+                return filter(props, section);
+            }
+            return props;
+        } catch (IOException e) {
+            LOG.log(Level.WARNING, "Error reading OSGI config for PID: " + pid, e);
+            return null;
+        }
+    }
+
+    @Override
+    public boolean containsBackup(String pid) {
+        return Backups.contains(pid);
+    }
+
+    private Dictionary<String, Object> filter(Dictionary<String, Object> props, String section) {
+        Hashtable<String, Object> result = new Hashtable<>();
+        Enumeration<String> keys = props.keys();
+        while(keys.hasMoreElements()){
+            String key = keys.nextElement();
+            if(key.startsWith(section)){
+                result.put(key, props.get(key));
+            }
+        }
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/a1cd433a/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/BackupCommands.java
----------------------------------------------------------------------
diff --git a/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/BackupCommands.java b/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/BackupCommands.java
new file mode 100644
index 0000000..d8734f7
--- /dev/null
+++ b/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/BackupCommands.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.tamaya.osgi.commands;
+
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+
+/**
+ * Utility class implementing the available backup related commands.
+ */
+public final class BackupCommands {
+
+    /** Singleton constructor. */
+    private BackupCommands(){}
+
+    public static String createBackup(TamayaConfigService service, ConfigurationAdmin cm, String pid, boolean force) throws IOException {
+        Configuration cfg = cm.getConfiguration(pid);
+        if(cfg!=null){
+            Dictionary<String,?> props = cfg.getProperties();
+            if(props!=null){
+                if(force && service.getBackup(pid)!=null) {
+                    service.deleteBackup(pid);
+                }
+                if(service.createBackup(pid)){
+                    return "Backup created, PID = " + pid + '\n' +  printProps(props);
+                }else{
+                    return "Creating backup failed. Backup already existing, PID = " + pid;
+                }
+            }
+        }
+        return "Creating backup failed. No Config found, PID = " + pid;
+    }
+
+    public static String deleteBackup(TamayaConfigService service, String pid) throws IOException {
+        if("*".equals(pid)){
+            for(String current: service.getBackupPids()){
+                service.deleteBackup(current);
+            }
+            return "All Backups deleted.";
+        }else {
+            service.deleteBackup(pid);
+            return "Backup deleted: " + pid;
+        }
+    }
+
+    public static String restoreBackup(TamayaConfigService plugin, String pid) throws IOException {
+        StringBuilder b = new StringBuilder("Restored Configurations:\n")
+                .append("------------------------\n");
+        if("*".equals(pid)){
+            for(String current: plugin.getBackupPids()){
+                try{
+                    if(plugin.restoreBackup(current)){
+                        b.append(current).append(" -> restored.\n");
+                    }else{
+                        b.append(current).append(" -> no backup found.\n");
+                    }
+                }catch(Exception e){
+                    b.append(current).append(" -> failed: ").append(e).append('\n');
+                }
+            }
+            return b.toString();
+        }else {
+            try{
+                if(plugin.restoreBackup(pid)){
+                    return "Backup restored for PID: "+pid+"\n";
+                }else{
+                    return "Backup restore failed for PID "+pid+": no backup found.\n";
+                }
+            }catch(Exception e){
+                return "Backup restore failed for PID "+pid+", error: " + e + '\n';
+            }
+        }
+    }
+
+    public static String listBackup(TamayaConfigService plugin, String pid) throws IOException {
+        if(pid!=null){
+            Dictionary<String, ?> props = plugin.getBackup(pid);
+            if(props==null){
+                return "No backup found: " + pid;
+            }else{
+                return "PID: " + pid + '\n' +
+                        printProps(props);
+            }
+        }else {
+            StringWriter sw = new StringWriter();
+            PrintWriter pw = new PrintWriter(sw);
+            for(String current: plugin.getBackupPids()){
+                pw.println("PID: " + current);
+                pw.println(printProps(plugin.getBackup(current)));
+            }
+            return sw.toString();
+        }
+    }
+
+    public static String printProps(Dictionary<String, ?> props) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        pw.println(StringUtil.format("  Key", 50));
+        pw.println(StringUtil.format("  Value", 50));
+        pw.println("  " + StringUtil.printRepeat("-", 100));
+        Enumeration<String> keys = props.keys();
+        while(keys.hasMoreElements()){
+            String key = keys.nextElement();
+            pw.print("  " + StringUtil.format(key, 50));
+            pw.println("  " + StringUtil.format(String.valueOf(props.get(key)), 50));
+        }
+        pw.println();
+        pw.flush();
+        return sw.toString();
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/a1cd433a/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/ConfigCommands.java
----------------------------------------------------------------------
diff --git a/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/ConfigCommands.java b/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/ConfigCommands.java
new file mode 100644
index 0000000..cccbf9d
--- /dev/null
+++ b/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/ConfigCommands.java
@@ -0,0 +1,245 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.tamaya.osgi.commands;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.functions.ConfigurationFunctions;
+import org.apache.tamaya.osgi.Policy;
+import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.*;
+
+/**
+ * Utility class implementing the available configuration related commands.
+ */
+public final class ConfigCommands {
+
+    /** Singleton constructor. */
+    private ConfigCommands(){}
+
+    public static String getInfo(TamayaConfigService configPlugin) throws IOException {
+        Configuration config = ConfigurationProvider.getConfiguration();
+        return config.toString() + "\n\n"
+                + StringUtil.format("Default Policy:", 30) + configPlugin.getDefaultPolicy() + '\n'
+                + StringUtil.format("Default Enabled: ", 30) + configPlugin.isTamayaEnabledByDefault();
+    }
+
+    public static String readTamayaConfig(String section, String filter) {
+        Configuration config = ConfigurationProvider.getConfiguration();
+        if(section!=null){
+            config = config
+                    .with(ConfigurationFunctions.section(section, true));
+        }
+        if(filter!=null){
+            config = config.with(ConfigurationFunctions.section(filter, false));
+        }
+        return "Tamaya Configuration\n" +
+                "--------------------\n" +
+                "Section:     "+section +"\n" +
+                (filter!=null?"Filter:      "+filter + "\n":"") +
+                config.query(ConfigurationFunctions.textInfo());
+    }
+
+    public static String readTamayaConfig4PID(String pid, String filter) {
+        return readTamayaConfig("["+pid+"]", filter);
+    }
+
+    public static String applyTamayaConfiguration(TamayaConfigService configPlugin, String pid, String operationMode, boolean dryRun){
+        Dictionary<String,Object> config = null;
+        if(operationMode!=null){
+            config = configPlugin.updateConfig(pid, Policy.valueOf(operationMode), true, dryRun);
+            return  "Applied Configuration\n" +
+                    "------------------\n" +
+                    "PID           : " + pid + "\n" +
+                    "Policy : "+ operationMode + "\n" +
+                    "Dryrun       : " + dryRun + "\n" +
+                    printOSGIConfig(pid, config);
+        }else{
+            config = configPlugin.updateConfig(pid, dryRun);
+            return  "Applied Configuration\n" +
+                    "------------------\n" +
+                    "PID           : " + pid + "\n" +
+                    "Policy : "+ configPlugin.getDefaultPolicy() + "\n" +
+                    "Dryrun       : " + dryRun + "\n" +
+                    printOSGIConfig(pid, config);
+        }
+    }
+
+    public static String readOSGIConfiguration(TamayaConfigService configPlugin, String pid, String section) {
+        Dictionary<String,Object> config = configPlugin.getOSGIConfiguration(pid, section);
+        return printOSGIConfig(pid, config);
+    }
+
+    private static String printOSGIConfig(String pid, Dictionary<String,Object> config){
+        if(config.isEmpty()){
+            return "No Config present for PID: " + pid;
+        }
+        StringBuilder b = new StringBuilder();
+        b.append("OSGI Configuration for PID: ").append(pid).append('\n');
+        b.append("-----------------------------------------------------\n");
+        TreeMap<String,String> result = new TreeMap<>();
+        Enumeration<String> keys = config.keys();
+        while(keys.hasMoreElements()){
+            String key = keys.nextElement();
+            result.put(key, String.valueOf(config.get(key)));
+        }
+        for(Map.Entry<String,String> en:result.entrySet()){
+            b.append(StringUtil.format(en.getKey(), 40));
+            b.append(StringUtil.format(en.getValue(), 40));
+            b.append('\n');
+        }
+        return b.toString();
+    }
+
+    public static String getDefaultOpPolicy(TamayaConfigService configPlugin) throws IOException {
+        return String.valueOf(configPlugin.getDefaultPolicy());
+    }
+
+    public static String setDefaultOpPolicy(TamayaConfigService configPlugin, String policy) throws IOException {
+        Policy opMode = Policy.valueOf(policy);
+        configPlugin.setDefaultPolicy(opMode);
+        return "Policy="+opMode.toString();
+    }
+
+    public static String getProperty(String propertysource, String key, boolean extended) throws IOException {
+        Configuration config = ConfigurationProvider.getConfiguration();
+        if(propertysource!=null){
+            PropertySource ps = config.getContext().getPropertySource(propertysource);
+            if(ps==null){
+                return "ERR: No such Property Source: " + propertysource;
+            }else {
+                PropertyValue val = ps.get(key);
+                if(val==null){
+                    return "ERR: Property Source: " + propertysource + " - undefined key: " + key;
+                }else {
+                    if(extended) {
+                        return StringUtil.format("Property Source", 25) + StringUtil.format("Value", 25) + '\n' +
+                                StringUtil.printRepeat("-", 50) + '\n' +
+                                StringUtil.format(propertysource, 25) + StringUtil.format(val.getValue(), 55);
+                    }else{
+                        return val.getValue();
+                    }
+                }
+            }
+        }else{
+            StringWriter sw = new StringWriter();
+            PrintWriter pw = new PrintWriter(sw);
+            pw.println(StringUtil.format("Property Source", 25) + StringUtil.format("Value", 25));
+            for(PropertySource ps:config.getContext().getPropertySources()){
+                PropertyValue val = ps.get(key);
+                if(val!=null){
+                    if(extended) {
+                        pw.println(StringUtil.format("", 25) + StringUtil.format(val.toString(), 55));
+                    }else{
+                        pw.println(StringUtil.format("", 25) + StringUtil.format(val.getValue(), 55));
+                    }
+                }
+            }
+            pw.flush();
+            return sw.toString();
+        }
+    }
+
+    public static String getPropertySource(String propertysource) throws IOException {
+        Configuration config = ConfigurationProvider.getConfiguration();
+        if(propertysource!=null){
+            PropertySource ps = config.getContext().getPropertySource(propertysource);
+            if(ps==null){
+                return "No such Property Source: " + propertysource;
+            }else {
+                StringWriter sw = new StringWriter();
+                PrintWriter pw = new PrintWriter(sw);
+                pw.println("Property Source");
+                pw.println("---------------");
+                pw.println(StringUtil.format("ID:", 20) + ps.getName());
+                pw.println(StringUtil.format("Ordinal:", 20) + ps.getOrdinal());
+                pw.println(StringUtil.format("Class:", 20) + ps.getClass().getName());
+                pw.println("Properties:");
+                pw.print(StringUtil.format("  Key", 20));
+                pw.print(StringUtil.format("Value", 20));
+                pw.print(StringUtil.format("Source", 20));
+                pw.println(StringUtil.format("Meta-Entries", 20));
+                pw.println("  " + StringUtil.printRepeat("-", 80));
+                for(PropertyValue pv:ps.getProperties().values()) {
+                    pw.print("  " + StringUtil.format(pv.getKey(), 20));
+                    pw.print(StringUtil.format(pv.getValue(), 20));
+                    pw.print(StringUtil.format(pv.getSource(), 20));
+                    pw.println(StringUtil.format(pv.getMetaEntries().toString(), 80));
+                }
+                pw.flush();
+                return sw.toString();
+            }
+        }
+        // Get a name of existing propertysources
+        List<String> result = new ArrayList<>();
+        for(PropertySource ps:config.getContext().getPropertySources()){
+            result.add(ps.getName());
+        }
+        StringBuilder b = new StringBuilder("Please select a property source:\n");
+        for(String name:result){
+            b.append(name).append('\n');
+        }
+        return b.toString();
+    }
+
+    public static String getPropertySourceOverview() throws IOException {
+        Configuration config = ConfigurationProvider.getConfiguration();
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        pw.println("Property Sources");
+        pw.println("----------------");
+        pw.print(StringUtil.format("ID", 30));
+        pw.print(StringUtil.format("Ordinal", 20));
+        pw.print(StringUtil.format("Class", 40));
+        pw.println(StringUtil.format("Size", 5));
+        pw.println(StringUtil.printRepeat("-", 80));
+        for(PropertySource ps:config.getContext().getPropertySources()){
+            pw.print(StringUtil.format(ps.getName(), 30));
+            pw.print(StringUtil.format(String.valueOf(ps.getOrdinal()), 20));
+            pw.print(StringUtil.format(ps.getClass().getName(), 40));
+            pw.println(StringUtil.format(String.valueOf(ps.getProperties().size()), 5));
+            pw.println("---");
+        }
+        pw.flush();
+        return sw.toString();
+    }
+
+    public static String setDefaultEnabled(TamayaConfigService configPlugin, boolean enabled) throws IOException {
+        configPlugin.setTamayaEnabledByDefault(enabled);
+        return TamayaConfigService.TAMAYA_ENABLED_PROP+"="+enabled;
+    }
+
+    public static String getDefaultEnabled(TamayaConfigService configPlugin) {
+        return String.valueOf(configPlugin.isTamayaEnabledByDefault());
+    }
+
+    public static String setAutoUpdateEnabled(TamayaConfigService configPlugin, boolean enabled) {
+        configPlugin.setAutoUpdateEnabled(enabled);
+        return TamayaConfigService.TAMAYA_AUTO_UPDATE_ENABLED_PROP+"="+enabled;
+    }
+
+    public static String getAutoUpdateEnabled(TamayaConfigService configPlugin) {
+        return String.valueOf(configPlugin.isAutoUpdateEnabled());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/a1cd433a/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/HistoryCommands.java
----------------------------------------------------------------------
diff --git a/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/HistoryCommands.java b/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/HistoryCommands.java
new file mode 100644
index 0000000..7323dbd
--- /dev/null
+++ b/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/HistoryCommands.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.tamaya.osgi.commands;
+
+import org.apache.tamaya.osgi.ConfigHistory;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+/**
+ * Utility class implementing the available change getHistory related commands.
+ */
+public final class HistoryCommands{
+
+    /** Singleton constructor. */
+    private HistoryCommands(){}
+
+    public static String clearHistory(TamayaConfigService service, String pid) throws IOException {
+        int size = service.getHistory(pid).size();
+        if(pid!=null){
+            service.clearHistory(pid);
+            return "Deleted Config Change History for PID: " + pid;
+        }else{
+            service.clearHistory();
+            return "Deleted complete Config Change History.";
+        }
+
+    }
+
+    public static String getHistory(TamayaConfigService service, String pid, String... events) throws IOException {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        List<ConfigHistory> history = service.getHistory(pid);
+        history = filterTypes(history, events);
+        pw.print(StringUtil.format("Type", 10));
+        pw.print(StringUtil.format("PID", 30));
+        pw.print(StringUtil.format("Key", 30));
+        pw.print(StringUtil.format("Value", 40));
+        pw.println(StringUtil.format("Previous Value", 40));
+        pw.println(StringUtil.printRepeat("-", 140));
+        for(ConfigHistory h:history){
+            pw.print(StringUtil.format(h.getType().toString(), 10));
+            pw.print(StringUtil.format(h.getPid(), 30));
+            pw.print(StringUtil.format(h.getKey(), 30));
+            pw.print(StringUtil.format(String.valueOf(h.getValue()), 40));
+            pw.println(String.valueOf(h.getPreviousValue()));
+        }
+        pw.flush();
+        return sw.toString();
+    }
+
+    public static String getMaxHistorySize(TamayaConfigService service){
+        return String.valueOf(service.getMaxHistorySize());
+    }
+
+    public static String setMaxHistorySize(TamayaConfigService service, int maxSize){
+        service.setMaxHistorySize(maxSize);
+        return "tamaya-max-getHistory-size="+maxSize;
+    }
+
+    private static List<ConfigHistory> filterTypes(List<ConfigHistory> history, String... eventTypes) {
+        if(eventTypes==null || eventTypes.length==0){
+            return history;
+        }
+        List<ConfigHistory> result = new ArrayList<>();
+        Set<ConfigHistory.TaskType> types = new HashSet<>();
+        for(String tt:eventTypes) {
+            types.add(ConfigHistory.TaskType.valueOf(tt));
+        }
+        for(ConfigHistory h:history){
+            if(types.contains(h.getType())){
+                result.add(h);
+            }
+        }
+        return result;
+    }
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/a1cd433a/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/StringUtil.java
----------------------------------------------------------------------
diff --git a/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/StringUtil.java b/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/StringUtil.java
new file mode 100644
index 0000000..f7b29ac
--- /dev/null
+++ b/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/StringUtil.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.tamaya.osgi.commands;
+
+/**
+ * Some String related helper methods.
+ */
+public final class StringUtil {
+
+    private StringUtil(){}
+
+    public static String format(String in, int length){
+        if(in==null){
+            in = "";
+        }
+        int count = length - in.length();
+        if(count<0){
+            return in.substring(0,length-3) + "...";
+        }
+        return in + printRepeat(" ", count);
+    }
+
+    public static String printRepeat(String s, int times) {
+        StringBuilder b = new StringBuilder();
+        for(int i=0;i<times;i++){
+            b.append(s);
+        }
+        return b.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/a1cd433a/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/TamayaConfigService.java
----------------------------------------------------------------------
diff --git a/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/TamayaConfigService.java b/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/TamayaConfigService.java
new file mode 100644
index 0000000..99cd5fb
--- /dev/null
+++ b/modules/osgi/common/src/main/java/org/apache/tamaya/osgi/commands/TamayaConfigService.java
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.tamaya.osgi.commands;
+
+import org.apache.tamaya.osgi.ConfigHistory;
+import org.apache.tamaya.osgi.Policy;
+import org.osgi.framework.Bundle;
+
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Service exposing the Tamaya OSGI configuration logic.
+ */
+public interface TamayaConfigService{
+    /** The system/config property to set Tamaya's {@link Policy}. */
+    String TAMAYA_POLICY_PROP = "tamaya-policy";
+    /** The MANIFEST property to set Tamaya's {@link Policy}. */
+    String TAMAYA_POLICY_MANIFEST = "Tamaya-Policy";
+    /** The system/config property to define a customized Tamaya's configuration root, replacing the {@code [PID]} default
+     * prefix used. */
+    String TAMAYA_CUSTOM_ROOT_PROP = "tamaya-config-root";
+    /** The MANIFEST property to define a customized Tamaya's configuration root, replacing the {@code [PID]} default
+     * prefix used. */
+    String TAMAYA_CUSTOM_ROOT_MANIFEST = "Tamaya-Config-Root";
+    /** The system/config property to enable Tamaya. */
+    String TAMAYA_ENABLED_PROP = "tamaya-enabled";
+    /** The MANIFEST property to enable Tamaya. */
+    String TAMAYA_ENABLED_MANIFEST = "Tamaya-Enabled";
+    /** The system/config property to enable Tamaya automatic updates (requires Tamaya's Updater plugin to be loaded as well). */
+    String TAMAYA_AUTO_UPDATE_ENABLED_PROP = "tamaya-update-enabled";
+    /** The MANIFEST property to enable Tamaya automatic updates (requires Tamaya's Updater plugin to be loaded as well). */
+    String TAMAYA_AUTO_UPDATE_ENABLED_MANIFEST = "Tamaya-Update-Enabled";
+
+    /**
+     * Enables/disables automatic updates (requires Tamaya's Updater plugin to be loaded as well).
+     * @param enabled set to true to enable updates.
+     */
+    void setAutoUpdateEnabled(boolean enabled);
+
+    /**
+     * Enables/disables Tamaya config by default.
+     * @param enabled set to true to enable Tamaya for all bundles by default.
+     */
+    void setTamayaEnabledByDefault(boolean enabled);
+
+    /**
+     * Get the flag, if Tamaya is enabled by default for all bundles.
+     * @return true if Tamaya is enabled.
+     */
+    boolean isTamayaEnabledByDefault();
+
+    /**
+     * Get the default policy Tamaya is using for adapting OSGI configuration.
+     * @return the default policy, never null.
+     */
+    Policy getDefaultPolicy();
+
+    /**
+     * Set the default policy Tamaya is using for adapting OSGI configuration.
+     * @param policy the policy, not null.
+     */
+    void setDefaultPolicy(Policy policy);
+
+    /**
+     * Updates the given OSGI configuration with Tamaya configuration.
+     * @param pid the target PID, not null.
+     * @return the new configuration.
+     */
+    Dictionary<String,Object> updateConfig(String pid);
+
+    /**
+     * Updates the given OSGI configuration with Tamaya configuration.
+     * @param pid the target PID, not null.
+     * @param dryRun if true, the changes will not be applied to the OSGI configuration.
+     * @return the configuration that would be applied, has been applied.
+     */
+    Dictionary<String,Object> updateConfig(String pid, boolean dryRun);
+
+    /**
+     * Updates the given OSGI configuration with Tamaya configuration.
+     * @param pid the target PID, not null.
+     * @param policy the updating policy to be used, by default.
+     * @param forcePolicy if set to true, the given policy will be used, even if an alternate policy is configured
+     *                    for the given PID.
+     * @param dryRun if true, the changes will not be applied to the OSGI configuration.
+     * @return the configuration that would be applied, has been applied.
+     */
+    Dictionary<String,Object> updateConfig(String pid, Policy policy, boolean forcePolicy, boolean dryRun);
+
+    /**
+     * Checks if a bundle is enabled for Tamaya configuration.
+     * @param bundle the bundle, not null.
+     * @return true, if the bundle is enabled.
+     */
+    boolean isBundleEnabled(Bundle bundle);
+
+    /**
+     * Get the flag if automatic updates for config changes are enabled.
+     * @return true, if automatic updates for config changes are enabled.
+     */
+    boolean isAutoUpdateEnabled();
+
+    /**
+     * Get the backup written for a PID.
+     * @param pid the pid, not null.
+     * @return the backup, or null, if no backup is present.
+     */
+    Dictionary<String,?> getBackup(String pid);
+
+    /**
+     * Get all current known PIDs for which backups are registered.
+     * @return all known PIDs for which backups are registered.
+     */
+    Set<String> getBackupPids();
+
+    /**
+     * Restores a backup, replacing the current OSGI configuration with the backup and
+     * disabling Tamaya for this PID.
+     * @param pid the PID, not null.
+     * @return true, if a backup has been restored successfully.
+     */
+    boolean restoreBackup(String pid);
+
+    /**
+     * Stores the current OSGI configuration as a backup (only if no backup is existing).
+     * @param pid the target PID, not null.
+     * @return true, if a backup has been stored successfully.
+     */
+    boolean createBackup(String pid);
+
+    /**
+     * Deletes a backup, if existing.
+     * @param pid the target PID, not null.
+     * @return true, if a backup has been restored successfully.
+     */
+    boolean deleteBackup(String pid);
+
+    /**
+     * Sets the maximum getHistory size.
+     * @param maxHistory the max getHistory size. {@code 0} disables the getHistory function.
+     */
+    void setMaxHistorySize(int maxHistory);
+
+    /**
+     * Get the max getHistory size.
+     * @return the max getHistory size. {@code 0} means the getHistory function is disabled.
+     */
+    int getMaxHistorySize();
+
+    /**
+     * Access the current (full) change getHistory.
+     * @return the current getHistory, never null.
+     */
+    List<ConfigHistory> getHistory();
+
+    /**
+     * Clears the getHistory.
+     */
+    void clearHistory();
+
+    /**
+     * Clears the getHistory for a PID.
+     * @param pid the target PID, not null.
+     */
+    void clearHistory(String pid);
+
+    /**
+     * Get the getHistory for a PID.
+     * @param pid the target PID, not null.
+     * @return the PID's getHistory, never null.
+     */
+    List<ConfigHistory> getHistory(String pid);
+
+    /**
+     * Access the current OSGI configuration for a PID.
+     * @param pid the target PID, not null.
+     * @param section a subsection to be filter (using startsWith).
+     * @return the (optionally filtered) OSGI configuration.
+     */
+    Dictionary<String,Object> getOSGIConfiguration(String pid, String section);
+
+    /**
+     * Checks if a backup exists.
+     * @param pid the target PID, not null.
+     * @return true, if a backup exists.
+     */
+    boolean containsBackup(String pid);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/a1cd433a/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/AbstractOSGITest.java
----------------------------------------------------------------------
diff --git a/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/AbstractOSGITest.java b/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/AbstractOSGITest.java
new file mode 100644
index 0000000..20f6fea
--- /dev/null
+++ b/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/AbstractOSGITest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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 org.apache.tamaya.osgi;
+
+import org.apache.tamaya.osgi.commands.TamayaConfigService;
+import org.junit.Before;
+import org.mockito.Mock;
+import org.mockito.stubbing.Answer;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.*;
+
+/**
+ * Created by atsticks on 27.09.17.
+ */
+public abstract class AbstractOSGITest {
+
+    private Map<String,Hashtable<String, Object>> properties = new ConcurrentHashMap<>();
+
+    @Mock
+    protected BundleContext bundleContext;
+
+    @Mock
+    protected ConfigurationAdmin cm;
+
+    @Mock
+    private ServiceReference<ConfigurationAdmin> cmRef;
+    @Mock
+    private ServiceReference<TamayaConfigPlugin> tamayaRef;
+
+    protected TamayaConfigService tamayaConfigPlugin;
+
+    protected Dictionary<String,Object> getProperties(String pid){
+        return this.properties.get(pid);
+    }
+
+    @Before
+    public void setup()throws Exception{
+        doAnswer(invocation -> {
+            return initConfigurationMock((String)invocation.getArguments()[0]);
+        }).when(cm).getConfiguration(any());
+        doAnswer(invocation -> {
+            return initConfigurationMock((String)invocation.getArguments()[0]);
+        }).when(cm).getConfiguration(any(), any());
+        doReturn(new Bundle[0]).when(bundleContext).getBundles();
+        doReturn(cmRef).when(bundleContext).getServiceReference(ConfigurationAdmin.class);
+        doReturn(cm).when(bundleContext).getService(cmRef);
+        doReturn(tamayaRef).when(bundleContext).getServiceReference(TamayaConfigPlugin.class);
+        tamayaConfigPlugin = new TamayaConfigPlugin(bundleContext);
+        doReturn(tamayaConfigPlugin).when(bundleContext).getService(tamayaRef);
+    }
+
+    protected Configuration initConfigurationMock(final String pid)throws Exception{
+        Configuration config = mock(Configuration.class);
+        doAnswer(invocation -> {
+            Hashtable<String,Object> props = properties.get(pid);
+            props.clear();
+            props.putAll((Map<? extends String, ?>) invocation.getArguments()[0]);
+            return null;
+        }).when(config).update(any(Dictionary.class));
+        doAnswer(invocation -> {
+            Hashtable<String,Object> props = properties.get(pid);
+            if(props==null){
+                props = new Hashtable<>();
+                properties.put(pid, props);
+                for(Map.Entry en:System.getProperties().entrySet()){
+                    props.put(en.getKey().toString(), en.getValue());
+                }
+            }
+            return new Hashtable<>(props);
+        }).when(config).getProperties();
+        return config;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/a1cd433a/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/ActivatorTest.java
----------------------------------------------------------------------
diff --git a/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/ActivatorTest.java b/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/ActivatorTest.java
new file mode 100644
index 0000000..c1510f8
--- /dev/null
+++ b/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/ActivatorTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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 org.apache.tamaya.osgi;
+
+import org.apache.tamaya.osgi.commands.TamayaConfigService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Created by atsti on 29.09.2017.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ActivatorTest extends AbstractOSGITest{
+
+    @Test
+    public void startStop() throws Exception {
+        Activator activator = new Activator();
+        activator.start(super.bundleContext);
+        verify(bundleContext).registerService(eq(TamayaConfigService.class), anyObject(), anyObject());
+        activator.stop(super.bundleContext);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/a1cd433a/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/BackupsTest.java
----------------------------------------------------------------------
diff --git a/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/BackupsTest.java b/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/BackupsTest.java
new file mode 100644
index 0000000..9039332
--- /dev/null
+++ b/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/BackupsTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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 org.apache.tamaya.osgi;
+
+import org.junit.Test;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Created by atsticks on 26.09.17.
+ */
+public class BackupsTest {
+
+
+    private Dictionary<String,Object> createConfig(String pid){
+        Hashtable<String,Object> config = new Hashtable<>();
+        config.put("test.id", pid);
+        return config;
+    }
+    @Test
+    public void setGet() throws Exception {
+        Dictionary<String,Object> cfg = createConfig("set");
+        Backups.set("set", cfg);
+        assertEquals(Backups.get("set"), cfg);
+    }
+
+    @Test
+    public void remove() throws Exception {
+        Dictionary<String,Object> cfg = createConfig("remove");
+        Backups.set("remove", cfg);
+        assertEquals(Backups.get("remove"), cfg);
+        Backups.remove("remove");
+        assertEquals(Backups.get("remove"), null);
+    }
+
+    @Test
+    public void removeAll() throws Exception {
+        Dictionary<String,Object> cfg = createConfig("remove");
+        Backups.set("remove", cfg);
+        assertEquals(Backups.get("remove"), cfg);
+        Backups.removeAll();
+        assertEquals(Backups.get("remove"), null);
+    }
+
+    @Test
+    public void get1() throws Exception {
+    }
+
+    @Test
+    public void getPids() throws Exception {
+        Dictionary<String,Object> cfg = createConfig("getPids");
+        Backups.set("getPids", cfg);
+        Set<String> pids = Backups.getPids();
+        assertNotNull(pids);
+        assertTrue(pids.contains("getPids"));
+        Backups.removeAll();
+        pids = Backups.getPids();
+        assertNotNull(pids);
+        assertTrue(pids.isEmpty());
+    }
+
+    @Test
+    public void contains() throws Exception {
+        Dictionary<String,Object> cfg = createConfig("contains");
+        Backups.set("contains", cfg);
+        assertTrue(Backups.contains("contains"));
+        assertFalse(Backups.contains("foo"));
+        Backups.removeAll();
+        assertFalse(Backups.contains("contains"));
+        assertFalse(Backups.contains("foo"));
+    }
+
+    @Test
+    public void saveRestore() throws Exception {
+        Dictionary<String,Object> store = new Hashtable<>();
+        Dictionary<String,Object> cfg = createConfig("contains");
+        Backups.set("saveRestore", cfg);
+        Backups.save(store);
+        Backups.removeAll();
+        assertFalse(Backups.contains("saveRestore"));
+        Backups.restore(store);
+        assertTrue(Backups.contains("saveRestore"));
+        assertEquals(Backups.get("saveRestore"), cfg);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/a1cd433a/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/ConfigHistoryTest.java
----------------------------------------------------------------------
diff --git a/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/ConfigHistoryTest.java b/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/ConfigHistoryTest.java
new file mode 100644
index 0000000..a829f7b
--- /dev/null
+++ b/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/ConfigHistoryTest.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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 org.apache.tamaya.osgi;
+
+import org.junit.Test;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Created by atsticks on 26.09.17.
+ */
+public class ConfigHistoryTest {
+    @Test
+    public void configuring() throws Exception {
+        ConfigHistory en = ConfigHistory.configuring("configuring", "configuring_test");
+        assertNotNull(en);
+        assertEquals(en.getPid(), "configuring");
+        assertEquals(en.getType(), ConfigHistory.TaskType.BEGIN);
+        assertEquals(en.getValue(), "configuring_test");
+    }
+
+    @Test
+    public void configured() throws Exception {
+        ConfigHistory en = ConfigHistory.configured("configured", "configured_test");
+        assertNotNull(en);
+        assertEquals(en.getPid(), "configured");
+        assertEquals(en.getType(), ConfigHistory.TaskType.END);
+        assertEquals(en.getValue(), "configured_test");
+    }
+
+    @Test
+    public void propertySet() throws Exception {
+        ConfigHistory en = ConfigHistory.propertySet("propertySet", "propertySet.key", "new", "prev");
+        assertNotNull(en);
+        assertEquals(en.getPid(), "propertySet");
+        assertEquals(en.getType(), ConfigHistory.TaskType.PROPERTY);
+        assertEquals(en.getKey(), "propertySet.key");
+        assertEquals(en.getPreviousValue(), "prev");
+        assertEquals(en.getValue(),"new");
+    }
+
+    @Test
+    public void setGetMaxHistory() throws Exception {
+        ConfigHistory.setMaxHistory(1000);
+        assertEquals(ConfigHistory.getMaxHistory(),1000);
+    }
+
+    @Test
+    public void history() throws Exception {
+        for(int i=0;i<100;i++){
+            ConfigHistory.propertySet("getHistory", "getHistory"+i, "prev"+i, "new"+i);
+        }
+        List<ConfigHistory> hist = ConfigHistory.getHistory();
+        assertNotNull(hist);
+        assertTrue(hist.size()>=100);
+    }
+
+    @Test
+    public void history_pid() throws Exception {
+        ConfigHistory.configuring("history1", "history_pid");
+        for(int i=0;i<100;i++){
+            ConfigHistory.propertySet("history1", "getHistory"+i, "prev"+i, "new"+i);
+        }
+        ConfigHistory.configured("history1", "history_pid");
+        for(int i=0;i<100;i++){
+            ConfigHistory.propertySet("history2", "getHistory"+i, "prev"+i, "new"+i);
+        }
+        List<ConfigHistory> hist = ConfigHistory.getHistory("history1");
+        assertNotNull(hist);
+        assertTrue(hist.size()==102);
+        hist = ConfigHistory.getHistory("history2");
+        assertNotNull(hist);
+        assertTrue(hist.size()==100);
+        hist = ConfigHistory.getHistory(null);
+        assertNotNull(hist);
+        assertTrue(hist.size()>=202);
+    }
+
+    @Test
+    public void clearHistory() throws Exception {
+        for(int i=0;i<100;i++){
+            ConfigHistory.propertySet("history3", "getHistory"+i, "prev"+i, "new"+i);
+        }
+        for(int i=0;i<100;i++){
+            ConfigHistory.propertySet("history4", "getHistory"+i, "prev"+i, "new"+i);
+        }
+        List<ConfigHistory> hist = ConfigHistory.getHistory("history3");
+        assertNotNull(hist);
+        assertTrue(hist.size()==100);
+        assertEquals(ConfigHistory.getHistory("history4").size(), 100);
+        ConfigHistory.clearHistory("history3");
+        assertEquals(ConfigHistory.getHistory("history3").size(), 0);
+        assertEquals(ConfigHistory.getHistory("history4").size(), 100);
+        ConfigHistory.clearHistory(null);
+        assertEquals(ConfigHistory.getHistory().size(), 0);
+        assertEquals(ConfigHistory.getHistory("history4").size(), 0);
+    }
+
+
+    @Test
+    public void setPreviousValue() throws Exception {
+    }
+
+    @Test
+    public void getValue() throws Exception {
+    }
+
+    @Test
+    public void getKey() throws Exception {
+    }
+
+    @Test
+    public void saveRestore() throws Exception {
+        for(int i=0;i<10;i++){
+            ConfigHistory.propertySet("save", "getHistory"+i, "prev"+i, "new"+i);
+        }
+        assertEquals(ConfigHistory.getHistory("save").size(), 10);
+        Dictionary<String,Object> config = new Hashtable<>();
+        ConfigHistory.save(config);
+        assertEquals(ConfigHistory.getHistory("save").size(), 10);
+        ConfigHistory.clearHistory();
+        assertEquals(ConfigHistory.getHistory("save").size(), 0);
+        ConfigHistory.restore(config);
+        assertEquals(ConfigHistory.getHistory("save").size(), 10);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/a1cd433a/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/TamayaConfigPluginTest.java
----------------------------------------------------------------------
diff --git a/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/TamayaConfigPluginTest.java b/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/TamayaConfigPluginTest.java
new file mode 100644
index 0000000..d597557
--- /dev/null
+++ b/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/TamayaConfigPluginTest.java
@@ -0,0 +1,290 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.tamaya.osgi;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import static org.junit.Assert.*;
+
+/**
+ * Created by atsticks on 10.12.16.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class TamayaConfigPluginTest extends  AbstractOSGITest{
+
+    @Test
+    public void pluginLoaded() throws Exception {
+        assertNotNull(bundleContext.getService(bundleContext.getServiceReference(TamayaConfigPlugin.class)));
+    }
+
+    @Test
+    public void testOperationMode() throws Exception {
+        Policy om = tamayaConfigPlugin.getDefaultPolicy();
+        tamayaConfigPlugin.setDefaultPolicy(Policy.EXTEND);
+        assertEquals(Policy.EXTEND, tamayaConfigPlugin.getDefaultPolicy());
+        tamayaConfigPlugin.setDefaultPolicy(Policy.OVERRIDE);
+    }
+
+    @Test
+    public void testAutoUpdate() throws Exception {
+        boolean autoUpdate = tamayaConfigPlugin.isAutoUpdateEnabled();
+        tamayaConfigPlugin.setAutoUpdateEnabled(!autoUpdate);
+        assertEquals(tamayaConfigPlugin.isAutoUpdateEnabled(),!autoUpdate);
+        tamayaConfigPlugin.setAutoUpdateEnabled(autoUpdate);
+        assertEquals(tamayaConfigPlugin.isAutoUpdateEnabled(),autoUpdate);
+    }
+
+    @Test
+    public void testDefaulEnabled() throws Exception {
+        boolean enabled = tamayaConfigPlugin.isTamayaEnabledByDefault();
+        tamayaConfigPlugin.setTamayaEnabledByDefault(!enabled);
+        assertEquals(tamayaConfigPlugin.isTamayaEnabledByDefault(),!enabled);
+        tamayaConfigPlugin.setTamayaEnabledByDefault(enabled);
+        assertEquals(tamayaConfigPlugin.isTamayaEnabledByDefault(),enabled);
+    }
+
+    @Test
+    public void testSetPluginConfig() throws Exception {
+        Dictionary<String,Object> config = new Hashtable<>();
+        ((TamayaConfigPlugin)tamayaConfigPlugin).setPluginConfig(config);
+        assertEquals(((TamayaConfigPlugin)tamayaConfigPlugin).getPluginConfig(), config);
+    }
+
+    @Test
+    public void testSetGetConfigValue() throws Exception {
+        Dictionary<String,Object> config = new Hashtable<>();
+        String val = (String)((TamayaConfigPlugin)tamayaConfigPlugin).getConfigValue("foo");
+        ((TamayaConfigPlugin)tamayaConfigPlugin).setConfigValue("bar", "foo");
+        assertEquals(((TamayaConfigPlugin)tamayaConfigPlugin).getConfigValue("bar"), "foo");
+    }
+
+    @Test
+    public void getTMUpdateConfig() throws Exception {
+        org.apache.tamaya.Configuration config = ((TamayaConfigPlugin)tamayaConfigPlugin).getTamayaConfiguration("java.");
+        assertNotNull(config);
+        assertNull(config.get("jlkjllj"));
+        assertEquals(config.get("home"),System.getProperty("java.home"));
+    }
+
+    @Test
+    public void getUpdateConfig() throws Exception {
+        Dictionary<String, Object> config = tamayaConfigPlugin.updateConfig(TamayaConfigPlugin.COMPONENTID);
+        assertNotNull(config);
+        assertEquals(config.get("java.home"), System.getProperty("java.home"));
+    }
+
+    @Test
+    public void getUpdateConfig_DryRun() throws Exception {
+        Dictionary<String, Object> config = tamayaConfigPlugin.updateConfig(TamayaConfigPlugin.COMPONENTID, true);
+        assertNotNull(config);
+        assertEquals(config.get("java.home"), System.getProperty("java.home"));
+    }
+
+    @Test
+    public void getUpdateConfig_Explicit_DryRun() throws Exception {
+        Dictionary<String, Object> config = tamayaConfigPlugin.updateConfig(TamayaConfigPlugin.COMPONENTID, Policy.EXTEND, true, true);
+        assertNotNull(config);
+        assertEquals(config.get("java.home"), System.getProperty("java.home"));
+    }
+
+    @Test
+    public void getPluginConfig() throws Exception {
+        Dictionary<String, Object> config = ((TamayaConfigPlugin)tamayaConfigPlugin).getPluginConfig();
+        assertNotNull(config);
+        assertEquals(config, super.getProperties(TamayaConfigPlugin.COMPONENTID));
+    }
+
+    @Test
+    public void getDefaultOperationMode() throws Exception {
+        Policy om = tamayaConfigPlugin.getDefaultPolicy();
+        assertNotNull(om);
+        Dictionary<String,Object> pluginConfig = super.getProperties(TamayaConfigPlugin.COMPONENTID);
+        pluginConfig.put(Policy.class.getSimpleName(), Policy.UPDATE_ONLY.toString());
+        TamayaConfigPlugin plugin = new TamayaConfigPlugin(bundleContext);
+        om = plugin.getDefaultPolicy();
+        assertNotNull(om);
+        assertEquals(om, Policy.UPDATE_ONLY);
+        pluginConfig.put(Policy.class.getSimpleName(), Policy.OVERRIDE.toString());
+        plugin = new TamayaConfigPlugin(bundleContext);
+        om = plugin.getDefaultPolicy();
+        assertNotNull(om);
+        assertEquals(om, Policy.OVERRIDE);
+    }
+
+    @Test
+    public void testConfiguration_Override() throws Exception {
+        assertNotNull(cm);
+        tamayaConfigPlugin.updateConfig("tamaya", Policy.OVERRIDE, true, false);
+        org.osgi.service.cm.Configuration config = cm.getConfiguration("tamaya");
+        assertNotNull(config);
+        assertNotNull(config.getProperties());
+        assertFalse(config.getProperties().isEmpty());
+        assertTrue(config.getProperties().size() > 4);
+        // Override should add additional values
+        assertEquals(config.getProperties().get("my.testProperty1"), "success1");
+        assertEquals(config.getProperties().get("my.testProperty2"), "success2");
+        assertEquals(config.getProperties().get("my.testProperty3"), "success3");
+        assertEquals(config.getProperties().get("my.testProperty4"), "success4");
+        // Extend should also update any existing values...
+        assertEquals(config.getProperties().get("java.version"), "Java2000");
+        tamayaConfigPlugin.restoreBackup("tamaya");
+    }
+
+    @Test
+    public void testConfiguration_Override_ImplicitlyConfigured() throws Exception {
+        assertNotNull(cm);
+        org.osgi.service.cm.Configuration config = cm.getConfiguration("tamaya");
+        Dictionary<String,Object> props = config.getProperties();
+        props.put(TamayaConfigPlugin.TAMAYA_POLICY_PROP, "OVERRIDE");
+        config.update(props);
+        tamayaConfigPlugin.updateConfig("tamaya", Policy.UPDATE_ONLY, false, false);
+        config = cm.getConfiguration("tamaya");
+        assertNotNull(config);
+        assertNotNull(config.getProperties());
+        assertFalse(config.getProperties().isEmpty());
+        assertTrue(config.getProperties().size() > 4);
+        // Override should add additional values
+        assertEquals(config.getProperties().get("my.testProperty1"), "success1");
+        assertEquals(config.getProperties().get("my.testProperty2"), "success2");
+        assertEquals(config.getProperties().get("my.testProperty3"), "success3");
+        assertEquals(config.getProperties().get("my.testProperty4"), "success4");
+        // Extend should also update any existing values...
+        assertEquals(config.getProperties().get("java.version"), "Java2000");
+        tamayaConfigPlugin.restoreBackup("tamaya");
+    }
+
+    @Test
+    public void testConfiguration_Extend() throws Exception {
+        assertNotNull(cm);
+        tamayaConfigPlugin.updateConfig("tamaya", Policy.EXTEND, true, false);
+        org.osgi.service.cm.Configuration config = cm.getConfiguration("tamaya");
+        assertNotNull(config);
+        assertNotNull(config.getProperties());
+        assertFalse(config.getProperties().isEmpty());
+        assertTrue(config.getProperties().size() > 4);
+        assertEquals(config.getProperties().get("my.testProperty1"), "success1");
+        assertEquals(config.getProperties().get("my.testProperty2"), "success2");
+        assertEquals(config.getProperties().get("my.testProperty3"), "success3");
+        assertEquals(config.getProperties().get("my.testProperty4"), "success4");
+        // Extend should not update any existing values...
+        assertEquals(config.getProperties().get("java.version"), System.getProperty("java.version"));
+        tamayaConfigPlugin.restoreBackup("tamaya");
+    }
+
+    @Test
+    public void testConfiguration_Update_Only() throws Exception {
+        assertNotNull(cm);
+        tamayaConfigPlugin.updateConfig("tamaya", Policy.UPDATE_ONLY, true, false);
+        org.osgi.service.cm.Configuration config = cm.getConfiguration("tamaya");
+        assertNotNull(config);
+        assertNotNull(config.getProperties());
+        assertFalse(config.getProperties().isEmpty());
+        assertTrue(config.getProperties().size() > 4);
+        assertEquals(config.getProperties().get("my.testProperty1"), null);
+        assertEquals(config.getProperties().get("my.testProperty2"), null);
+        assertEquals(config.getProperties().get("my.testProperty3"), null);
+        assertEquals(config.getProperties().get("my.testProperty4"), null);
+        // Update only should update any existing values...
+        assertEquals(config.getProperties().get("java.version"), "Java2000");
+        tamayaConfigPlugin.restoreBackup("tamaya");
+    }
+
+    @Test
+    public void testConfiguration_Override_Dryrun() throws Exception {
+        assertNotNull(cm);
+        Dictionary<String,Object> result = tamayaConfigPlugin.updateConfig("tamaya", Policy.OVERRIDE, true, true);
+        assertNotNull(result);
+        // Override should add additional values
+        assertEquals(result.get("my.testProperty1"), "success1");
+        assertEquals(result.get("my.testProperty2"), "success2");
+        assertEquals(result.get("my.testProperty3"), "success3");
+        assertEquals(result.get("my.testProperty4"), "success4");
+        // Extend should also update any existing values...
+        assertEquals(result.get("java.version"), "Java2000");
+
+        // DryRun: should not have been changged anything on OSGI level...
+        org.osgi.service.cm.Configuration config = cm.getConfiguration("tamaya");
+        assertNotNull(config);
+        assertNotNull(config.getProperties());
+        assertFalse(config.getProperties().isEmpty());
+        assertTrue(config.getProperties().size() > 4);
+        assertEquals(config.getProperties().get("my.testProperty1"), null);
+        assertEquals(config.getProperties().get("my.testProperty2"), null);
+        assertEquals(config.getProperties().get("my.testProperty3"), null);
+        assertEquals(config.getProperties().get("my.testProperty4"), null);
+        assertEquals(config.getProperties().get("java.version"), System.getProperty("java.version"));
+    }
+
+    @Test
+    public void testConfiguration_Extend_Dryrun() throws Exception {
+        assertNotNull(cm);
+        Dictionary<String,Object> result = tamayaConfigPlugin.updateConfig("tamaya", Policy.EXTEND, true, true);
+        assertNotNull(result);
+        assertEquals(result.get("my.testProperty1"), "success1");
+        assertEquals(result.get("my.testProperty2"), "success2");
+        assertEquals(result.get("my.testProperty3"), "success3");
+        assertEquals(result.get("my.testProperty4"), "success4");
+        // Extend should not update any existing values...
+        assertEquals(result.get("java.version"), System.getProperty("java.version"));
+
+        // DryRun: should not have been changged anything on OSGI level...
+        org.osgi.service.cm.Configuration config = cm.getConfiguration("tamaya");
+        assertNotNull(config);
+        assertNotNull(config.getProperties());
+        assertFalse(config.getProperties().isEmpty());
+        assertTrue(config.getProperties().size() > 4);
+        assertEquals(config.getProperties().get("my.testProperty1"), null);
+        assertEquals(config.getProperties().get("my.testProperty2"), null);
+        assertEquals(config.getProperties().get("my.testProperty3"), null);
+        assertEquals(config.getProperties().get("my.testProperty4"), null);
+        assertEquals(config.getProperties().get("java.version"), System.getProperty("java.version"));
+    }
+
+    @Test
+    public void testConfiguration_Update_Only_Dryrun() throws Exception {
+        assertNotNull(cm);
+        Dictionary<String,Object> result = tamayaConfigPlugin.updateConfig("tamaya", Policy.UPDATE_ONLY, true, true);
+        assertNotNull(result);
+        assertTrue(result.size() > 4);
+        assertEquals(result.get("my.testProperty1"), null);
+        assertEquals(result.get("my.testProperty2"), null);
+        assertEquals(result.get("my.testProperty3"), null);
+        assertEquals(result.get("my.testProperty4"), null);
+        // Update only should update any existing values...
+        assertEquals(result.get("java.version"), "Java2000");
+
+        // DryRun: should not have been changged anything on OSGI level...
+        org.osgi.service.cm.Configuration config = cm.getConfiguration("tamaya");
+        assertNotNull(config);
+        assertNotNull(config.getProperties());
+        assertFalse(config.getProperties().isEmpty());
+        assertTrue(config.getProperties().size() > 4);
+        assertEquals(config.getProperties().get("my.testProperty1"), null);
+        assertEquals(config.getProperties().get("my.testProperty2"), null);
+        assertEquals(config.getProperties().get("my.testProperty3"), null);
+        assertEquals(config.getProperties().get("my.testProperty4"), null);
+        assertEquals(config.getProperties().get("java.version"), System.getProperty("java.version"));
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/a1cd433a/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/commands/BackupCommandsTest.java
----------------------------------------------------------------------
diff --git a/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/commands/BackupCommandsTest.java b/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/commands/BackupCommandsTest.java
new file mode 100644
index 0000000..20d2a78
--- /dev/null
+++ b/modules/osgi/common/src/test/java/org/apache/tamaya/osgi/commands/BackupCommandsTest.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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 org.apache.tamaya.osgi.commands;
+
+import org.apache.tamaya.osgi.AbstractOSGITest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.Hashtable;
+
+import static org.junit.Assert.*;
+
+/**
+ * Created by atsti on 30.09.2017.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class BackupCommandsTest extends AbstractOSGITest {
+    @Test
+    public void createBackup() throws Exception {
+        String result = BackupCommands.createBackup(tamayaConfigPlugin, cm, "createBackup", false);
+        assertNotNull(result);
+        assertTrue(result.contains("createBackup"));
+        assertTrue(result.contains("Backup created"));
+        assertTrue(tamayaConfigPlugin.containsBackup("createBackup"));
+        // A backup with the given name already exists, so it fails
+        result = BackupCommands.createBackup(tamayaConfigPlugin, cm, "createBackup", false);
+        assertNotNull(result);
+        assertTrue(result.contains("createBackup"));
+        assertTrue(result.contains("Creating backup failed"));
+        assertTrue(result.contains("already existing"));
+        assertTrue(tamayaConfigPlugin.containsBackup("createBackup"));
+        // any existing backups gets overridden
+        result = BackupCommands.createBackup(tamayaConfigPlugin, cm, "createBackup", true);
+        assertNotNull(result);
+        assertTrue(result.contains("createBackup"));
+        assertTrue(result.contains("Backup created"));
+        assertTrue(tamayaConfigPlugin.containsBackup("createBackup"));
+    }
+
+    @Test
+    public void deleteBackup() throws Exception {
+        BackupCommands.createBackup(tamayaConfigPlugin, cm, "deleteBackup", false);
+        assertTrue(tamayaConfigPlugin.containsBackup("deleteBackup"));
+        String result = BackupCommands.deleteBackup(tamayaConfigPlugin, "deleteBackup");
+        assertNotNull(result);
+        assertTrue(result.contains("deleteBackup"));
+        assertTrue(result.contains("Backup deleted"));
+        assertFalse(tamayaConfigPlugin.containsBackup("deleteBackup"));
+    }
+
+    @Test
+    public void restoreBackup() throws Exception {
+        BackupCommands.createBackup(tamayaConfigPlugin, cm, "restoreBackup", false);
+        assertTrue(tamayaConfigPlugin.containsBackup("restoreBackup"));
+        String result = BackupCommands.restoreBackup(tamayaConfigPlugin, "restoreBackup");
+        assertNotNull(result);
+        assertTrue(result.contains("restoreBackup"));
+        assertTrue(result.contains("Backup restored"));
+        BackupCommands.deleteBackup(tamayaConfigPlugin, "restoreBackup");
+        assertFalse(tamayaConfigPlugin.containsBackup("restoreBackup"));
+        result = BackupCommands.restoreBackup(tamayaConfigPlugin, "restoreBackup");
+        assertTrue(result.contains("Backup restore failed"));
+        assertTrue(result.contains("no backup found"));
+    }
+
+    @Test
+    public void listBackup() throws Exception {
+        BackupCommands.createBackup(tamayaConfigPlugin, cm, "listBackup", false);
+        String result = BackupCommands.listBackup(tamayaConfigPlugin, "listBackup");
+        result.concat("listBackup");
+        result.contains("pid");
+    }
+
+    @Test
+    public void printProps() throws Exception {
+        Hashtable<String,Object> props = new Hashtable<>();
+        props.put("k1", "v1");
+        props.put("k2", "v2");
+        String result = BackupCommands.printProps(props);
+        assertTrue(result.contains("k1"));
+        assertTrue(result.contains("k2"));
+        assertTrue(result.contains("v1"));
+        assertTrue(result.contains("v2"));
+    }
+
+}
\ No newline at end of file