The pair of annotation types {@code @ContainedBy} and - * {@link java.lang.annotation.ContainerFor @ContainerFor} are used to - * indicate that annotation types are repeatable. Specifically: - * - *
- * An inconsistent pair of {@code @ContainedBy} and - * {@code @ContainerFor} annotations on a repeatable annotation type - * and its containing annotation type (JLS 9.6) will lead to - * compile-time errors and runtime exceptions when using reflection to - * read annotations of a repeatable type. - * - * @see java.lang.annotation.ContainerFor - * @since 1.8 - * @jls 9.6 Annotation Types - * @jls 9.7 Annotations - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.ANNOTATION_TYPE) -public @interface ContainedBy { - /** - * Indicates the containing annotation type for the - * repeatable annotation type. - */ - Class extends Annotation> value(); -} diff --git a/jdk/src/share/classes/java/lang/annotation/ContainerFor.java b/jdk/src/share/classes/java/lang/annotation/ContainerFor.java deleted file mode 100644 index 62f3446e021..00000000000 --- a/jdk/src/share/classes/java/lang/annotation/ContainerFor.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.lang.annotation; - -/** - * The annotation type {@code java.lang.annotation.ContainerFor} is - * used to indicate that the annotation type whose declaration it - * (meta-)annotates is a containing annotation type. The - * value of {@code @ContainerFor} indicates the repeatable - * annotation type for the containing annotation type. - * - *
The pair of annotation types {@link - * java.lang.annotation.ContainedBy @ContainedBy} and - * {@code @ContainerFor} are used to indicate that annotation types - * are repeatable. Specifically: - * - *
- * An inconsistent pair of {@code @ContainedBy} and - * {@code @ContainerFor} annotations on a repeatable annotation type - * and its containing annotation type (JLS 9.6) will lead to - * compile-time errors and runtime exceptions when using reflection to - * read annotations of a repeatable type. - * - * @see java.lang.annotation.ContainedBy - * @since 1.8 - * @jls 9.6 Annotation Types - * @jls 9.7 Annotations - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.ANNOTATION_TYPE) -public @interface ContainerFor { - - /** - * Indicates the repeatable annotation type for the containing - * annotation type. - */ - Class extends Annotation> value(); -} diff --git a/jdk/src/share/classes/java/lang/annotation/InvalidContainerAnnotationError.java b/jdk/src/share/classes/java/lang/annotation/InvalidContainerAnnotationError.java index b24e3034179..37d00a98b40 100644 --- a/jdk/src/share/classes/java/lang/annotation/InvalidContainerAnnotationError.java +++ b/jdk/src/share/classes/java/lang/annotation/InvalidContainerAnnotationError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,10 +27,9 @@ package java.lang.annotation; import java.util.Objects; /** - * Thrown to indicate that an annotation type whose declaration is - * (meta-)annotated with a {@link ContainerFor} annotation is not, in - * fact, the containing annotation type of the type named by {@link - * ContainerFor}. + * Thrown to indicate that an annotation type expected to act as a + * container for another annotation type by virture of an @Repeatable + * annotation, does not act as a container. * * @see java.lang.reflect.AnnotatedElement * @since 1.8 diff --git a/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java b/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java index baaec298a85..9986aef6cf7 100644 --- a/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java +++ b/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java @@ -180,14 +180,6 @@ public class AccessibleObject implements AnnotatedElement { throw new AssertionError("All subclasses should override this method"); } - /** - * @throws NullPointerException {@inheritDoc} - * @since 1.5 - */ - public boolean isAnnotationPresent(Class extends Annotation> annotationClass) { - return getAnnotation(annotationClass) != null; - } - /** * @throws NullPointerException {@inheritDoc} * @since 1.8 diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java new file mode 100644 index 00000000000..e84a3360fdd --- /dev/null +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.reflect; + + +/** + * AnnotatedArrayType represents the use of an array type, whose component + * type may itself represent the annotated use of a type. + * + * @since 1.8 + */ +public interface AnnotatedArrayType extends AnnotatedType { + + /** + * Returns the annotated generic component type of this array type. + * + * @return the annotated generic component type of this array type + */ + AnnotatedType getAnnotatedGenericComponentType(); +} diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java index 58a07350f36..85472ff5b00 100644 --- a/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,24 @@ import java.lang.annotation.Annotation; * arrays returned by accessors for array-valued enum members; it will * have no affect on the arrays returned to other callers. * + *
An annotation A is directly present on an element E if the + * RuntimeVisibleAnnotations or RuntimeVisibleParameterAnnotations attribute + * associated with E either: + *
An annotation A is present on an element E if either: + *
If an annotation returned by a method in this interface contains * (directly or indirectly) a {@link Class}-valued member referring to * a class that is not accessible in this VM, attempting to read the class @@ -50,7 +68,7 @@ import java.lang.annotation.Annotation; * containing annotation type of T will result in an * InvalidContainerAnnotationError. * - *
Finally, Attempting to read a member whose definition has evolved + *
Finally, attempting to read a member whose definition has evolved * incompatibly will result in a {@link * java.lang.annotation.AnnotationTypeMismatchException} or an * {@link java.lang.annotation.IncompleteAnnotationException}. @@ -70,6 +88,12 @@ public interface AnnotatedElement { * is present on this element, else false. This method * is designed primarily for convenient access to marker annotations. * + *
The truth value returned by this method is equivalent to: + * {@code getAnnotation(annotationClass) != null} + * + *
The body of the default method is specified to be the code
+ * above.
+ *
* @param annotationClass the Class object corresponding to the
* annotation type
* @return true if an annotation for the specified annotation
@@ -77,7 +101,9 @@ public interface AnnotatedElement {
* @throws NullPointerException if the given annotation class is null
* @since 1.5
*/
- boolean isAnnotationPresent(Class extends Annotation> annotationClass);
+ default boolean isAnnotationPresent(Class extends Annotation> annotationClass) {
+ return getAnnotation(annotationClass) != null;
+ }
/**
* Returns this element's annotation for the specified type if
@@ -110,12 +136,15 @@ public interface AnnotatedElement {
The Base64 padding character {@code '='} is accepted and + * interpreted as the end of the encoded byte data, but is not + * required. So if the final unit of the encoded byte data only has + * two or three Base64 characters (without the corresponding padding + * character(s) padded), they are decoded as if followed by padding + * character(s). + * *
Instances of {@link Decoder} class are safe for use by * multiple concurrent threads. * @@ -695,7 +704,7 @@ public class Base64 { * using the {@link Base64} encoding scheme. * *
An invocation of this method has exactly the same effect as invoking - * {@code return decode(src.getBytes(StandardCharsets.ISO_8859_1))} + * {@code decode(src.getBytes(StandardCharsets.ISO_8859_1))} * * @param src * the string to decode @@ -856,6 +865,9 @@ public class Base64 { /** * Returns an input stream for decoding {@link Base64} encoded byte stream. * + *
The {@code read} methods of the returned {@code InputStream} will + * throw {@code IOException} when reading bytes that cannot be decoded. + * *
Closing the returned input stream will close the underlying * input stream. * @@ -866,6 +878,7 @@ public class Base64 { * byte stream */ public InputStream wrap(InputStream is) { + Objects.requireNonNull(is); return new DecInputStream(is, isURL ? fromBase64URL : fromBase64, isMIME); } @@ -881,13 +894,16 @@ public class Base64 { int dl = dst.arrayOffset() + dst.limit(); int dp0 = dp; int mark = sp; - boolean padding = false; try { while (sp < sl) { int b = sa[sp++] & 0xff; if ((b = base64[b]) < 0) { if (b == -2) { // padding byte - padding = true; + if (shiftto == 6 && (sp == sl || sa[sp++] != '=') || + shiftto == 18) { + throw new IllegalArgumentException( + "Input byte array has wrong 4-byte ending unit"); + } break; } if (isMIME) // skip if for rfc2045 @@ -913,24 +929,23 @@ public class Base64 { if (shiftto == 6) { if (dl - dp < 1) return dp - dp0; - if (padding && (sp + 1 != sl || sa[sp++] != '=')) - throw new IllegalArgumentException( - "Input buffer has wrong 4-byte ending unit"); da[dp++] = (byte)(bits >> 16); - mark = sp; } else if (shiftto == 0) { if (dl - dp < 2) return dp - dp0; - if (padding && sp != sl) - throw new IllegalArgumentException( - "Input buffer has wrong 4-byte ending unit"); da[dp++] = (byte)(bits >> 16); da[dp++] = (byte)(bits >> 8); - mark = sp; - } else if (padding || shiftto != 18) { + } else if (shiftto == 12) { throw new IllegalArgumentException( "Last unit does not have enough valid bits"); } + while (sp < sl) { + if (isMIME && base64[sa[sp++]] < 0) + continue; + throw new IllegalArgumentException( + "Input byte array has incorrect ending byte at " + sp); + } + mark = sp; return dp - dp0; } finally { src.position(mark); @@ -948,14 +963,16 @@ public class Base64 { int dl = dst.limit(); int dp0 = dp; int mark = sp; - boolean padding = false; - try { while (sp < sl) { int b = src.get(sp++) & 0xff; if ((b = base64[b]) < 0) { if (b == -2) { // padding byte - padding = true; + if (shiftto == 6 && (sp == sl || src.get(sp++) != '=') || + shiftto == 18) { + throw new IllegalArgumentException( + "Input byte array has wrong 4-byte ending unit"); + } break; } if (isMIME) // skip if for rfc2045 @@ -981,24 +998,23 @@ public class Base64 { if (shiftto == 6) { if (dl - dp < 1) return dp - dp0; - if (padding && (sp + 1 != sl || src.get(sp++) != '=')) - throw new IllegalArgumentException( - "Input buffer has wrong 4-byte ending unit"); dst.put(dp++, (byte)(bits >> 16)); - mark = sp; } else if (shiftto == 0) { if (dl - dp < 2) return dp - dp0; - if (padding && sp != sl) - throw new IllegalArgumentException( - "Input buffer has wrong 4-byte ending unit"); dst.put(dp++, (byte)(bits >> 16)); dst.put(dp++, (byte)(bits >> 8)); - mark = sp; - } else if (padding || shiftto != 18) { + } else if (shiftto == 12) { throw new IllegalArgumentException( "Last unit does not have enough valid bits"); } + while (sp < sl) { + if (isMIME && base64[src.get(sp++)] < 0) + continue; + throw new IllegalArgumentException( + "Input byte array has incorrect ending byte at " + sp); + } + mark = sp; return dp - dp0; } finally { src.position(mark); @@ -1012,9 +1028,12 @@ public class Base64 { int len = sl - sp; if (len == 0) return 0; - if (len < 2) + if (len < 2) { + if (isMIME && base64[0] == -1) + return 0; throw new IllegalArgumentException( "Input byte[] should at least have 2 bytes for base64 bytes"); + } if (src[sl - 1] == '=') { paddings++; if (src[sl - 2] == '=') @@ -1043,12 +1062,20 @@ public class Base64 { int dp = 0; int bits = 0; int shiftto = 18; // pos of first byte of 4-byte atom - boolean padding = false; while (sp < sl) { int b = src[sp++] & 0xff; if ((b = base64[b]) < 0) { - if (b == -2) { // padding byte - padding = true; + if (b == -2) { // padding byte '=' + // xx= shiftto==6&&sp==sl missing last = + // xx=y shiftto==6 last is not = + // = shiftto==18 unnecessary padding + // x= shiftto==12 be taken care later + // together with single x, invalid anyway + if (shiftto == 6 && (sp == sl || src[sp++] != '=') || + shiftto == 18) { + throw new IllegalArgumentException( + "Input byte array has wrong 4-byte ending unit"); + } break; } if (isMIME) // skip if for rfc2045 @@ -1068,22 +1095,23 @@ public class Base64 { bits = 0; } } - // reach end of byte arry or hit padding '=' characters. - // if '=' presents, they must be the last one or two. - if (shiftto == 6) { // xx== - if (padding && (sp + 1 != sl || src[sp] != '=')) - throw new IllegalArgumentException( - "Input byte array has wrong 4-byte ending unit"); + // reached end of byte array or hit padding '=' characters. + if (shiftto == 6) { dst[dp++] = (byte)(bits >> 16); - } else if (shiftto == 0) { // xxx= - if (padding && sp != sl) - throw new IllegalArgumentException( - "Input byte array has wrong 4-byte ending unit"); + } else if (shiftto == 0) { dst[dp++] = (byte)(bits >> 16); dst[dp++] = (byte)(bits >> 8); - } else if (padding || shiftto != 18) { - throw new IllegalArgumentException( - "last unit does not have enough bytes"); + } else if (shiftto == 12) { + throw new IllegalArgumentException( + "Last unit does not have enough valid bits"); + } + // anything left is invalid, if is not MIME. + // if MIME, ignore all non-base64 character + while (sp < sl) { + if (isMIME && base64[src[sp++]] < 0) + continue; + throw new IllegalArgumentException( + "Input byte array has incorrect ending byte at " + sp); } return dp; } @@ -1247,8 +1275,22 @@ public class Base64 { int v = is.read(); if (v == -1) { eof = true; - if (nextin != 18) - throw new IOException("Base64 stream has un-decoded dangling byte(s)."); + if (nextin != 18) { + if (nextin == 12) + throw new IOException("Base64 stream has one un-decoded dangling byte."); + // treat ending xx/xxx without padding character legal. + // same logic as v == 'v' below + b[off++] = (byte)(bits >> (16)); + len--; + if (nextin == 0) { // only one padding byte + if (len == 0) { // no enough output space + bits >>= 8; // shift to lowest byte + nextout = 0; + } else { + b[off++] = (byte) (bits >> 8); + } + } + } if (off == oldOff) return -1; else diff --git a/jdk/src/share/classes/java/util/Formatter.java b/jdk/src/share/classes/java/util/Formatter.java index f5f479588c1..03a58004918 100644 --- a/jdk/src/share/classes/java/util/Formatter.java +++ b/jdk/src/share/classes/java/util/Formatter.java @@ -351,7 +351,9 @@ import sun.misc.FormattedFloatingDecimal; *
Multicast group address, port number and ttl have to be chosen on upper + * level and passed to broadcaster constructor. Also it's possible to specify + * source address to broadcast from.
+ * + *JdpBradcaster doesn't perform any validation on a supplied {@code port} and {@code ttl} because + * the allowed values depend on an operating system setup
+ * + */ +public final class JdpBroadcaster { + + private final InetAddress addr; + private final int port; + private final DatagramChannel channel; + + /** + * Create a new broadcaster + * + * @param address - multicast group address + * @param srcAddress - address of interface we should use to broadcast. + * @param port - udp port to use + * @param ttl - packet ttl + * @throws IOException + */ + public JdpBroadcaster(InetAddress address, InetAddress srcAddress, int port, int ttl) + throws IOException, JdpException { + this.addr = address; + this.port = port; + + ProtocolFamily family = (address instanceof Inet6Address) + ? StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; + + channel = DatagramChannel.open(family); + channel.setOption(StandardSocketOptions.SO_REUSEADDR, true); + channel.setOption(StandardSocketOptions.IP_MULTICAST_TTL, ttl); + + // with srcAddress equal to null, this constructor do exactly the same as + // if srcAddress is not passed + if (srcAddress != null) { + // User requests particular interface to bind to + NetworkInterface interf = NetworkInterface.getByInetAddress(srcAddress); + try { + channel.bind(new InetSocketAddress(srcAddress, 0)); + } catch (UnsupportedAddressTypeException ex) { + throw new JdpException("Unable to bind to source address"); + } + channel.setOption(StandardSocketOptions.IP_MULTICAST_IF, interf); + } + } + + /** + * Create a new broadcaster + * + * @param address - multicast group address + * @param port - udp port to use + * @param ttl - packet ttl + * @throws IOException + */ + public JdpBroadcaster(InetAddress address, int port, int ttl) + throws IOException, JdpException { + this(address, null, port, ttl); + } + + /** + * Broadcast pre-built packet + * + * @param packet - instance of JdpPacket + * @throws IOException + */ + public void sendPacket(JdpPacket packet) + throws IOException { + byte[] data = packet.getPacketData(); + // Unlike allocate/put wrap don't need a flip afterward + ByteBuffer b = ByteBuffer.wrap(data); + channel.send(b, new InetSocketAddress(addr, port)); + } + + /** + * Shutdown broadcaster and close underlying socket channel + * + * @throws IOException + */ + public void shutdown() throws IOException { + channel.close(); + } +} diff --git a/jdk/src/share/classes/sun/management/jdp/JdpController.java b/jdk/src/share/classes/sun/management/jdp/JdpController.java new file mode 100644 index 00000000000..d8d0ed46930 --- /dev/null +++ b/jdk/src/share/classes/sun/management/jdp/JdpController.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.management.jdp; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.UUID; + +/** + * JdpController is responsible to create and manage a broadcast loop + * + *Other part of code has no access to broadcast loop and have to use + * provided static methods + * {@link #startDiscoveryService(InetAddress,int,String,String) startDiscoveryService} + * and {@link #stopDiscoveryService() stopDiscoveryService}
+ *{@link #startDiscoveryService(InetAddress,int,String,String) startDiscoveryService} could be called multiple + * times as it stops the running service if it is necessary. Call to {@link #stopDiscoveryService() stopDiscoveryService} + * ignored if service isn't run
+ * + * + * + * + *System properties below could be used to control broadcast loop behavior. + * Property below have to be set explicitly in command line. It's not possible to + * set it in management.config file. Careless changes of these properties could + * lead to security or network issues. + *
null parameters values are filtered out on {@link JdpPacketWriter} level and + * corresponding keys are not placed to packet.
+ */ +public final class JdpController { + + private static class JDPControllerRunner implements Runnable { + + private final JdpJmxPacket packet; + private final JdpBroadcaster bcast; + private final int pause; + private volatile boolean shutdown = false; + + private JDPControllerRunner(JdpBroadcaster bcast, JdpJmxPacket packet, int pause) { + this.bcast = bcast; + this.packet = packet; + this.pause = pause; + } + + @Override + public void run() { + try { + while (!shutdown) { + bcast.sendPacket(packet); + try { + Thread.sleep(this.pause); + } catch (InterruptedException e) { + // pass + } + } + + } catch (IOException e) { + // pass; + } + + // It's not possible to re-use controller, + // nevertheless reset shutdown variable + try { + stop(); + bcast.shutdown(); + } catch (IOException ex) { + // pass - ignore IOException during shutdown + } + } + + public void stop() { + shutdown = true; + } + } + private static JDPControllerRunner controller = null; + + private JdpController(){ + // Don't allow to instantiate this class. + } + + // Utility to handle optional system properties + // Parse an integer from string or return default if provided string is null + private static int getInteger(String val, int dflt, String msg) throws JdpException { + try { + return (val == null) ? dflt : Integer.parseInt(val); + } catch (NumberFormatException ex) { + throw new JdpException(msg); + } + } + + // Parse an inet address from string or return default if provided string is null + private static InetAddress getInetAddress(String val, InetAddress dflt, String msg) throws JdpException { + try { + return (val == null) ? dflt : InetAddress.getByName(val); + } catch (UnknownHostException ex) { + throw new JdpException(msg); + } + } + + /** + * Starts discovery service + * + * @param address - multicast group address + * @param port - udp port to use + * @param instanceName - name of running JVM instance + * @param url - JMX service url + * @throws IOException + */ + public static synchronized void startDiscoveryService(InetAddress address, int port, String instanceName, String url) + throws IOException, JdpException { + + // Limit packet to local subnet by default + int ttl = getInteger( + System.getProperty("com.sun.management.jdp.ttl"), 1, + "Invalid jdp packet ttl"); + + // Broadcast once a 5 seconds by default + int pause = getInteger( + System.getProperty("com.sun.management.jdp.pause"), 5, + "Invalid jdp pause"); + + // Converting seconds to milliseconds + pause = pause * 1000; + + // Allow OS to choose broadcast source + InetAddress sourceAddress = getInetAddress( + System.getProperty("com.sun.management.jdp.source_addr"), null, + "Invalid source address provided"); + + // Generate session id + UUID id = UUID.randomUUID(); + + JdpJmxPacket packet = new JdpJmxPacket(id, url); + + // Don't broadcast whole command line for security reason. + // Strip everything after first space + String javaCommand = System.getProperty("sun.java.command"); + if (javaCommand != null) { + String[] arr = javaCommand.split(" ", 2); + packet.setMainClass(arr[0]); + } + + // Put optional explicit java instance name to packet, if user doesn't specify + // it the key is skipped. PacketWriter is responsible to skip keys having null value. + packet.setInstanceName(instanceName); + + JdpBroadcaster bcast = new JdpBroadcaster(address, sourceAddress, port, ttl); + + // Stop discovery service if it's already running + stopDiscoveryService(); + + controller = new JDPControllerRunner(bcast, packet, pause); + + Thread t = new Thread(controller, "JDP broadcaster"); + t.setDaemon(true); + t.start(); + } + + /** + * Stop running discovery service, + * it's safe to attempt to stop not started service + */ + public static synchronized void stopDiscoveryService() { + if ( controller != null ){ + controller.stop(); + controller = null; + } + } +} diff --git a/jdk/src/share/classes/sun/management/jdp/JdpException.java b/jdk/src/share/classes/sun/management/jdp/JdpException.java new file mode 100644 index 00000000000..03404223e94 --- /dev/null +++ b/jdk/src/share/classes/sun/management/jdp/JdpException.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.management.jdp; + +/** + * An Exception thrown if a JDP implementation encounters a problem. + */ +public final class JdpException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Construct a new JDP exception with a meaningful message + * + * @param msg - message + */ + public JdpException(String msg) { + super(msg); + } +} diff --git a/jdk/src/share/classes/sun/management/jdp/JdpGenericPacket.java b/jdk/src/share/classes/sun/management/jdp/JdpGenericPacket.java new file mode 100644 index 00000000000..8e88b148265 --- /dev/null +++ b/jdk/src/share/classes/sun/management/jdp/JdpGenericPacket.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.management.jdp; + +/** + * JdpGenericPacket responsible to provide fields + * common for all Jdp packets + */ +public abstract class JdpGenericPacket implements JdpPacket { + + /** + * JDP protocol magic. Magic allows a reader to quickly select + * JDP packets from a bunch of broadcast packets addressed to the same port + * and broadcast group. Any packet intended to be parsed by JDP client + * has to start from this magic. + */ + private static final int MAGIC = 0xC0FFEE42; + + /** + * Current version of protocol. Any implementation of this protocol has to + * conform with the packet structure and the flow described in JEP-168 + */ + private static final short PROTOCOL_VERSION = 1; + + /** + * Default do-nothing constructor + */ + protected JdpGenericPacket(){ + // do nothing + } + + + /** + * Validate protocol header magic field + * + * @param magic - value to validate + * @throws JdpException + */ + public static void checkMagic(int magic) + throws JdpException { + if (magic != MAGIC) { + throw new JdpException("Invalid JDP magic header: " + magic); + } + } + + /** + * Validate protocol header version field + * + * @param version - value to validate + * @throws JdpException + */ + public static void checkVersion(short version) + throws JdpException { + + if (version > PROTOCOL_VERSION) { + throw new JdpException("Unsupported protocol version: " + version); + } + } + + /** + * + * @return protocol magic + */ + public static int getMagic() { + return MAGIC; + } + + /** + * + * @return current protocol version + */ + public static short getVersion() { + return PROTOCOL_VERSION; + } +} diff --git a/jdk/src/share/classes/sun/management/jdp/JdpJmxPacket.java b/jdk/src/share/classes/sun/management/jdp/JdpJmxPacket.java new file mode 100644 index 00000000000..7d5ccc2f892 --- /dev/null +++ b/jdk/src/share/classes/sun/management/jdp/JdpJmxPacket.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.management.jdp; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +/** + * A packet to broadcasts JMX URL + * + * Fields: + * + *Each packet have to contain MAGIC and PROTOCOL_VERSION in order to be + * recognized as a valid JDP packet.
+ * + *Default implementation build packet as a set of UTF-8 encoded Key/Value pairs + * are stored as an ordered list of values, and are sent to the server + * in that order.
+ * + *+ * Packet structure: + * + * 4 bytes JDP magic (0xC0FFE42) + * 2 bytes JDP protocol version (01) + * + * 2 bytes size of key + * x bytes key (UTF-8 encoded) + * 2 bytes size of value + * x bytes value (UTF-8 encoded) + * + * repeat as many times as necessary ... + *
+ */ +public interface JdpPacket { + + /** + * This method responsible to assemble packet and return a byte array + * ready to be sent across a Net. + * + * @return assembled packet as an array of bytes + * @throws IOException + */ + public byte[] getPacketData() throws IOException; + +} diff --git a/jdk/src/share/classes/sun/management/jdp/JdpPacketReader.java b/jdk/src/share/classes/sun/management/jdp/JdpPacketReader.java new file mode 100644 index 00000000000..9f3957ab5ce --- /dev/null +++ b/jdk/src/share/classes/sun/management/jdp/JdpPacketReader.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.management.jdp; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * JdpPacketReader responsible for reading a packetThis class gets a byte + * array as it came from a Net, validates it and breaks a part
+ */ +public final class JdpPacketReader { + + private final DataInputStream pkt; + private MapThis class assembles a set of key/value pairs to valid JDP packet, + * ready to be sent across a Net
+ */ +public final class JdpPacketWriter { + + private final ByteArrayOutputStream baos; + private final DataOutputStream pkt; + + /** + * Create a JDP packet, add mandatory magic and version headers + * + * @throws IOException + */ + public JdpPacketWriter() + throws IOException { + baos = new ByteArrayOutputStream(); + pkt = new DataOutputStream(baos); + + pkt.writeInt(JdpGenericPacket.getMagic()); + pkt.writeShort(JdpGenericPacket.getVersion()); + } + + /** + * Put string entry to packet + * + * @param entry - string to put (utf-8 encoded) + * @throws IOException + */ + public void addEntry(String entry) + throws IOException { + pkt.writeShort(entry.length()); + byte[] b = entry.getBytes("UTF-8"); + pkt.write(b); + } + + /** + * Put key/value pair to packet + * + * @param key - key to put (utf-8 encoded) + * @param val - value to put (utf-8 encoded) + * @throws IOException + */ + public void addEntry(String key, String val) + throws IOException { + /* Silently skip key if value is null. + * We don't need to distinguish between key missing + * and key has no value cases + */ + if (val != null) { + addEntry(key); + addEntry(val); + } + } + + /** + * Return assembled packet as a byte array + * + * @return packet bytes + */ + public byte[] getPacketBytes() { + return baos.toByteArray(); + } +} diff --git a/jdk/src/share/classes/sun/management/jdp/package-info.java b/jdk/src/share/classes/sun/management/jdp/package-info.java new file mode 100644 index 00000000000..e21e461214f --- /dev/null +++ b/jdk/src/share/classes/sun/management/jdp/package-info.java @@ -0,0 +1,55 @@ +/** + * Summary + * ------- + * + * Define a lightweight network protocol for discovering running and + * manageable Java processes within a network subnet. + * + * + * Description + * ----------- + * + * The protocol is lightweight multicast based, and works like a beacon, + * broadcasting the JMXService URL needed to connect to the external JMX + * agent if an application is started with appropriate parameters. + * + * The payload is structured like this: + * + * 4 bytes JDP magic (0xC0FFEE42) + * 2 bytes JDP protocol version (1) + * 2 bytes size of the next entry + * x bytes next entry (UTF-8 encoded) + * 2 bytes size of next entry + * ... Rinse and repeat... + * + * The payload will be parsed as even entries being keys, odd entries being + * values. + * + * The standard JDP packet contains four entries: + * + * - `DISCOVERABLE_SESSION_UUID` -- Unique id of the instance; this id changes every time + * the discovery protocol starts and stops + * + * - `MAIN_CLASS` -- The value of the `sun.java.command` property + * + * - `JMX_SERVICE_URL` -- The URL to connect to the JMX agent + * + * - `INSTANCE_NAME` -- The user-provided name of the running instance + * + * The protocol sends packets to 239.255.255.225:7095 by default. + * + * The protocol uses system properties to control it's behaviour: + * - `com.sun.management.jdp.port` -- override default port + * + * - `com.sun.management.jdp.address` -- override default address + * + * - `com.sun.management.jmxremote.autodiscovery` -- whether we should start autodiscovery or + * not. Autodiscovery starts if and only if following conditions are met: (autodiscovery is + * true OR (autodiscovery is not set AND jdp.port is set)) + * + * - `com.sun.management.jdp.ttl` -- set ttl for broadcast packet, default is 1 + * - `com.sun.management.jdp.pause` -- set broadcast interval in seconds default is 5 + * - `com.sun.management.jdp.source_addr` -- an address of interface to use for broadcast + */ + +package sun.management.jdp; diff --git a/jdk/src/share/classes/sun/misc/JavaLangAccess.java b/jdk/src/share/classes/sun/misc/JavaLangAccess.java index 9506194c707..db8d8213179 100644 --- a/jdk/src/share/classes/sun/misc/JavaLangAccess.java +++ b/jdk/src/share/classes/sun/misc/JavaLangAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package sun.misc; import java.lang.annotation.Annotation; +import java.lang.reflect.Executable; import sun.reflect.ConstantPool; import sun.reflect.annotation.AnnotationType; import sun.nio.ch.Interruptible; @@ -46,6 +47,18 @@ public interface JavaLangAccess { */ AnnotationType getAnnotationType(Class> klass); + /** + * Get the array of bytes that is the class-file representation + * of this Class' type annotations. + */ + byte[] getRawClassTypeAnnotations(Class> klass); + + /** + * Get the array of bytes that is the class-file representation + * of this Executable's type annotations. + */ + byte[] getRawExecutableTypeAnnotations(Executable executable); + /** * Returns the elements of an enum class or null if the * Class object does not represent an enum type; @@ -84,9 +97,4 @@ public interface JavaLangAccess { * Returns the ith StackTraceElement for the given throwable. */ StackTraceElement getStackTraceElement(Throwable t, int i); - - /** - * Returns a directly present annotation. - */ - public A getDirectDeclaredAnnotation(Class> klass, Class anno); } diff --git a/jdk/src/share/classes/sun/reflect/LangReflectAccess.java b/jdk/src/share/classes/sun/reflect/LangReflectAccess.java index fba1d318086..3c3b2757410 100644 --- a/jdk/src/share/classes/sun/reflect/LangReflectAccess.java +++ b/jdk/src/share/classes/sun/reflect/LangReflectAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,6 +81,9 @@ public interface LangReflectAccess { public void setConstructorAccessor(Constructor> c, ConstructorAccessor accessor); + /** Gets the byte[] that encodes TypeAnnotations on an Executable. */ + public byte[] getExecutableTypeAnnotationBytes(Executable ex); + /** Gets the "slot" field from a Constructor (used for serialization) */ public int getConstructorSlot(Constructor> c); diff --git a/jdk/src/share/classes/sun/reflect/ReflectionFactory.java b/jdk/src/share/classes/sun/reflect/ReflectionFactory.java index ea5323b8b9a..de97dfc7001 100644 --- a/jdk/src/share/classes/sun/reflect/ReflectionFactory.java +++ b/jdk/src/share/classes/sun/reflect/ReflectionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package sun.reflect; import java.lang.reflect.Field; +import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; @@ -314,6 +315,12 @@ public class ReflectionFactory { return langReflectAccess().copyConstructor(arg); } + /** Gets the byte[] that encodes TypeAnnotations on an executable. + */ + public byte[] getExecutableTypeAnnotationBytes(Executable ex) { + return langReflectAccess().getExecutableTypeAnnotationBytes(ex); + } + //-------------------------------------------------------------------------- // // Routines used by serialization diff --git a/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java b/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java new file mode 100644 index 00000000000..e0524e849dc --- /dev/null +++ b/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.reflect.annotation; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static sun.reflect.annotation.TypeAnnotation.*; + +public class AnnotatedTypeFactory { + /** + * Create an AnnotatedType. + * + * @param type the type this AnnotatedType corresponds to + * @param currentLoc the location this AnnotatedType corresponds to + * @param actualTypeAnnos the type annotations this AnnotatedType has + * @param allOnSameTarget all type annotation on the same TypeAnnotationTarget + * as the AnnotatedType being built + * @param decl the declaration having the type use this AnnotatedType + * corresponds to + */ + public static AnnotatedType buildAnnotatedType(Type type, + LocationInfo currentLoc, + TypeAnnotation[] actualTypeAnnos, + TypeAnnotation[] allOnSameTarget, + AnnotatedElement decl) { + if (type == null) { + return EMPTY_ANNOTATED_TYPE; + } + if (isArray(type)) + return new AnnotatedArrayTypeImpl(type, + currentLoc, + actualTypeAnnos, + allOnSameTarget, + decl); + if (type instanceof Class) { + return new AnnotatedTypeBaseImpl(type, + addNesting(type, currentLoc), + actualTypeAnnos, + allOnSameTarget, + decl); + } else if (type instanceof TypeVariable) { + return new AnnotatedTypeVariableImpl((TypeVariable)type, + currentLoc, + actualTypeAnnos, + allOnSameTarget, + decl); + } else if (type instanceof ParameterizedType) { + return new AnnotatedParameterizedTypeImpl((ParameterizedType)type, + addNesting(type, currentLoc), + actualTypeAnnos, + allOnSameTarget, + decl); + } else if (type instanceof WildcardType) { + return new AnnotatedWildcardTypeImpl((WildcardType) type, + currentLoc, + actualTypeAnnos, + allOnSameTarget, + decl); + } + throw new AssertionError("Unknown instance of Type: " + type + "\nThis should not happen."); + } + + private static LocationInfo addNesting(Type type, LocationInfo addTo) { + if (isArray(type)) + return addTo; + if (type instanceof Class) { + Class> clz = (Class)type; + if (clz.getEnclosingClass() == null) + return addTo; + return addNesting(clz.getEnclosingClass(), addTo.pushInner()); + } else if (type instanceof ParameterizedType) { + ParameterizedType t = (ParameterizedType)type; + if (t.getOwnerType() == null) + return addTo; + return addNesting(t.getOwnerType(), addTo.pushInner()); + } + return addTo; + } + + private static boolean isArray(Type t) { + if (t instanceof Class) { + Class> c = (Class)t; + if (c.isArray()) + return true; + } else if (t instanceof GenericArrayType) { + return true; + } + return false; + } + + static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION, + new TypeAnnotation[0], new TypeAnnotation[0], null); + + private static class AnnotatedTypeBaseImpl implements AnnotatedType { + private final Type type; + private final AnnotatedElement decl; + private final LocationInfo location; + private final TypeAnnotation[] allOnSameTargetTypeAnnotations; + private final Map