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