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.dynamic;
  27 
  28 import java.io.IOException;
  29 import java.lang.annotation.ElementType;
  30 import java.lang.annotation.Retention;
  31 import java.lang.annotation.RetentionPolicy;
  32 import java.lang.annotation.Target;
  33 import java.util.ArrayList;
  34 import java.util.Collections;
  35 import java.util.HashMap;
  36 import java.util.List;
  37 import java.util.Map;
  38 
  39 import jdk.jfr.AnnotationElement;
  40 import jdk.jfr.Category;
  41 import jdk.jfr.Description;
  42 import jdk.jfr.Event;
  43 import jdk.jfr.EventFactory;
  44 import jdk.jfr.EventType;
  45 import jdk.jfr.Label;
  46 import jdk.jfr.MetadataDefinition;
  47 import jdk.jfr.Name;
  48 import jdk.jfr.Recording;
  49 import jdk.jfr.Relational;
  50 import jdk.jfr.ValueDescriptor;
  51 import jdk.jfr.consumer.RecordedEvent;
  52 import jdk.testlibrary.jfr.Events;
  53 
  54 /*
  55  * @test
  56  * @key jfr
  57  * @library /lib/testlibrary
  58  * @run main/othervm jdk.jfr.api.event.dynamic.TestDynamicAnnotations
  59  */
  60 public class TestDynamicAnnotations {
  61 
  62     @Label("Execution Context Id")
  63     @Description("A unique identifier to correlate events or requests associated with the same task across several components")
  64     @Relational
  65     @MetadataDefinition
  66     @Target(ElementType.FIELD)
  67     @Retention(RetentionPolicy.RUNTIME)
  68     private @interface ECID {
  69     }
  70 
  71     @MetadataDefinition
  72     @Target({ ElementType.FIELD, ElementType.TYPE })
  73     @Retention(RetentionPolicy.RUNTIME)
  74     private @interface Array {
  75         String[] stringArray();
  76 
  77         int[] intArray();
  78 
  79         long[] longArray();
  80 
  81         float[] floatArray();
  82 
  83         double[] doubleArray();
  84 
  85         boolean[] booleanArray();
  86 
  87         short[] shortArray();
  88 
  89         byte[] byteArray();
  90 
  91         char[] charArray();
  92     }
  93 
  94     public static void main(String[] args) throws Throwable {
  95         testEventFactoryExample();
  96         testECID();
  97         testArray();
  98     }
  99 
 100     // Copy of sample code in Javadoc for jdk.jfr.EVentFactory
 101     public static void testEventFactoryExample() throws IOException {
 102          List<ValueDescriptor> fields = new ArrayList<>();
 103          List<AnnotationElement> messageAnnotations = Collections.singletonList(new AnnotationElement(Label.class, "Message"));
 104          fields.add(new ValueDescriptor(String.class, "message", messageAnnotations));
 105          List<AnnotationElement> numberAnnotations = Collections.singletonList(new AnnotationElement(Label.class, "Number"));
 106          fields.add(new ValueDescriptor(int.class, "number", numberAnnotations));
 107 
 108          String[] category = { "Example", "Getting Started" };
 109          List<AnnotationElement> eventAnnotations = new ArrayList<>();
 110          eventAnnotations.add(new AnnotationElement(Name.class, "com.example.HelloWorld"));
 111          eventAnnotations.add(new AnnotationElement(Label.class, "Hello World"));
 112          eventAnnotations.add(new AnnotationElement(Description.class, "Helps programmer getting started"));
 113          eventAnnotations.add(new AnnotationElement(Category.class, category));
 114 
 115          EventFactory f = EventFactory.create(eventAnnotations, fields);
 116 
 117          Event event = f.newEvent();
 118          event.set(0, "hello, world!");
 119          event.set(1, 4711);
 120          event.commit();
 121     }
 122 
 123     public static void testECID() throws Exception {
 124         List<ValueDescriptor> fields = new ArrayList<>();
 125 
 126         List<AnnotationElement> fieldAnnotations = new ArrayList<>();
 127         fieldAnnotations.add(new AnnotationElement(ECID.class));
 128         ValueDescriptor ecidField = new ValueDescriptor(String.class, "ecid", fieldAnnotations);
 129         fields.add(ecidField);
 130 
 131         EventFactory f = EventFactory.create(fieldAnnotations, fields);
 132 
 133         String ecidValue = "131739871298371279812";
 134         try (Recording r = new Recording()) {
 135             r.start();
 136             Event event = f.newEvent();
 137             event.set(0, ecidValue);
 138             event.commit();
 139             r.stop();
 140             List<RecordedEvent> events = Events.fromRecording(r);
 141             Events.hasEvents(events);
 142             Events.assertField(events.get(0), "ecid").equal(ecidValue);
 143         }
 144         EventType type = f.getEventType();
 145         ECID e = type.getAnnotation(ECID.class);
 146         if (e == null) {
 147             throw new Exception("Missing ECID annotation");
 148         }
 149     }
 150 
 151     public static void testArray() throws Exception {
 152         List<AnnotationElement> annotations = new ArrayList<>();
 153         Map<String, Object> values = new HashMap<>();
 154         values.put("stringArray", new String[] {"zero", "one"});
 155         values.put("intArray", new int[] {0, 1});
 156         values.put("longArray", new long[] {0L, 1L});
 157         values.put("floatArray", new float[] {0.0f, 1.0f});
 158         values.put("doubleArray", new double[] {0.0, 1.0});
 159         values.put("booleanArray", new boolean[] {false, true});
 160         values.put("shortArray", new short[] {(short)0, (short)1});
 161         values.put("byteArray", new byte[] {(byte)0, (byte)1});
 162         values.put("charArray", new char[] {'0','1'});
 163 
 164         annotations.add(new AnnotationElement(Array.class, values));
 165         EventFactory f = EventFactory.create(annotations, Collections.emptyList());
 166         Array a = f.getEventType().getAnnotation(Array.class);
 167         if (a == null) {
 168             throw new Exception("Missing array annotation");
 169         }
 170         verifyArrayAnnotation(a);
 171         System.out.println("Event metadata is correct");
 172         try (Recording r = new Recording()) {
 173             r.start();
 174             Event e = f.newEvent();
 175             e.commit();
 176             r.stop();
 177             List<RecordedEvent> events = Events.fromRecording(r);
 178             Events.hasEvents(events);
 179             RecordedEvent re = events.get(0);
 180             Array arrayAnnotation = re.getEventType().getAnnotation(Array.class);
 181             if (arrayAnnotation== null) {
 182                 throw new Exception("Missing array annotation");
 183             }
 184             verifyArrayAnnotation(arrayAnnotation);
 185             System.out.println("Persisted event metadata is correct");
 186         }
 187     }
 188 
 189     private static void verifyArrayAnnotation(Array a) throws Exception {
 190         if (!a.stringArray()[0].equals("zero") || !a.stringArray()[1].equals("one")) {
 191             throw new Exception("string[] doesn't match");
 192         }
 193         if (a.intArray()[0] != 0 || a.intArray()[1] != 1) {
 194             throw new Exception("int[] doesn't match");
 195         }
 196         if (a.longArray()[0] != 0 || a.longArray()[1] != 1) {
 197             throw new Exception("long[] doesn't match");
 198         }
 199         if (a.floatArray()[0] != 0.0f || a.floatArray()[1] != 1.0f) {
 200             throw new Exception("float[] doesn't match");
 201         }
 202         if (a.doubleArray()[0] != 0.0 || a.doubleArray()[1] != 1.0) {
 203             throw new Exception("double[] doesn't match");
 204         }
 205         if (a.booleanArray()[0] != false || a.booleanArray()[1] != true) {
 206             throw new Exception("boolean[] doesn't match");
 207         }
 208         if (a.shortArray()[0] != (short)0 || a.shortArray()[1] != (short)1) {
 209             throw new Exception("short[] doesn't match");
 210         }
 211         if (a.byteArray()[0] != (byte)0 || a.byteArray()[1] != (byte)1) {
 212             throw new Exception("byte[] doesn't match");
 213         }
 214         if (a.charArray()[0] != '0' || a.charArray()[1] != '1') {
 215             throw new Exception("char[] doesn't match");
 216         }
 217     }
 218 }