--- /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();
+ }
+}