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