8003256: (profiles) Add support for profile identification
authoralanb
Mon, 21 Jan 2013 23:21:15 -0500
changeset 15683 3acd10709925
parent 15682 793a36de151d
child 15684 e5b41bd22ec9
8003256: (profiles) Add support for profile identification Reviewed-by: dholmes, mchung, ksrini
jdk/make/java/version/Makefile
jdk/makefiles/GensrcMisc.gmk
jdk/src/share/classes/sun/misc/Version.java.template
jdk/test/tools/launcher/profiles/VersionCheck.java
--- a/jdk/make/java/version/Makefile	Mon Jan 21 23:20:42 2013 -0500
+++ b/jdk/make/java/version/Makefile	Mon Jan 21 23:21:15 2013 -0500
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1999, 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
@@ -40,6 +40,7 @@
 	    -e 's/@@java_version@@/$(RELEASE)/g' \
 	    -e 's/@@java_runtime_version@@/$(FULL_VERSION)/g' \
 	    -e 's/@@java_runtime_name@@/$(RUNTIME_NAME)/g' \
+	    -e 's/@@java_profile_name@@//g' \
 	$< > $@.temp
 	@$(MV) $@.temp $@
 
--- a/jdk/makefiles/GensrcMisc.gmk	Mon Jan 21 23:20:42 2013 -0500
+++ b/jdk/makefiles/GensrcMisc.gmk	Mon Jan 21 23:21:15 2013 -0500
@@ -23,24 +23,29 @@
 # questions.
 #
 
+include ProfileNames.gmk
+
 ##########################################################################################
 # Install the launcher name, release version string, full version
 # string and the runtime name into the Version.java file.
 # To be printed by java -version
 
-$(JDK_OUTPUTDIR)/gensrc/sun/misc/Version.java: \
-	$(JDK_TOPDIR)/src/share/classes/sun/misc/Version.java.template
+$(JDK_OUTPUTDIR)/gensrc/sun/misc/Version.java \
+$(PROFILE_VERSION_JAVA_TARGETS): \
+		$(JDK_TOPDIR)/src/share/classes/sun/misc/Version.java.template
 	$(MKDIR) -p $(@D)
 	$(RM) $@ $@.tmp
-	$(ECHO) $(LOG_INFO) Generating sun/misc/Version.java
+	$(ECHO) Generating sun/misc/Version.java $(call profile_version_name, $@)
 	$(SED) -e 's/@@launcher_name@@/$(LAUNCHER_NAME)/g' \
 	       -e 's/@@java_version@@/$(RELEASE)/g' \
 	       -e 's/@@java_runtime_version@@/$(FULL_VERSION)/g' \
 	       -e 's/@@java_runtime_name@@/$(RUNTIME_NAME)/g' \
+	       -e 's/@@java_profile_name@@/$(call profile_version_name, $@)/g' \
             $< > $@.tmp
 	$(MV) $@.tmp $@
 
-GENSRC_MISC += $(JDK_OUTPUTDIR)/gensrc/sun/misc/Version.java
+GENSRC_MISC += $(JDK_OUTPUTDIR)/gensrc/sun/misc/Version.java \
+    $(PROFILE_VERSION_JAVA_TARGETS)
 
 ##########################################################################################
 # Version file for jconsole
--- a/jdk/src/share/classes/sun/misc/Version.java.template	Mon Jan 21 23:20:42 2013 -0500
+++ b/jdk/src/share/classes/sun/misc/Version.java.template	Mon Jan 21 23:21:15 2013 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -36,8 +36,11 @@
         "@@java_version@@";
 
     private static final String java_runtime_name =
-	"@@java_runtime_name@@";
- 
+        "@@java_runtime_name@@";
+
+    private static final String java_profile_name =
+        "@@java_profile_name@@";
+
     private static final String java_runtime_version =
         "@@java_runtime_version@@";
 
@@ -49,6 +52,8 @@
         System.setProperty("java.version", java_version);
         System.setProperty("java.runtime.version", java_runtime_version);
         System.setProperty("java.runtime.name", java_runtime_name);
+        if (java_profile_name.length() > 0)
+            System.setProperty("java.runtime.profile", java_profile_name);
     }
 
     private static boolean versionsInitialized = false;
@@ -90,23 +95,28 @@
         boolean isHeadless = false;
 
         /* Report that we're running headless if the property is true */
-	String headless = System.getProperty("java.awt.headless");
-	if ( (headless != null) && (headless.equalsIgnoreCase("true")) ) {
+        String headless = System.getProperty("java.awt.headless");
+        if ( (headless != null) && (headless.equalsIgnoreCase("true")) ) {
             isHeadless = true;
-	} 
+        }
 
         /* First line: platform version. */
         ps.println(launcher_name + " version \"" + java_version + "\"");
 
         /* Second line: runtime version (ie, libraries). */
 
-	ps.print(java_runtime_name + " (build " + java_runtime_version);
+        ps.print(java_runtime_name + " (build " + java_runtime_version);
 
-	if (java_runtime_name.indexOf("Embedded") != -1 && isHeadless) {
-	    // embedded builds report headless state
-	    ps.print(", headless");
-	}
-	ps.println(')');
+        if (java_profile_name.length() > 0) {
+            // profile name
+            ps.print(", profile " + java_profile_name);
+        }
+
+        if (java_runtime_name.indexOf("Embedded") != -1 && isHeadless) {
+            // embedded builds report headless state
+            ps.print(", headless");
+        }
+        ps.println(')');
 
         /* Third line: JVM information. */
         String java_vm_name    = System.getProperty("java.vm.name");
@@ -332,6 +342,67 @@
     private static native boolean getJvmVersionInfo();
     private static native void getJdkVersionInfo();
 
+    // Possible runtime profiles, ordered from small to large
+    private final static String[] PROFILES = { "compact1", "compact2", "compact3" };
+
+    /**
+     * Returns the name of the profile that this runtime implements. The empty
+     * string is returned for the full Java Runtime.
+     */
+    public static String profileName() {
+        return java_profile_name;
+    }
+
+    /**
+     * Indicates if this runtime implements the full Java Runtime.
+     */
+    public static boolean isFullJre() {
+        return java_profile_name.length() == 0;
+    }
+
+    // cached index of this profile's name in PROFILES (1-based)
+    private static int thisRuntimeIndex;
+
+    /**
+     * Indicates if this runtime supports the given profile. Profile names are
+     * case sensitive. 
+     *
+     * @return {@code true} if the given profile is supported
+     */
+    public static boolean supportsProfile(String requiredProfile) {
+        int x = thisRuntimeIndex - 1;
+        if (x < 0) {
+            String profile = profileName();
+            if (profile.length() > 0) {
+                x = 0;
+                while (x < PROFILES.length) {
+                    if (PROFILES[x].equals(profile))
+                        break;
+                    x++;
+                }
+                if (x >= PROFILES.length)
+                    throw new InternalError(profile + " not known to sun.misc.Version");
+
+                // okay if another thread has already set it
+                thisRuntimeIndex = x + 1;
+            }
+            // else we are a full JRE
+        }
+
+        int y = 0;
+        while (y < PROFILES.length) {
+            if (PROFILES[y].equals(requiredProfile))
+                break;
+            y++;
+        }
+        if (y >= PROFILES.length) {
+            // profile not found so caller has requested something that is not defined
+            return false;
+        }
+
+        return x < 0 || x >= y;
+    }
+
 }
 
 // Help Emacs a little because this file doesn't end in .java.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/profiles/VersionCheck.java	Mon Jan 21 23:21:15 2013 -0500
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8003256
+ * @compile -XDignore.symbol.file VersionCheck.java
+ * @run main VersionCheck
+ * @summary Tests that "java -version" includes the name of the profile and that
+ *     it matches the name in the release file
+ */
+
+import java.nio.file.*;
+import java.io.*;
+import java.util.Properties;
+
+public class VersionCheck {
+
+    static final String JAVA_HOME = System.getProperty("java.home");
+    static final String OS_NAME = System.getProperty("os.name");
+    static final String OS_ARCH = System.getProperty("os.arch");
+
+    static final String JAVA_CMD =
+            OS_NAME.startsWith("Windows") ? "java.exe" : "java";
+
+    static final boolean NEED_D64 =
+            OS_NAME.equals("SunOS") &&
+            (OS_ARCH.equals("sparcv9") || OS_ARCH.equals("amd64"));
+
+    /**
+     * Returns {@code true} if the given class is present.
+     */
+    static boolean isPresent(String cn) {
+        try {
+            Class.forName(cn);
+            return true;
+        } catch (ClassNotFoundException ignore) {
+            return false;
+        }
+    }
+
+    /**
+     * Determines the profile by checking whether specific classes are present.
+     * Returns the empty string if this runtime does not appear to be a profile
+     * of Java SE.
+     */
+    static String probeProfile() {
+        if (isPresent("java.awt.Window"))
+            return "";
+        if (isPresent("java.lang.management.ManagementFactory"))
+            return "compact3";
+        if (isPresent("java.sql.DriverManager"))
+            return "compact2";
+        return "compact1";
+    }
+
+    /**
+     * Execs java with the given parameters. The method blocks until the
+     * process terminates. Returns a {@code ByteArrayOutputStream} with any
+     * stdout or stderr from the process.
+     */
+    static ByteArrayOutputStream execJava(String... args)
+        throws IOException
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append(Paths.get(JAVA_HOME, "bin", JAVA_CMD).toString());
+        if (NEED_D64)
+            sb.append(" -d64");
+        for (String arg: args) {
+            sb.append(' ');
+            sb.append(arg);
+        }
+        String[] cmd = sb.toString().split(" ");
+        ProcessBuilder pb = new ProcessBuilder(cmd);
+        pb.redirectErrorStream(true);
+        Process p = pb.start();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        byte[] buf = new byte[1024];
+        int n;
+        do {
+            n = p.getInputStream().read(buf);
+            if (n > 0)
+               baos.write(buf, 0, n);
+        } while (n > 0);
+        try {
+            int exitCode = p.waitFor();
+            if (exitCode != 0)
+                throw new RuntimeException("Exit code: " + exitCode);
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Should not happen");
+        }
+        return baos;
+    }
+
+    public static void main(String[] args) throws IOException {
+        String reported = sun.misc.Version.profileName();
+        String probed = probeProfile();
+        if (!reported.equals(probed)) {
+            throw new RuntimeException("sun.misc.Version reports: " + reported
+               + ", but probing reports: " + probed);
+        }
+
+        String profile = probed;
+        boolean isFullJre = (profile.length() == 0);
+
+        // check that java -version includes "profile compactN"
+        String expected = "profile " + profile;
+        System.out.println("Checking java -version ...");
+        ByteArrayOutputStream baos = execJava("-version");
+        ByteArrayInputStream bain = new ByteArrayInputStream(baos.toByteArray());
+        BufferedReader reader = new BufferedReader(new InputStreamReader(bain));
+        boolean found = false;
+        String line;
+        while ((line = reader.readLine()) != null) {
+            if (line.contains(expected)) {
+                found = true;
+                break;
+            }
+        }
+        if (found && isFullJre)
+           throw new RuntimeException(expected + " found in java -version output");
+        if (!found && !isFullJre)
+            throw new RuntimeException("java -version did not include " + expected);
+
+        // check that the profile name matches the release file
+        System.out.println("Checking release file ...");
+        Properties props = new Properties();
+
+        Path home = Paths.get(JAVA_HOME);
+        if (home.getFileName().toString().equals("jre"))
+            home = home.getParent();
+        Path release = home.resolve("release");
+        try (InputStream in = Files.newInputStream(release)) {
+            props.load(in);
+        }
+        String value = props.getProperty("JAVA_PROFILE");
+        if (isFullJre) {
+            if (value != null)
+                throw new RuntimeException("JAVA_PROFILE should not be present");
+        } else {
+            if (value == null)
+                throw new RuntimeException("JAVA_PROFILE not present in release file");
+            if (!value.equals("\"" + profile + "\""))
+                throw new RuntimeException("Unexpected value of JAVA_PROFILE: " + value);
+        }
+
+        System.out.println("Test passed.");
+    }
+}