1 /* 2 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.jfr; 27 28 import java.security.AccessController; 29 import java.util.Set; 30 31 import jdk.jfr.internal.Control; 32 33 /** 34 * Base class to extend to create setting controls. 35 * <p> 36 * The following example shows a naive implementation of a setting control for 37 * regular expressions: 38 * 39 * <pre> 40 * <code> 41 * final class RegExpControl extends SettingControl { 42 * private Pattern pattern = Pattern.compile(".*"); 43 * 44 * {@literal @}Override 45 * public void setValue(String value) { 46 * this.pattern = Pattern.compile(value); 47 * } 48 * 49 * {@literal @}Override 50 * public String combine(Set{@literal <}String{@literal >} values) { 51 * return String.join("|", values); 52 * } 53 * 54 * {@literal @}Override 55 * public String getValue() { 56 * return pattern.toString(); 57 * } 58 * 59 * public String matches(String s) { 60 * return pattern.matcher(s).find(); 61 * } 62 * } 63 * </code> 64 * </pre> 65 * 66 * The {@code setValue(String)}, {@code getValue()} and 67 * {@code combine(Set<String>)} methods are invoked when a setting value 68 * changes, which typically happens when a recording is started or stopped. The 69 * {@code combine(Set<String>)} method is invoked to resolve what value to use 70 * when multiple recordings are running at the same time. 71 * <p> 72 * The setting control must have a default constructor that can be invoked when 73 * the event is registered. 74 * <p> 75 * To use a setting control with an event, add a method that returns a 76 * {@code boolean} value and takes the setting control as a parameter. Annotate 77 * the method with the {@code @SettingDefinition} annotation. By default, the 78 * method name is used as the setting name, but the name can be set explicitly 79 * by using the {@code @Name} annotation. If the method returns {@code true}, 80 * the event will be committed. 81 * <p> 82 * It is recommended that the {@code setValue(String)} method updates an 83 * efficient data structure that can be quickly checked when the event is 84 * committed. 85 * <p> 86 * The following example shows how to create an event that uses the 87 * regular expression filter defined above. 88 * 89 * <pre> 90 * <code> 91 * abstract class HTTPRequest extends Event { 92 * {@literal @}Label("Request URI") 93 * protected String uri; 94 * 95 * {@literal @}Label("Servlet URI Filter") 96 * {@literal @}SettingDefinition 97 * protected boolean uriFilter(RegExpControl regExp) { 98 * return regExp.matches(uri); 99 * } 100 * } 101 * 102 * {@literal @}Label("HTTP Get Request") 103 * class HTTPGetRequest extends HTTPRequest { 104 * } 105 * 106 * {@literal @}Label("HTTP Post Request") 107 * class HTTPPostRequest extends HTTPRequest { 108 * } 109 * 110 * class ExampleServlet extends HTTPServlet { 111 * protected void doGet(HttpServletRequest req, HttpServletResponse resp) { 112 * HTTPGetRequest request = new HTTPGetRequest(); 113 * request.begin(); 114 * request.uri = req.getRequestURI(); 115 * ... 116 * request.commit(); 117 * } 118 * 119 * protected void doPost(HttpServletRequest req, HttpServletResponse resp) { 120 * HTTPPostRequest request = new HTTPPostRequest(); 121 * request.begin(); 122 * request.uri = req.getRequestURI(); 123 * ... 124 * request.commit(); 125 * } 126 * } 127 * </code> 128 * </pre> 129 * 130 * The following example shows how an event can be filtered by assigning the 131 * {@code "uriFilter"} setting with the specified regular expressions. 132 * 133 * <pre> 134 * <code> 135 * Recording r = new Recording(); 136 * r.enable("HTTPGetRequest").with("uriFilter", "https://www.example.com/list/.*"); 137 * r.enable("HTTPPostRequest").with("uriFilter", "https://www.example.com/login/.*"); 138 * r.start(); 139 * </code> 140 * </pre> 141 * 142 * 143 * 144 * @see SettingDefinition 145 * 146 * @since 9 147 */ 148 @MetadataDefinition 149 public abstract class SettingControl extends Control { 150 151 /** 152 * Constructor for invocation by subclass constructors. 153 */ 154 protected SettingControl() { 155 super(AccessController.getContext()); 156 157 } 158 159 /** 160 * Combines the setting values for all running recordings into one value when 161 * multiple recordings are running at the same time, 162 * <p> 163 * The semantics of how setting values are combined depends on the setting 164 * control that is implemented, but all recordings should get at least all the 165 * events they request. 166 * <p> 167 * This method should have no side effects, because the caller might cache values. 168 * This method should never return {@code null} or throw an exception. If a 169 * value is not valid for this setting control, the value should be ignored. 170 * <p> 171 * Examples: 172 * <p> 173 * if the setting control represents a threshold and three recordings are 174 * running at the same time with the setting values {@code "10 ms"}, 175 * {@code "8 s"}, and {@code "1 ms"}, this method returns {@code "1 ms"} 176 * because it means that all recordings get at least all the requested data. 177 * <p> 178 * If the setting control represents a set of names and two recordings are 179 * running at the same time with the setting values {@code "Smith, Jones"} and {@code "Jones, 180 * Williams"} the returned value is {@code "Smith, Jones, Williams"} because all names would be accepted. 181 * <p> 182 * If the setting control represents a boolean condition and four recordings are 183 * running at the same time with the following values {@code "true"}, {@code "false"}, {@code "false"}, and 184 * {@code "incorrect"}, this method returns {@code "true"}, because all 185 * recordings get at least all the requested data. 186 * 187 * @param settingValues the set of values, not {@code null} 188 * 189 * @return the value to use, not {@code null} 190 */ 191 @Override 192 public abstract String combine(Set<String> settingValues); 193 194 /** 195 * Sets the value for this setting. 196 * <p> 197 * If the setting value is not valid for this setting, this method 198 * does not throw an exception. Instead, the value is ignored. 199 * 200 * @param settingValue the string value, not {@code null} 201 */ 202 @Override 203 public abstract void setValue(String settingValue); 204 205 /** 206 * Returns the currently used value for this setting, not {@code null}. 207 * <p> 208 * The value returned by this method is valid as an argument to both 209 * the {@code setValue(String)} method and {@code combine(Set)} method. 210 * <p> 211 * This method is invoked when an event is registered to obtain the 212 * default value. It is therefore important that a valid value can be 213 * returned immediately after an instance of this class is created. It is 214 * not valid to return {@code null}. 215 * 216 * @return the setting value, not {@code null} 217 */ 218 @Override 219 public abstract String getValue(); 220 }