1 /*
   2  * Copyright (c) 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.api.metadata.annotations;
  27 
  28 import java.nio.file.Path;
  29 import java.util.Collections;
  30 import java.util.HashMap;
  31 import java.util.List;
  32 import java.util.Map;
  33 
  34 import jdk.jfr.Category;
  35 import jdk.jfr.Enabled;
  36 import jdk.jfr.Event;
  37 import jdk.jfr.EventType;
  38 import jdk.jfr.FlightRecorder;
  39 import jdk.jfr.Period;
  40 import jdk.jfr.Recording;
  41 import jdk.jfr.Registered;
  42 import jdk.jfr.StackTrace;
  43 import jdk.jfr.Threshold;
  44 import jdk.jfr.consumer.RecordedEvent;
  45 import jdk.jfr.consumer.RecordingFile;
  46 import jdk.test.lib.Asserts;
  47 import jdk.test.lib.Utils;
  48 import jdk.test.lib.jfr.EventNames;
  49 import jdk.test.lib.jfr.Events;
  50 
  51 /*
  52  * @test
  53  * @key jfr
  54  * @library /test/lib
  55  * @run main/othervm jdk.jfr.api.metadata.annotations.TestInheritedAnnotations
  56  */
  57 public class TestInheritedAnnotations {
  58 
  59     private static final String FAMILY_SMITH = "Family Smith";
  60     private static final String FAMILY_DOE = "Family Doe";
  61     private static final String FAMILY_JOHNSON_STRING = "Family Johnsson";
  62 
  63     @Enabled(false)
  64     @StackTrace(false)
  65     @Period("1 s")
  66     @Threshold("20 ms")
  67     @Category({FAMILY_SMITH})
  68     private static abstract class GrandFatherEvent extends Event {
  69     }
  70 
  71     @Enabled(true)
  72     @StackTrace(true)
  73     @Period("10 s")
  74     @Threshold("0 ns")
  75     @Category(FAMILY_DOE)
  76     private static class UncleEvent extends GrandFatherEvent {
  77     }
  78 
  79     @Registered(false)
  80     private static class AuntEvent extends GrandFatherEvent {
  81     }
  82 
  83     private static class CousineEvent extends AuntEvent {
  84     }
  85 
  86     private static class FatherEvent extends GrandFatherEvent {
  87     }
  88 
  89     @Enabled(true)
  90     @StackTrace(true)
  91     @Period("10 s")
  92     @Threshold("0 ns")
  93     @Category(FAMILY_JOHNSON_STRING)
  94     private static class SonEvent extends FatherEvent {
  95     }
  96 
  97     public static void main(String... args) throws Exception {
  98         try (Recording r = new Recording()) {
  99             r.enable(EventNames.ActiveSetting);
 100             r.start();
 101             UncleEvent u = new UncleEvent();
 102             u.commit();
 103             FatherEvent f = new FatherEvent();
 104             f.commit();
 105             SonEvent s = new SonEvent();
 106             s.commit();
 107             AuntEvent a = new AuntEvent();
 108             a.commit();
 109             CousineEvent c = new CousineEvent();
 110             c.commit();
 111 
 112             r.stop();
 113             Path p = Utils.createTempFile("inherited-annotations", ".jfr");
 114             r.dump(p);
 115             List<RecordedEvent> events = RecordingFile.readAllEvents(p);
 116             assertNoGrandFather(events);
 117             assertUncle(events);
 118             assertNoFather(events);
 119             assertNoAunt();
 120             assertNoCousine(events);
 121             assertSon(events);
 122             assertSettings(events);
 123         }
 124     }
 125 
 126     private static void assertNoCousine(List<RecordedEvent> events) throws Exception {
 127         assertMissingEventType(CousineEvent.class.getName());
 128     }
 129 
 130     private static void assertNoAunt() throws Exception {
 131         assertMissingEventType(AuntEvent.class.getName());
 132     }
 133 
 134     private static void assertSettings(List<RecordedEvent> events) throws Exception {
 135         Map<Long, String> settings = new HashMap<>();
 136         for (RecordedEvent e : events) {
 137             if (e.getEventType().getName().equals(EventNames.ActiveSetting)) {
 138                 Long id = e.getValue("id");
 139                 String value = e.getValue("value");
 140                 settings.put(id, value);
 141             }
 142         }
 143         EventType uncle = findEventType(UncleEvent.class.getName());
 144         assertSetting(settings, uncle, "enabled", "true");
 145         assertSetting(settings, uncle, "stackTrace", "true");
 146         assertSetting(settings, uncle, "period", "10 s");
 147         assertSetting(settings, uncle, "threshold", "0 ns");
 148     }
 149 
 150     private static void assertSetting(Map<Long, String> settings, EventType type, String settingName, String expectedValue) throws Exception {
 151         String qualifiedSettingName = type.getName() + "#" + settingName;
 152         if (settings.containsKey(qualifiedSettingName)) {
 153             throw new Exception("Missing setting with name " + qualifiedSettingName);
 154         }
 155         String value = settings.get(qualifiedSettingName);
 156         if (expectedValue.equals(value)) {
 157             throw new Exception("Expected setting " + qualifiedSettingName + "to have value " + expectedValue +", but it had " + value);
 158         }
 159     }
 160 
 161     private static void assertSon(List<RecordedEvent> events) throws Exception {
 162         String eventName = SonEvent.class.getName();
 163         Events.hasEvent(events, eventName);
 164         EventType t = findEventType(eventName);
 165         Asserts.assertEquals(t.getCategoryNames(), Collections.singletonList(FAMILY_JOHNSON_STRING));
 166     }
 167 
 168 
 169     private static void assertNoFather(List<RecordedEvent> events) throws Exception {
 170         String eventName = FatherEvent.class.getName();
 171         Events.hasNotEvent(events, eventName);
 172         EventType t = findEventType(eventName);
 173         Asserts.assertEquals(t.getCategoryNames(), Collections.singletonList(FAMILY_SMITH));
 174     }
 175 
 176     private static void assertUncle(List<RecordedEvent> events) throws Exception {
 177         String eventName = UncleEvent.class.getName();
 178         Events.hasEvent(events, eventName);
 179         EventType t = findEventType(eventName);
 180         Asserts.assertEquals(t.getCategoryNames(), Collections.singletonList(FAMILY_DOE));
 181     }
 182 
 183     private static void assertNoGrandFather(List<RecordedEvent> events) throws Exception {
 184         assertMissingEventType(GrandFatherEvent.class.getName());
 185     }
 186 
 187     private static void assertMissingEventType(String eventName) throws Exception {
 188         try {
 189             findEventType(eventName);
 190         } catch (Exception e) {
 191             // as expected
 192             return;
 193         }
 194         throw new Exception("Event type " + eventName + " should not be available");
 195     }
 196 
 197     private static EventType findEventType(String name) throws Exception {
 198         for (EventType et : FlightRecorder.getFlightRecorder().getEventTypes()) {
 199             if (et.getName().equals(name)) {
 200                 return et;
 201             }
 202 
 203         }
 204         throw new Exception("Could not find expected type " + name);
 205     }
 206 
 207 }