tamaya-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From anat...@apache.org
Subject [2/5] incubator-tamaya git commit: TAMAYA-156: Added stats function, TAMAYA-150: Refactored UI Widgets., TAMAYA-157: Added CLI main arg support.
Date Sat, 30 Apr 2016 19:37:37 GMT
TAMAYA-156: Added stats function, TAMAYA-150: Refactored UI Widgets., TAMAYA-157: Added CLI main arg support.


Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/4749d395
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/4749d395
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/4749d395

Branch: refs/heads/master
Commit: 4749d3950983a78b0fd33459cf15cf339dc44f51
Parents: a7ee4e4
Author: anatole <anatole@apache.org>
Authored: Sat Apr 30 19:57:52 2016 +0200
Committer: anatole <anatole@apache.org>
Committed: Sat Apr 30 19:57:52 2016 +0200

----------------------------------------------------------------------
 .../core/propertysource/CLIPropertySource.java  | 102 +++++++
 .../propertysource/CLIPropertySourceTest.java   |  58 ++++
 .../java/org/apache/tamaya/model/Usage.java     | 275 +++++++++++++++++++
 .../org/apache/tamaya/model/UsageReference.java |  45 +++
 .../model/internal/DefaultUsageTracker.java     | 127 +++++++++
 .../model/internal/UsageTrackerFilter.java      |  45 +++
 .../tamaya/model/spi/UsageTrackerSpi.java       |  67 +++++
 .../org.apache.tamaya.model.spi.UsageTrackerSpi |  19 ++
 .../org.apache.tamaya.spi.PropertyFilter        |  19 ++
 .../java/test/model/TestConfigAccessor.java     |  27 ++
 .../mutableconfig/ui/ConfigEditorWidget.java    | 110 ++++++++
 .../mutableconfig/ui/ConfigUpdaterView.java     |  33 +--
 .../tamaya/mutableconfig/ui/ProtocolWidget.java |  87 ++++++
 .../ui/TransactionControlWidget.java            | 168 +++++++++++
 .../main/resources/ui/lang/tamaya.properties    |  13 +-
 15 files changed, 1175 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/code/core/src/main/java/org/apache/tamaya/core/propertysource/CLIPropertySource.java
----------------------------------------------------------------------
diff --git a/code/core/src/main/java/org/apache/tamaya/core/propertysource/CLIPropertySource.java b/code/core/src/main/java/org/apache/tamaya/core/propertysource/CLIPropertySource.java
new file mode 100644
index 0000000..ddc540e
--- /dev/null
+++ b/code/core/src/main/java/org/apache/tamaya/core/propertysource/CLIPropertySource.java
@@ -0,0 +1,102 @@
+/*
+ * 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.core.propertysource;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * PropertySource that allows to add the programs main arguments as configuration entries. Unix syntax using '--' and
+ * '-' params is supported.
+ */
+public class CLIPropertySource extends BasePropertySource{
+
+    /** The original main arguments. */
+    private static String[] args = new String[0];
+
+    /** The map of parsed main arguments. */
+    private static Map<String,String> mainArgs;
+
+    /** Initializes the initial state. */
+    static{
+        initMainArgs(args);
+    }
+
+
+    /**
+     * Creates a new instance.
+     */
+    public CLIPropertySource(){}
+
+    /**
+     * Configure the main arguments, herby parsing and mapping the main arguments into
+     * configuration properties.
+     * @param args the main arguments, not null.
+     * @returns the parsed main arguments as key/value pairs.
+     */
+    public static void initMainArgs(String... args){
+        CLIPropertySource.args = Objects.requireNonNull(args);
+        // TODO is there a way to figure out the args?
+        String argsProp = System.getProperty("main.args");
+        if(argsProp!=null){
+            CLIPropertySource.args = argsProp.split("\\s");
+        }
+        Map<String,String> result = null;
+        if(CLIPropertySource.args==null){
+            result = Collections.emptyMap();
+        }else{
+            result = new HashMap<>();
+            String prefix = System.getProperty("main.args.prefix");
+            if(prefix==null){
+                prefix="";
+            }
+            String key = null;
+            for(String arg:CLIPropertySource.args){
+                if(arg.startsWith("--")){
+                    arg = arg.substring(2);
+                    int index = arg.indexOf("=");
+                    if(index>0){
+                        key = arg.substring(0,index).trim();
+                        result.put(prefix+key, arg.substring(index+1).trim());
+                        key = null;
+                    }else{
+                        result.put(prefix+arg, arg);
+                    }
+                }else if(arg.startsWith("-")){
+                    key = arg.substring(1);
+                }else{
+                    if(key!=null){
+                        result.put(prefix+key, arg);
+                        key = null;
+                    }else{
+                        result.put(prefix+arg, arg);
+                    }
+                }
+            }
+        }
+        CLIPropertySource.mainArgs = Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        return Collections.unmodifiableMap(mainArgs);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/code/core/src/test/java/org/apache/tamaya/core/propertysource/CLIPropertySourceTest.java
----------------------------------------------------------------------
diff --git a/code/core/src/test/java/org/apache/tamaya/core/propertysource/CLIPropertySourceTest.java b/code/core/src/test/java/org/apache/tamaya/core/propertysource/CLIPropertySourceTest.java
new file mode 100644
index 0000000..dde63e5
--- /dev/null
+++ b/code/core/src/test/java/org/apache/tamaya/core/propertysource/CLIPropertySourceTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.core.propertysource;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests for PropertySource for reading main arguments as configuration.
+ */
+public class CLIPropertySourceTest {
+
+    @Test
+    public void setCLIProps() throws Exception {
+        System.clearProperty("main.args");
+        CLIPropertySource ps = new CLIPropertySource();
+        assertTrue(ps.getProperties().isEmpty());
+        CLIPropertySource.initMainArgs("-a", "b");
+        assertFalse(ps.getProperties().isEmpty());
+        assertEquals(ps.getProperties().get("a"), "b");
+        CLIPropertySource.initMainArgs("--c");
+        assertFalse(ps.getProperties().isEmpty());
+        assertEquals(ps.getProperties().get("c"), "c");
+        CLIPropertySource.initMainArgs("sss");
+        assertFalse(ps.getProperties().isEmpty());
+        assertEquals(ps.getProperties().get("sss"), "sss");
+        CLIPropertySource.initMainArgs("-a", "b", "--c", "sss", "--val=vvv");
+        assertFalse(ps.getProperties().isEmpty());
+        assertEquals(ps.getProperties().get("a"), "b");
+        assertEquals(ps.getProperties().get("c"), "c");
+        assertEquals(ps.getProperties().get("sss"), "sss");
+    // getProperties() throws Exception {
+        System.setProperty("main.args", "-a b\t--c sss  ");
+        ps = new CLIPropertySource();
+        assertFalse(ps.getProperties().isEmpty());
+        System.clearProperty("main.args");
+        assertEquals(ps.getProperties().get("a"), "b");
+        assertEquals(ps.getProperties().get("c"), "c");
+        assertEquals(ps.getProperties().get("sss"), "sss");
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/modules/model/src/main/java/org/apache/tamaya/model/Usage.java
----------------------------------------------------------------------
diff --git a/modules/model/src/main/java/org/apache/tamaya/model/Usage.java b/modules/model/src/main/java/org/apache/tamaya/model/Usage.java
new file mode 100644
index 0000000..d5625f3
--- /dev/null
+++ b/modules/model/src/main/java/org/apache/tamaya/model/Usage.java
@@ -0,0 +1,275 @@
+/*
+ * 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.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.logging.Logger;
+
+/**
+ * Metrics container containing access statistics for a given vonfiguration key.
+ */
+public final class Usage {
+    private static final Logger LOG = Logger.getLogger(Usage.class.getName());
+    /**
+     * the config section.
+     */
+    private final String key;
+
+    /**
+     * Maps with usage references, key is the fully qualified package name.
+     */
+    private final Map<String,AccessDetail> accessDetails = new ConcurrentHashMap<>();
+
+    /**
+     * Creates a usage metric container for a given key.
+     * @param key the parameter (fully qualified).
+     */
+    public Usage(String key) {
+        this.key = Objects.requireNonNull(key);
+    }
+
+    /**
+     * Get the configModel section.
+     *
+     * @return the section, never null.
+     */
+    public String getKey() {
+        return key;
+    }
+
+    /**
+     * Clears all collected usage metrics for this key.
+     */
+    public void clearMetrics(){
+        this.accessDetails.clear();
+    }
+
+    /**
+     * Get the detail message.
+     *
+     * @return the detail message, or null.
+     */
+    public int getReferenceCount() {
+        return accessDetails.size();
+    }
+
+    /**
+     * Get the detail message.
+     *
+     * @return the detail message, or null.
+     */
+    public int getUsageCount() {
+        int count = 0;
+        for(AccessDetail ref: accessDetails.values()){
+            count += ref.getAccessCount();
+        }
+        return count;
+    }
+
+    /**
+     * Access a usage reference for a given class.
+     * @return the usage ref, if present, or null.
+     */
+    public Collection<AccessDetail> getAccessDetails(Class type){
+        return getAccessDetails(type.getName() +"\\..*");
+    }
+
+    /**
+     * Access a usage reference for a given package.
+     * @return the usage ref, if present, or null.
+     */
+    public Collection<AccessDetail> getAccessDetails(Package pack){
+        return getAccessDetails(pack.getName() +"\\..*");
+    }
+
+    /**
+     * Find usages of this key for the given expression (regex). Hereby the expression is
+     * matched with the tracked reference identifier, which has the form
+     * {@code f.q.n.ClassName#methodName(line: 123)}.
+     * @param lookupExpression the target lookup expression, not null.
+     * @return the matching references, not null.
+     */
+    public Collection<AccessDetail> getAccessDetails(String lookupExpression){
+        List<AccessDetail> result = new ArrayList<>();
+        for(AccessDetail ref:this.accessDetails.values()){
+            if(ref.getAccessPoint().matches(lookupExpression)){
+                result.add(ref);
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "Usage Count: " + key + " -> " + getUsageCount() + '\n';
+    }
+
+    /**
+     * Get the access details (stacktrace etrc) for this reference.
+     * @return return the access details, not null.
+     */
+    public Collection<AccessDetail> getAccessDetails(){
+        return Collections.unmodifiableCollection(accessDetails.values());
+    }
+
+    /**
+     * Evaluates the current access point from the current stacktrace and adds an according
+     * usage reference object (or updates any existing one) for the given key. The
+     * stacktrace is shortened to a maximal size of 20 items.
+     * @param value the value returned, not null.
+     */
+    public void trackUsage(String value){
+        trackUsage(value, 10);
+    }
+
+    /**
+     * Evaluates the current access point from the current stacktrace and adds an according
+     * usage reference object (or updates any existing one) for the given key.
+     * @param value the value returned, not null.
+     * @param maxTraceLength the maximal length of the stored stacktrace.
+     */
+    public void trackUsage(String value, int maxTraceLength){
+
+        Exception e = new Exception();
+        List<String> trace = new ArrayList<>();
+        String accessPoint = null;
+        stack:for(StackTraceElement ste:e.getStackTrace()){
+            for(String ignored: ConfigModelManager.getIgnoredPackages()) {
+                if (ste.getClassName().startsWith(ignored)) {
+                    continue stack;
+                }
+            }
+            String ref = ste.getClassName() + '#' + ste.getMethodName() + "(line:" + ste.getLineNumber() + ')';
+            trace.add(ref);
+            if (accessPoint == null) {
+                accessPoint = ref;
+            }
+            if(trace.size()>=maxTraceLength){
+                break;
+            }
+        }
+        if (accessPoint == null) {
+            // all ignored, take first one, with different package
+            accessPoint = "<unknown/filtered/internal>";
+        }
+        AccessDetail details = getAccessDetails(accessPoint, trace.toArray(new String[trace.size()]));
+        details.trackAccess(value);
+    }
+
+    private AccessDetail getAccessDetails(String accessPoint, String[] trace) {
+        AccessDetail details = accessDetails.get(accessPoint);
+        if(details==null){
+            details = new AccessDetail(accessPoint, trace);
+            accessDetails.put(accessPoint, details);
+        }
+        return details;
+    }
+
+    /**
+     * Class modelling the access details tracked per detailed item, e.g. per class in the owning package.
+     */
+    public static final class AccessDetail {
+        private AtomicLong accessCount = new AtomicLong();
+        private long lastAccessTS;
+        private long firstAccessTS;
+        private String[] stackTrace;
+        private String accessPoint;
+        private Map<Long, String> trackedValues;
+
+        public AccessDetail(String accessPoint, String[] stackTrace){
+            this.accessPoint = Objects.requireNonNull(accessPoint);
+            this.stackTrace = stackTrace.clone();
+        }
+
+        public void clearStats(){
+            lastAccessTS = 0;
+            firstAccessTS = 0;
+            accessCount.set(0);
+        }
+
+        public long trackAccess(String value){
+            long count = accessCount.incrementAndGet();
+            lastAccessTS = System.currentTimeMillis();
+            if(firstAccessTS==0){
+                firstAccessTS = lastAccessTS;
+            }
+            if(value!=null){
+                synchronized (this) {
+                    if(trackedValues==null){
+                        trackedValues = new HashMap<>();
+                    }
+                    trackedValues.put(lastAccessTS, value);
+                }
+            }
+            return count;
+        }
+
+        public long getAccessCount() {
+            return accessCount.get();
+        }
+
+        public String getAccessPoint() {
+            return accessPoint;
+        }
+
+        public long getFirstAccessTS() {
+            return firstAccessTS;
+        }
+
+        public long getLastAccessTS() {
+            return lastAccessTS;
+        }
+
+        public String[] getStackTrace() {
+            return stackTrace.clone();
+        }
+
+        public Map<Long, String> getTrackedValues(){
+            if(trackedValues==null){
+                return Collections.emptyMap();
+            }else{
+                synchronized (this) {
+                    return new HashMap<>(trackedValues);
+                }
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "AccessDetails{" +
+                    "accessCount=" + accessCount +
+                    ", lastAccessTS=" + lastAccessTS +
+                    ", firstAccessTS=" + firstAccessTS +
+                    ", stackTrace=" + Arrays.toString(stackTrace) +
+                    ", accessPoint='" + accessPoint + '\'' +
+                    ", trackedValues=" + trackedValues +
+                    '}';
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/modules/model/src/main/java/org/apache/tamaya/model/UsageReference.java
----------------------------------------------------------------------
diff --git a/modules/model/src/main/java/org/apache/tamaya/model/UsageReference.java b/modules/model/src/main/java/org/apache/tamaya/model/UsageReference.java
new file mode 100644
index 0000000..3504def
--- /dev/null
+++ b/modules/model/src/main/java/org/apache/tamaya/model/UsageReference.java
@@ -0,0 +1,45 @@
+/*
+ * 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.model;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Reference object store for a parameter or configuration accessed.
+ */
+public class UsageReference {
+
+    private String reference;
+
+
+    public UsageReference(String reference){
+        this.reference = Objects.requireNonNull(reference);
+    }
+
+    /**
+     * Access the package name which accessed the configuration.
+     * @return the package name, never null.
+     */
+    public String getReference(){
+        return reference;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/modules/model/src/main/java/org/apache/tamaya/model/internal/DefaultUsageTracker.java
----------------------------------------------------------------------
diff --git a/modules/model/src/main/java/org/apache/tamaya/model/internal/DefaultUsageTracker.java b/modules/model/src/main/java/org/apache/tamaya/model/internal/DefaultUsageTracker.java
new file mode 100644
index 0000000..73729f1
--- /dev/null
+++ b/modules/model/src/main/java/org/apache/tamaya/model/internal/DefaultUsageTracker.java
@@ -0,0 +1,127 @@
+/*
+ * 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.model.internal;
+
+import org.apache.tamaya.model.Usage;
+import org.apache.tamaya.model.spi.UsageTrackerSpi;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Created by atsticks on 29.04.16.
+ */
+public class DefaultUsageTracker implements UsageTrackerSpi{
+
+    private Set<String> ignoredPackages = new HashSet<>();
+
+    private Map<String, Usage> usages = new ConcurrentHashMap<>();
+
+    public DefaultUsageTracker(){
+        ignoredPackages.add("com.intellij");
+        ignoredPackages.add("java");
+        ignoredPackages.add("org.junit");
+        ignoredPackages.add("junit");
+        ignoredPackages.add("javax");
+        ignoredPackages.add("sun");
+        ignoredPackages.add("oracle");
+        ignoredPackages.add("com.sun");
+        ignoredPackages.add("com.oracle");
+        ignoredPackages.add("org.apache.tamaya");
+    }
+
+    @Override
+    public Set<String> getIgnoredPackages() {
+        return Collections.unmodifiableSet(ignoredPackages);
+    }
+
+    /**
+     * Get the recorded usage references of configuration.
+     * @return the recorded usge references, never null.
+     */
+    @Override
+    public Collection<Usage> getUsages() {
+        return usages.values();
+    }
+
+    @Override
+    public void trackConfigurationAccess(){
+        trackSingleKeyAccess("[[Configuration]]", "<not stored>");
+    }
+
+    @Override
+    public void trackAllPropertiesAccess(){
+        trackSingleKeyAccess("<<all>>", "<not stored>");
+    }
+
+    @Override
+    public void trackSingleKeyAccess(String key, String value){
+        // Ignore meta-entries
+        if(key.startsWith("_")){
+            return;
+        }
+        Usage usage = this.usages.get(key);
+        if(usage==null){
+            usage = new Usage(key);
+            this.usages.put(key, usage);
+        }
+        usage.trackUsage(value);
+    }
+
+
+    /**
+     * Access the usage statistics for the recorded uses of configuration.
+     */
+    @Override
+    public String getUsageInfo(){
+        StringBuilder b = new StringBuilder();
+        b.append("Apache Tamaya Configuration Usage Metrics\n");
+        b.append("=========================================\n");
+        b.append("DATE: " + new Date()).append("\n\n");
+        List<Usage> usages = new ArrayList<>(getUsages());
+        Collections.sort(usages, new Comparator<Usage>() {
+            @Override
+            public int compare(Usage k1, Usage k2) {
+                return k2.getUsageCount() - k1.getUsageCount();
+            }
+        });
+        for(Usage usage:usages){
+            String usageCount = String.valueOf(usage.getUsageCount());
+            b.append(usageCount);
+            b.append("       ".substring(0, 7-usageCount.length()));
+            b.append(usage.getKey()).append(":\n");
+            for(Usage.AccessDetail details: usage.getAccessDetails()) {
+                String accessCount = String.valueOf(details.getAccessCount());
+                    b.append("  - ").append(accessCount);
+                    b.append("      ".substring(0, 6-usageCount.length()));
+                    b.append(details.getAccessPoint());
+                    int endIndex = 50-details.getAccessPoint().length();
+                    if(endIndex<0){
+                        endIndex = 0;
+                    }
+                    b.append("                                                  ".substring(0, endIndex));
+                    b.append(",");b.append(" first=").append(new Date(details.getFirstAccessTS()))
+                            .append(",");b.append(" last=").append(new Date(details.getLastAccessTS()))
+                            .append('\n');
+            }
+        }
+        return b.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/modules/model/src/main/java/org/apache/tamaya/model/internal/UsageTrackerFilter.java
----------------------------------------------------------------------
diff --git a/modules/model/src/main/java/org/apache/tamaya/model/internal/UsageTrackerFilter.java b/modules/model/src/main/java/org/apache/tamaya/model/internal/UsageTrackerFilter.java
new file mode 100644
index 0000000..8cf7b60
--- /dev/null
+++ b/modules/model/src/main/java/org/apache/tamaya/model/internal/UsageTrackerFilter.java
@@ -0,0 +1,45 @@
+/*
+ * 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.model.internal;
+
+import org.apache.tamaya.model.spi.UsageTrackerSpi;
+import org.apache.tamaya.spi.FilterContext;
+import org.apache.tamaya.spi.PropertyFilter;
+import org.apache.tamaya.spi.ServiceContextManager;
+
+import javax.annotation.Priority;
+
+/**
+ * Configuration filter to be applied at the end of the filter chain. This filter
+ * actually does not change the current filter value, but use the filter process
+ * to track configuration usage.
+ */
+@Priority(Integer.MAX_VALUE)
+public class UsageTrackerFilter implements PropertyFilter{
+    @Override
+    public String filterProperty(String value, FilterContext context) {
+        UsageTrackerSpi tracker = ServiceContextManager.getServiceContext().getService(UsageTrackerSpi.class);
+        if(context.isSinglePropertyScoped()) {
+            tracker.trackSingleKeyAccess(context.getKey(), value);
+        }else{
+            tracker.trackAllPropertiesAccess();
+        }
+        return value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/modules/model/src/main/java/org/apache/tamaya/model/spi/UsageTrackerSpi.java
----------------------------------------------------------------------
diff --git a/modules/model/src/main/java/org/apache/tamaya/model/spi/UsageTrackerSpi.java b/modules/model/src/main/java/org/apache/tamaya/model/spi/UsageTrackerSpi.java
new file mode 100644
index 0000000..fd85597
--- /dev/null
+++ b/modules/model/src/main/java/org/apache/tamaya/model/spi/UsageTrackerSpi.java
@@ -0,0 +1,67 @@
+/*
+ * 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.model.spi;
+
+import org.apache.tamaya.model.Usage;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * SPI to implemented by the component responsible for usage tracking of
+ * configuration.
+ */
+public interface UsageTrackerSpi {
+
+    /**
+     * Get the list of package, which are not evaluated for tracking configuration access and usage statistics.
+     * @return the set of ignored package names.
+     */
+    Set<String> getIgnoredPackages();
+
+    /**
+     * Get the recorded usage references of configuration.
+     * @return the recorded usge references, never null.
+     */
+    Collection<Usage> getUsages();
+
+    /**
+     * Track the access of {@code ConfigurationProvider#getConfiguration()} for
+     * usage statistics.
+     */
+    void trackConfigurationAccess();
+
+    /**
+     * Track the access of {@code Configuration#getProperties()} for
+     * usage statistics.
+     */
+    void trackAllPropertiesAccess();
+
+    /**
+     * Track the access of {@code Configuration#get(String)} for
+     * usage statistics.
+     */
+    void trackSingleKeyAccess(String key, String value);
+
+    /**
+     * Access the usage statistics for the recorded uses of configuration.
+     */
+    String getUsageInfo();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/modules/model/src/main/resources/META-INF/services/org.apache.tamaya.model.spi.UsageTrackerSpi
----------------------------------------------------------------------
diff --git a/modules/model/src/main/resources/META-INF/services/org.apache.tamaya.model.spi.UsageTrackerSpi b/modules/model/src/main/resources/META-INF/services/org.apache.tamaya.model.spi.UsageTrackerSpi
new file mode 100644
index 0000000..1a87f60
--- /dev/null
+++ b/modules/model/src/main/resources/META-INF/services/org.apache.tamaya.model.spi.UsageTrackerSpi
@@ -0,0 +1,19 @@
+#
+# 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 current 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.
+#
+org.apache.tamaya.model.internal.DefaultUsageTracker
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/modules/model/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertyFilter
----------------------------------------------------------------------
diff --git a/modules/model/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertyFilter b/modules/model/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertyFilter
new file mode 100644
index 0000000..04cec4a
--- /dev/null
+++ b/modules/model/src/main/resources/META-INF/services/org.apache.tamaya.spi.PropertyFilter
@@ -0,0 +1,19 @@
+#
+# 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 current 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.
+#
+org.apache.tamaya.model.internal.UsageTrackerFilter
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/modules/model/src/test/java/test/model/TestConfigAccessor.java
----------------------------------------------------------------------
diff --git a/modules/model/src/test/java/test/model/TestConfigAccessor.java b/modules/model/src/test/java/test/model/TestConfigAccessor.java
new file mode 100644
index 0000000..191a074
--- /dev/null
+++ b/modules/model/src/test/java/test/model/TestConfigAccessor.java
@@ -0,0 +1,27 @@
+package test.model;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+
+import java.util.Map;
+
+/**
+ * Created by atsticks on 30.04.16.
+ */
+public final class TestConfigAccessor {
+
+    private TestConfigAccessor(){}
+
+    public static Map<String,String> readAllProperties(){
+        return ConfigurationProvider.getConfiguration()
+                .getProperties();
+    }
+
+    public static Configuration readConfiguration(){
+        return ConfigurationProvider.getConfiguration();
+    }
+
+    public static String readProperty(Configuration config, String key){
+        return config.get(key);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/ConfigEditorWidget.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/ConfigEditorWidget.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/ConfigEditorWidget.java
new file mode 100644
index 0000000..02e486b
--- /dev/null
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/ConfigEditorWidget.java
@@ -0,0 +1,110 @@
+/*
+ * 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.mutableconfig.ui;
+
+import com.vaadin.ui.*;
+import org.apache.tamaya.mutableconfig.MutableConfiguration;
+import org.apache.tamaya.spi.ServiceContextManager;
+import org.apache.tamaya.ui.services.MessageProvider;
+
+import java.util.Objects;
+
+/**
+ * Tamaya UI view to change configuration.
+ */
+public class ConfigEditorWidget extends FormLayout {
+
+    private MutableConfiguration mutableConfig;
+    private ProtocolWidget logWriter;
+
+    private TextField configKey = new TextField(
+            ServiceContextManager.getServiceContext().getService(MessageProvider.class)
+                    .getMessage("view.edit.text.configKey"));
+    private TextField configValue = new TextField(
+            ServiceContextManager.getServiceContext().getService(MessageProvider.class)
+                    .getMessage("view.edit.text.configValue"));
+    private Button updateButton = new Button(ServiceContextManager.getServiceContext().getService(MessageProvider.class)
+            .getMessage("view.edit.button.updateKey"));
+    private Button removeButton = new Button(ServiceContextManager.getServiceContext().getService(MessageProvider.class)
+            .getMessage("view.edit.button.removeKey"));
+    private Button readButton = new Button(ServiceContextManager.getServiceContext().getService(MessageProvider.class)
+            .getMessage("view.edit.button.readKey"));
+
+    public ConfigEditorWidget(MutableConfiguration mutableConfig, ProtocolWidget logWriter) {
+        this.mutableConfig = Objects.requireNonNull(mutableConfig);
+        this.logWriter = Objects.requireNonNull(logWriter);
+        configKey.setWidth(50, Unit.PERCENTAGE);
+        configValue.setWidth(50, Unit.PERCENTAGE);
+        addComponents(configKey, configValue);
+        HorizontalLayout buttonLayout = new HorizontalLayout();
+        buttonLayout.addComponents(readButton, new Label("   "), updateButton, removeButton);
+        buttonLayout.setSpacing(true);
+        addComponents(buttonLayout);
+        initActions();
+    }
+
+    private void initActions() {
+        updateButton.addClickListener(new Button.ClickListener() {
+            @Override
+            public void buttonClick(Button.ClickEvent clickEvent) {
+                if(mutableConfig.isWritable(configKey.getValue())){
+                    mutableConfig.put(configKey.getValue(), configValue.getValue());
+                    logWriter.println(" - PUT " + configKey.getValue() + " = " + configValue.getValue());
+                }else{
+                    logWriter.println(" - PUT " + configKey.getValue() + " rejected - not writable.");
+                }
+            }
+        });
+        removeButton.addClickListener(new Button.ClickListener() {
+            @Override
+            public void buttonClick(Button.ClickEvent clickEvent) {
+                if(mutableConfig.isRemovable(configKey.getValue())){
+                    mutableConfig.remove(configKey.getValue());
+                    logWriter.println(" - DEL " + configKey.getValue());
+                }else{
+                    logWriter.println(" - DEL " + configKey.getValue() + " rejected - not removable.");
+                }
+            }
+        });
+        readButton.addClickListener(new Button.ClickListener() {
+            @Override
+            public void buttonClick(Button.ClickEvent clickEvent) {
+                if(mutableConfig.isExisting(configKey.getValue())){
+                    String key = configKey.getValue();
+                    configValue.setValue(mutableConfig.get(key));
+                    logWriter.println(" - GET " + key + " = " + configValue.getValue());
+                    logWriter.println("   - removable: " + mutableConfig.isRemovable(key));
+                    logWriter.println("   - writable : " + mutableConfig.isWritable(key));
+                }else{
+                    logWriter.println(" - GET " + configKey.getValue() + " rejected - not existing.");
+                }
+            }
+        });
+    }
+
+    private String getCaption(String key, String value) {
+        int index = key.lastIndexOf('.');
+        if(index<0){
+            return key + " = " + value;
+        }else{
+            return key.substring(index+1) + " = " + value;
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/ConfigUpdaterView.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/ConfigUpdaterView.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/ConfigUpdaterView.java
index 81dfc3f..ea33d22 100644
--- a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/ConfigUpdaterView.java
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/ConfigUpdaterView.java
@@ -21,11 +21,10 @@ package org.apache.tamaya.mutableconfig.ui;
 import com.vaadin.navigator.View;
 import com.vaadin.navigator.ViewChangeListener;
 import com.vaadin.shared.ui.label.ContentMode;
-import com.vaadin.ui.ComboBox;
-import com.vaadin.ui.Label;
-import com.vaadin.ui.TextArea;
-import com.vaadin.ui.TextField;
+import com.vaadin.ui.*;
+import org.apache.tamaya.mutableconfig.MutableConfiguration;
 import org.apache.tamaya.mutableconfig.MutableConfigurationProvider;
+import org.apache.tamaya.mutableconfig.spi.MutablePropertySource;
 import org.apache.tamaya.spi.ServiceContextManager;
 import org.apache.tamaya.ui.UIConstants;
 import org.apache.tamaya.ui.ViewProvider;
@@ -33,7 +32,6 @@ import org.apache.tamaya.ui.components.VerticalSpacedLayout;
 import org.apache.tamaya.ui.services.MessageProvider;
 
 import javax.annotation.Priority;
-import java.util.Arrays;
 
 /**
  * Tamaya UI view to change configuration.
@@ -68,18 +66,14 @@ public class ConfigUpdaterView extends VerticalSpacedLayout implements View {
         }
     }
 
-    private ComboBox changePropagationPolicy = new ComboBox(ServiceContextManager.getServiceContext()
-            .getService(MessageProvider.class).getMessage("view.edit.select.propagationPolicy"),
-            Arrays.asList(new String[]{"ALL", "MOST_SIGNIFICANT_ONLY", "SELECTIVE", "NONE"}));
+    private ProtocolWidget protocolArea = new ProtocolWidget();
 
-    private TextField changePropagationPolicyOther = new TextField(
-            ServiceContextManager.getServiceContext().getService(MessageProvider.class)
-                    .getMessage("view.edit.text.propagationPolicyOther"),
-            MutableConfigurationProvider.getApplyAllChangePolicy().getClass().getName());
+    private MutableConfiguration mutableConfig = MutableConfigurationProvider.getMutableConfiguration();
 
-    private TextArea generalInfo = new TextArea(ServiceContextManager.getServiceContext()
-            .getService(MessageProvider.class).getMessage("view.edit.textArea.general"));
+    private TransactionControlWidget taControlWidget = new TransactionControlWidget(mutableConfig,
+            protocolArea);
 
+    private ConfigEditorWidget editorWidget = new ConfigEditorWidget(mutableConfig, protocolArea);
 
 
     public ConfigUpdaterView() {
@@ -91,13 +85,14 @@ public class ConfigUpdaterView extends VerticalSpacedLayout implements View {
 
         caption.addStyleName(UIConstants.LABEL_HUGE);
         description.addStyleName(UIConstants.LABEL_LARGE);
-        changePropagationPolicy.setWidth(300, Unit.PIXELS);
-        changePropagationPolicyOther.setWidth(600, Unit.PIXELS);
-        generalInfo.setWidth(100, Unit.PERCENTAGE);
-        addComponents(caption, description,changePropagationPolicy,changePropagationPolicyOther,generalInfo);
+        protocolArea.print("INFO: Writable Property Sources: ");
+        for(MutablePropertySource ps:mutableConfig.getMutablePropertySources()){
+            protocolArea.print(ps.getName(), ", ");
+        }
+        protocolArea.println();
+        addComponents(caption, description, editorWidget, protocolArea, taControlWidget);
     }
 
-
     private String getCaption(String key, String value) {
         int index = key.lastIndexOf('.');
         if(index<0){

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/ProtocolWidget.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/ProtocolWidget.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/ProtocolWidget.java
new file mode 100644
index 0000000..5ceaaa6
--- /dev/null
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/ProtocolWidget.java
@@ -0,0 +1,87 @@
+/*
+ * 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.mutableconfig.ui;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.TextArea;
+import com.vaadin.ui.VerticalLayout;
+import org.apache.tamaya.spi.ServiceContextManager;
+import org.apache.tamaya.ui.services.MessageProvider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Widget showing a text protocol wioth a clear button to clear the widget space.
+ */
+public class ProtocolWidget extends VerticalLayout{
+
+    private TextArea textArea = new TextArea(ServiceContextManager.getServiceContext()
+            .getService(MessageProvider.class).getMessage("view.edit.textArea.protocol"));
+    private Button clearButton = new Button(ServiceContextManager.getServiceContext().getService(MessageProvider.class)
+            .getMessage("view.edit.button.clearProtocol"));
+
+    private StringWriter protocol = new StringWriter();
+    private PrintWriter writer = new PrintWriter(protocol);
+
+    public ProtocolWidget(){
+        textArea.setWidth(100, Unit.PERCENTAGE);
+        textArea.setReadOnly(true);
+        clearButton.addClickListener(new Button.ClickListener() {
+            @Override
+            public void buttonClick(Button.ClickEvent clickEvent) {
+                protocol.getBuffer().setLength(0);
+                flush();
+            }
+        });
+        textArea.setSizeFull();
+        addComponents(textArea, clearButton);
+    }
+
+    public PrintWriter getWriter(){
+        return writer;
+    }
+
+    public void println(){
+        writer.println();
+    }
+
+    public void println(Object... items){
+        for(int i=0;i<items.length;i++){
+            writer.print(items[i]);
+        }
+        writer.println();
+        flush();
+    }
+
+    public void print(Object... items){
+        for(int i=0;i<items.length;i++){
+            writer.print(items[i]);
+        }
+        flush();
+    }
+
+    private void flush(){
+        writer.flush();
+        textArea.setReadOnly(false);
+        textArea.setValue(protocol.toString());
+        textArea.setReadOnly(true);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/TransactionControlWidget.java
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/TransactionControlWidget.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/TransactionControlWidget.java
new file mode 100644
index 0000000..73f4a18
--- /dev/null
+++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ui/TransactionControlWidget.java
@@ -0,0 +1,168 @@
+/*
+ * 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.mutableconfig.ui;
+
+import com.vaadin.data.Property;
+import com.vaadin.navigator.View;
+import com.vaadin.navigator.ViewChangeListener;
+import com.vaadin.shared.ui.label.ContentMode;
+import com.vaadin.ui.*;
+import org.apache.tamaya.mutableconfig.ChangePropagationPolicy;
+import org.apache.tamaya.mutableconfig.MutableConfiguration;
+import org.apache.tamaya.mutableconfig.MutableConfigurationProvider;
+import org.apache.tamaya.mutableconfig.spi.MutablePropertySource;
+import org.apache.tamaya.spi.ServiceContextManager;
+import org.apache.tamaya.ui.UIConstants;
+import org.apache.tamaya.ui.ViewProvider;
+import org.apache.tamaya.ui.components.VerticalSpacedLayout;
+import org.apache.tamaya.ui.services.MessageProvider;
+
+import javax.annotation.Priority;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Tamaya UI view to change configuration.
+ */
+public class TransactionControlWidget extends VerticalSpacedLayout {
+
+    private CheckBox autoCommit = new CheckBox(ServiceContextManager.getServiceContext()
+            .getService(MessageProvider.class).getMessage("view.edit.box.autoCommit"));
+
+    private ComboBox changePropagationPolicy = new ComboBox(ServiceContextManager.getServiceContext()
+            .getService(MessageProvider.class).getMessage("view.edit.select.propagationPolicy"),
+            Arrays.asList(new String[]{"ALL", "MOST_SIGNIFICANT_ONLY", "SELECTIVE", "NONE", "CUSTOM"}));
+
+    private TextField changePropagationPolicyOther = new TextField(
+            ServiceContextManager.getServiceContext().getService(MessageProvider.class)
+                    .getMessage("view.edit.text.propagationPolicyOther"),
+            MutableConfigurationProvider.getApplyAllChangePolicy().getClass().getName());
+
+    private MutableConfiguration mutableConfig;
+    private Button startTAButton = new Button(ServiceContextManager.getServiceContext().getService(MessageProvider.class)
+            .getMessage("view.edit.button.startTransaction"));
+    private Button rollbackTAButton = new Button(ServiceContextManager.getServiceContext().getService(MessageProvider.class)
+            .getMessage("view.edit.button.rollbackTransaction"));
+    private Button commitTAButton = new Button(ServiceContextManager.getServiceContext().getService(MessageProvider.class)
+            .getMessage("view.edit.button.commitTransaction"));
+    private ProtocolWidget logWriter;
+
+    public TransactionControlWidget(MutableConfiguration mutableConfig, ProtocolWidget logWriter) {
+        this.mutableConfig = Objects.requireNonNull(mutableConfig);
+        this.logWriter = Objects.requireNonNull(logWriter);
+        changePropagationPolicy.setWidth(300, Unit.PIXELS);
+        changePropagationPolicyOther.
+                setWidth(600, Unit.PIXELS);
+        HorizontalLayout buttonLayout = new HorizontalLayout();
+        buttonLayout.addComponents(startTAButton, commitTAButton, rollbackTAButton);
+        addComponents(changePropagationPolicy, changePropagationPolicyOther, buttonLayout);
+        initActions();
+    }
+
+    private void initActions() {
+        autoCommit.addValueChangeListener(new Property.ValueChangeListener() {
+            @Override
+            public void valueChange(Property.ValueChangeEvent valueChangeEvent) {
+                mutableConfig.setAutoCommit(autoCommit.getValue());
+                logWriter.println(" - Set Auto-Commit to " + autoCommit.getValue());
+            }
+        });
+        changePropagationPolicy.addValueChangeListener(new Property.ValueChangeListener() {
+            @Override
+            public void valueChange(Property.ValueChangeEvent valueChangeEvent) {
+                changePropagationPolicyOther.setEnabled(false);
+                changePropagationPolicyOther.addValueChangeListener(new Property.ValueChangeListener() {
+                    @Override
+                    public void valueChange(Property.ValueChangeEvent valueChangeEvent) {
+                        String className = changePropagationPolicyOther.getValue();
+                        try {
+                            mutableConfig.setChangePropagationPolicy(
+                                    (ChangePropagationPolicy) Class.forName(className).newInstance());
+                            logWriter.println(" - Set ChangePropagationPolicy " + className);
+                            Notification.show("Successfully applied change policy: " + className);
+                        } catch (Exception e) {
+                            Notification.show("Failed to apply change policy: " + className + ": " + e,
+                                    Notification.Type.ERROR_MESSAGE);
+                        }
+                    }
+                });
+                switch ((String) changePropagationPolicy.getValue()) {
+                    case "MOST_SIGNIFICANT_ONLY":
+                        mutableConfig.setChangePropagationPolicy(
+                                MutableConfigurationProvider.getApplyMostSignificantOnlyChangePolicy());
+                        logWriter.println(" - Set ChangePropagationPolicy to MOST_SIGNIFICANT_ONLY.");
+                        break;
+                    case "SELECTIVE":
+//                        mutableConfig.setChangePropagationPolicy(
+//                                MutableConfigurationProvider.getApplySelectiveChangePolicy("source1", "source2");
+                        Notification.show("Selective Backends are not yet supported by the UI.",
+                                Notification.Type.WARNING_MESSAGE);
+                        break;
+                    case "NONE":
+                        Notification.show("Applying none equals being your config READ-ONLY.",
+                                Notification.Type.ASSISTIVE_NOTIFICATION);
+                        mutableConfig.setChangePropagationPolicy(
+                                MutableConfigurationProvider.getApplyNonePolicy());
+                        logWriter.println(" - Set ChangePropagationPolicy to NONE.");
+                        break;
+                    case "CUSTOM":
+                        changePropagationPolicyOther.setEnabled(true);
+                        break;
+                    case "ALL":
+                    default:
+                        mutableConfig.setChangePropagationPolicy(
+                                MutableConfigurationProvider.getApplyAllChangePolicy());
+                        logWriter.println(" - Set ChangePropagationPolicy to ALL.");
+                }
+            }
+        });
+        startTAButton.addClickListener(new Button.ClickListener() {
+            @Override
+            public void buttonClick(Button.ClickEvent clickEvent) {
+                mutableConfig.startTransaction();
+                logWriter.println("Started Transaction: " + mutableConfig.getTransactionId());
+            }
+        });
+        rollbackTAButton.addClickListener(new Button.ClickListener() {
+            @Override
+            public void buttonClick(Button.ClickEvent clickEvent) {
+                mutableConfig.rollbackTransaction();
+                logWriter.println("Rolled back Transaction: " + mutableConfig.getTransactionId());
+            }
+        });
+        commitTAButton.addClickListener(new Button.ClickListener() {
+            @Override
+            public void buttonClick(Button.ClickEvent clickEvent) {
+                mutableConfig.commitTransaction();
+                logWriter.println("Committed Transaction: " + mutableConfig.getTransactionId());
+            }
+        });
+    }
+
+    private String getCaption(String key, String value) {
+        int index = key.lastIndexOf('.');
+        if (index < 0) {
+            return key + " = " + value;
+        } else {
+            return key.substring(index + 1) + " = " + value;
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4749d395/modules/mutable-config/src/main/resources/ui/lang/tamaya.properties
----------------------------------------------------------------------
diff --git a/modules/mutable-config/src/main/resources/ui/lang/tamaya.properties b/modules/mutable-config/src/main/resources/ui/lang/tamaya.properties
index 8f7d227..f1ce00a 100644
--- a/modules/mutable-config/src/main/resources/ui/lang/tamaya.properties
+++ b/modules/mutable-config/src/main/resources/ui/lang/tamaya.properties
@@ -20,4 +20,15 @@ view.edit.name=Edit Configuration
 view.edit.description=This is a simple Tamaya configuration editor for changing configuration values.
 view.edit.select.propagationPolicy=Change Propagation Policy
 view.edit.text.propagationPolicyOther=Custom Change Propagation Policy (Class)
-view.edit.textArea.general=General Infos
\ No newline at end of file
+view.edit.textArea.general=General Infos
+view.edit.box.autoCommit=Auto-Commit
+
+view.edit.button.startTransaction=Start TA
+view.edit.button.rollbackTransaction=Rollback
+view.edit.button.commitTransaction=Commit
+view.edit.text.configKey=Configuration Key
+view.edit.text.configValue=Value
+view.edit.button.updateKey=Write/Update
+view.edit.button.removeKey=Delete
+view.edit.button.readKey=Read from Config
+view.edit.button.clearProtocol=Clear Protocol
\ No newline at end of file


Mime
View raw message