src/jdk.jfr/share/classes/jdk/jfr/internal/SettingsManager.java
changeset 50113 caf115bb98ad
child 52334 a181612f0715
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/SettingsManager.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.StringJoiner;
+
+import jdk.jfr.Event;
+import jdk.jfr.internal.handlers.EventHandler;
+
+final class SettingsManager {
+
+    private static class InternalSetting {
+
+        private final String identifier;
+        private Map<String, Set<String>> enabledMap = new LinkedHashMap<>(5);
+        private Map<String, Set<String>> allMap = new LinkedHashMap<>(5);
+        private boolean enabled;
+
+        /**
+         * Settings identifier, for example "com.example.HelloWorld" or "56"
+         * (id of event)
+         *
+         * @param settingsId
+         */
+        public InternalSetting(String settingsId) {
+            this.identifier = settingsId;
+        }
+
+        public Set<String> getValues(String key) {
+            if (enabled) {
+                return enabledMap.get(key);
+            } else {
+                return allMap.get(key);
+            }
+        }
+
+        public void add(String attribute, String value) {
+            if ("enabled".equals(attribute) && "true".equals(value)) {
+                enabled = true;
+                allMap = null; // no need to keep these around
+            }
+            addToMap(enabledMap, attribute, value);
+            if (allMap != null) {
+                addToMap(allMap, attribute, value);
+            }
+        }
+
+        private void addToMap(Map<String, Set<String>> map, String attribute, String value) {
+            Set<String> values = map.get(attribute);
+            if (values == null) {
+                values = new HashSet<String>(5);
+                map.put(attribute, values);
+            }
+            values.add(value);
+
+        }
+
+        public String getSettingsId() {
+            return identifier;
+        }
+
+        public void add(InternalSetting enabled) {
+            for (Map.Entry<String, Set<String>> entry : enabled.enabledMap.entrySet()) {
+                for (String value : entry.getValue()) {
+                    add(entry.getKey(), value);
+                }
+            }
+        }
+
+        public boolean isEnabled() {
+            return enabled;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(identifier);
+            sb.append(": ");
+            sb.append(enabledMap.toString());
+            return sb.toString();
+        }
+
+        public void finish() {
+            if (!enabled) {
+                // settings from disabled
+                // events should not impact results, but
+                // we can't clear enabledMap since enabled=false
+                // needs be there, so events that are enabled
+                // by default are turned off
+                Map<String, Set<String>> disabledMap = new HashMap<>(2);
+                Set<String> values = new HashSet<>(2);
+                values.add("false");
+                disabledMap.put("enabled", values);
+                enabledMap = disabledMap;
+            }
+        }
+    }
+
+   private Map<String, InternalSetting> availableSettings = new LinkedHashMap<>();
+
+    void setSettings(List<Map<String, String>> activeSettings) {
+        // store settings so they are available if a new event class is loaded
+        availableSettings = createSettingsMap(activeSettings);
+        List<EventControl> eventControls = MetadataRepository.getInstance().getEventControls();
+        if (!JVM.getJVM().isRecording()) {
+            for (EventControl ec : eventControls) {
+                ec.disable();
+            }
+        } else {
+            if (LogTag.JFR_SETTING.shouldLog(LogLevel.INFO.level)) {
+                Collections.sort(eventControls, (x,y) -> x.getEventType().getName().compareTo(y.getEventType().getName()));
+            }
+            for (EventControl ec : eventControls) {
+                setEventControl(ec);
+            }
+        }
+        if (JVM.getJVM().getAllowedToDoEventRetransforms()) {
+            updateRetransform(JVM.getJVM().getAllEventClasses());
+        }
+    }
+
+    public void updateRetransform(List<Class<? extends Event>> eventClasses) {
+        List<Class<?>> classes = new ArrayList<>();
+        for(Class<? extends Event> eventClass: eventClasses) {
+            EventHandler eh = Utils.getHandler(eventClass);
+            if (eh != null ) {
+                PlatformEventType eventType = eh.getPlatformEventType();
+                if (eventType.isMarkedForInstrumentation()) {
+                    classes.add(eventClass);
+                    eventType.markForInstrumentation(false);
+                    // A bit premature to set it here, but hard to check
+                    // after call to retransformClasses.
+                    eventType.setInstrumented();
+                }
+            }
+        }
+        if (!classes.isEmpty()) {
+            JVM.getJVM().retransformClasses(classes.toArray(new Class<?>[0]));
+        }
+    }
+
+    private Map<String, InternalSetting> createSettingsMap(List<Map<String,String>> activeSettings) {
+        Map<String, InternalSetting> map = new LinkedHashMap<>(activeSettings.size());
+        for (Map<String, String> rec : activeSettings) {
+            for (InternalSetting internal : makeInternalSettings(rec)) {
+                InternalSetting is = map.get(internal.getSettingsId());
+                if (is == null) {
+                    map.put(internal.getSettingsId(), internal);
+                } else {
+                    is.add(internal);
+                }
+            }
+        }
+        return map;
+    }
+
+    private Collection<InternalSetting> makeInternalSettings(Map<String, String> rec) {
+        Map<String, InternalSetting> internals = new LinkedHashMap<>();
+        for (Map.Entry<String, String> entry : rec.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue();
+            int index = key.indexOf("#");
+            if (index > 1 && index < key.length() - 2) {
+                String eventName = key.substring(0, index);
+                eventName = Utils.upgradeLegacyJDKEvent(eventName);
+                InternalSetting s = internals.get(eventName);
+                String settingName = key.substring(index + 1).trim();
+                if (s == null) {
+                    s = new InternalSetting(eventName);
+                    internals.put(eventName, s);
+                }
+                s.add(settingName, value);
+            }
+        }
+      for (InternalSetting s : internals.values()) {
+         s.finish();
+      }
+
+      return internals.values();
+    }
+
+    void setEventControl(EventControl ec) {
+        InternalSetting is = getInternalSetting(ec);
+        Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, "Applied settings for " + ec.getEventType().getLogName() + " {");
+        for (Entry<String, Control> entry : ec.getEntries()) {
+            Set<String> values = null;
+            String settingName = entry.getKey();
+            if (is != null) {
+                values = is.getValues(settingName);
+            }
+            Control control = entry.getValue();
+            if (values != null) {
+                control.apply(values);
+                String after = control.getLastValue();
+                if (LogTag.JFR_SETTING.shouldLog(LogLevel.INFO.level)) {
+                    if (Utils.isSettingVisible(control, ec.getEventType().hasEventHook())) {
+                        if (values.size() > 1) {
+                            StringJoiner sj = new StringJoiner(", ", "{", "}");
+                            for (String s : values) {
+                                sj.add("\"" + s + "\"");
+                            }
+                            String message = "  " + settingName + "= " + sj.toString() + " => \"" + after + "\"";
+                            Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, message);
+                        } else {
+                            String message = "  " + settingName + "=\"" + control.getLastValue() + "\"";
+                            Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, message);
+                        }
+                    }
+                }
+            } else {
+                control.setDefault();
+                if (LogTag.JFR_SETTING.shouldLog(LogLevel.INFO.level)) {
+                    String message = "  " + settingName + "=\"" + control.getLastValue() + "\"";
+                    Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, message);
+                }
+            }
+        }
+        ec.writeActiveSettingEvent();
+        Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, "}");
+    }
+
+    private InternalSetting getInternalSetting(EventControl ec) {
+        String name = ec.getEventType().getName();
+        InternalSetting nameBased = availableSettings.get(name);
+        InternalSetting idBased = availableSettings.get(ec.getSettingsId());
+
+        if (nameBased == null && idBased == null) {
+            return null;
+        }
+        if (idBased == null) {
+            return nameBased;
+        }
+        if (nameBased == null) {
+            return idBased;
+        }
+        InternalSetting mixed = new InternalSetting(nameBased.getSettingsId());
+        mixed.add(nameBased);
+        mixed.add(idBased);
+        return mixed;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        for (InternalSetting enabled : availableSettings.values()) {
+            sb.append(enabled.toString());
+            sb.append("\n");
+        }
+        return sb.toString();
+    }
+
+    boolean isEnabled(String eventName) {
+        InternalSetting is = availableSettings.get(eventName);
+        if (is == null) {
+            return false;
+        }
+        return is.isEnabled();
+    }
+}