1 /*
   2  * Copyright (c) 2018, 2019, 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.event;
  27 
  28 import java.io.IOException;
  29 import java.util.List;
  30 
  31 import jdk.jfr.Event;
  32 import jdk.jfr.EventType;
  33 import jdk.jfr.FlightRecorder;
  34 import jdk.jfr.Recording;
  35 import jdk.jfr.Registered;
  36 import jdk.jfr.consumer.RecordedEvent;
  37 import jdk.testlibrary.Asserts;
  38 import jdk.testlibrary.jfr.Events;
  39 
  40 /*
  41  * @test
  42  * @summary Test enable/disable event and verify recording has expected events.
  43  * @key jfr
  44  * @library /lib/testlibrary
  45  * @run main/othervm jdk.jfr.api.event.TestClinitRegistration
  46  */
  47 
  48 public class TestClinitRegistration {
  49 
  50     public static void main(String[] args) throws Exception {
  51         // Test basic registration with or without auto registration
  52         assertClinitRegister(AutoRegisteredEvent.class, true, false);
  53         assertClinitRegister(NotAutoRegisterededEvent.class, false, false);
  54         assertClinitRegister(AutoRegisteredUserClinit.class, true, true);
  55         assertClinitRegister(NotAutoRegisteredUserClinit.class, false, true);
  56 
  57         // Test complex <clinit>
  58         assertClinitRegister(ComplexClInit.class, true, true);
  59 
  60         // Test hierarchy
  61         assertClinitRegister(DerivedClinit.class, true, true);
  62         if (!isClinitExecuted(Base.class)) {
  63             Asserts.fail("Expected <clinit> of base class to be executed");
  64         }
  65 
  66         // Test committed event in <clinit>
  67         Recording r = new Recording();
  68         r.start();
  69         r.enable(EventInClinit.class);
  70         triggerClinit(EventInClinit.class);
  71         r.stop();
  72         hasEvent(r, EventInClinit.class.getName());
  73     }
  74 
  75     private static void assertClinitRegister(Class<? extends Event> eventClass, boolean shouldExist, boolean setsProperty) throws ClassNotFoundException {
  76         String className = eventClass.getName();
  77         triggerClinit(eventClass);
  78         boolean hasEventType = hasEventType(className);
  79         boolean hasProperty = Boolean.getBoolean(className);
  80         if (hasEventType && !shouldExist) {
  81             Asserts.fail("Event class " + className + " should not be registered");
  82         }
  83         if (!hasEventType && shouldExist) {
  84             Asserts.fail("Event class " + className + " is not registered");
  85         }
  86         if (setsProperty && !hasProperty) {
  87             Asserts.fail("Expected clinit to be executed");
  88         }
  89         if (!setsProperty && hasProperty) {
  90             Asserts.fail("Property in clinit should not been set. Test bug?");
  91         }
  92     }
  93 
  94     private static boolean hasEventType(String name) {
  95         for (EventType type : FlightRecorder.getFlightRecorder().getEventTypes()) {
  96             if (type.getName().equals(name)) {
  97                 return true;
  98             }
  99         }
 100         return false;
 101     }
 102 
 103     private static void triggerClinit(Class<?> clazz) throws ClassNotFoundException {
 104         Class.forName(clazz.getName(), true, clazz.getClassLoader());
 105     }
 106 
 107     private static void setClinitExecuted(Class<? extends Event> eventClass) {
 108         System.setProperty(eventClass.getName(), "true");
 109     }
 110 
 111     private static boolean isClinitExecuted(Class<? extends Event> eventClass) {
 112         return "true".equals(System.getProperty(eventClass.getName(), "true"));
 113     }
 114 
 115     static class AutoRegisteredEvent extends Event {
 116     }
 117 
 118     @Registered(false)
 119     static class NotAutoRegisterededEvent extends Event {
 120     }
 121 
 122     static class AutoRegisteredUserClinit extends Event {
 123         static {
 124             setClinitExecuted(AutoRegisteredUserClinit.class);
 125         }
 126     }
 127 
 128     @Registered(false)
 129     static class NotAutoRegisteredUserClinit extends Event {
 130         static {
 131             setClinitExecuted(NotAutoRegisteredUserClinit.class);
 132         }
 133     }
 134 
 135     static class Base extends Event {
 136         static {
 137             setClinitExecuted(Base.class);
 138         }
 139     }
 140 
 141     static class DerivedClinit extends Base {
 142         static {
 143             setClinitExecuted(DerivedClinit.class);
 144         }
 145 
 146         @Deprecated
 147         void myVoidMethod() {
 148         }
 149     }
 150 
 151     static class ComplexClInit extends Event {
 152         static {
 153             setClinitExecuted(ComplexClInit.class);
 154         }
 155         public static final long l = Long.parseLong("7");
 156         public static final int i = Integer.parseInt("7");
 157         public static final short s = Short.parseShort("7");
 158         public static final double d = Double.parseDouble("7");
 159         public static final float f = Float.parseFloat("7");
 160         public static final boolean b = Boolean.parseBoolean("true");
 161         public static final char c = (char) Integer.parseInt("48");
 162         public static final String text = "ioio".substring(2);
 163         public static final int[] primitivArray = new int[] { 7, 4 };
 164         public static final Class<?> Object = ComplexClInit.class;
 165 
 166         static {
 167             String text = "";
 168             long l = 56;
 169             long i = 56;
 170             if (i != l) {
 171                 throw new RuntimeException("unexpected result from comparison");
 172             }
 173             if (!isClinitExecuted(ComplexClInit.class)) {
 174                 throw new RuntimeException("Expected clinit flag to be set" + text);
 175             }
 176         }
 177 
 178         static {
 179             try {
 180                 throw new IllegalStateException("Exception");
 181             } catch (IllegalStateException ise) {
 182                 // as expected
 183             }
 184         }
 185     }
 186 
 187     static class EventInClinit extends Event {
 188         static {
 189             EventInClinit eventInClinit = new EventInClinit();
 190             eventInClinit.commit();
 191         }
 192     }
 193 
 194     public static void hasEvent(Recording r, String name) throws IOException {
 195         List<RecordedEvent> events = Events.fromRecording(r);
 196         Events.hasEvents(events);
 197 
 198         for (RecordedEvent event : events) {
 199             if (event.getEventType().getName().equals(name)) {
 200                 return;
 201             }
 202         }
 203         Asserts.fail("Missing event " + name + " in recording " + events.toString());
 204     }
 205 }