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