/* * Copyright (c) 2008, 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 com.sun.servicetag; import java.io.*; import java.util.Date; import java.text.SimpleDateFormat; import java.text.ParseException; import java.util.TimeZone; import java.util.UUID; import java.lang.reflect.Field; import java.lang.reflect.Method; // Utility class for com.sun.servicetag package class Util { private static boolean verbose = (System.getProperty("servicetag.verbose") != null); private static String jrepath = null; private static final String REGKEY_TAIL = "microsoft\\windows\\currentversion\\app paths\\stclient.exe"; private static final String STCLIENT_TAIL = "sun\\servicetag\\stclient.exe"; private static final String WIN32_STCLIENT = "c:\\Program Files (x86)\\" + STCLIENT_TAIL; // for debugging and tracing static boolean isVerbose() { return verbose; } /** * Gets the pathname of JRE in the running platform * This can be a JDK or JRE. */ static synchronized String getJrePath() { if (jrepath == null) { // Determine the JRE path by checking the existence of // <HOME>/jre/lib and <HOME>/lib. String javaHome = System.getProperty("java.home"); jrepath = javaHome + File.separator + "jre"; File f = new File(jrepath, "lib"); if (!f.exists()) { // java.home usually points to the JRE path jrepath = javaHome; } } return jrepath; } /** * Tests if the running platform is a JDK. */ static boolean isJdk() { // <HOME>/jre exists which implies it's a JDK return getJrePath().endsWith(File.separator + "jre"); } /** * Generates the URN string of "urn:st" namespace */ static String generateURN() { return "urn:st:" + UUID.randomUUID().toString(); } static int getIntValue(String value) { try { return Integer.parseInt(value); } catch (NumberFormatException e) { throw new IllegalArgumentException("\"" + value + "\"" + " expected to be an integer"); } } /** * Formats the Date into a timestamp string in YYYY-MM-dd HH:mm:ss GMT. * @param timestamp Date * @return a string representation of the timestamp * in the YYYY-MM-dd HH:mm:ss GMT format. */ static String formatTimestamp(Date timestamp) { if (timestamp == null) { return "[No timestamp]"; } SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); df.setTimeZone(TimeZone.getTimeZone("GMT")); return df.format(timestamp); } /** * Parses a timestamp string in YYYY-MM-dd HH:mm:ss GMT format. * @param timestamp Timestamp in the YYYY-MM-dd HH:mm:ss GMT format. * @return Date */ static Date parseTimestamp(String timestamp) { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); df.setTimeZone(TimeZone.getTimeZone("GMT")); try { return df.parse(timestamp); } catch (ParseException e) { // should not reach here e.printStackTrace(); return new Date(); } } static String commandOutput(Process p) throws IOException { Reader r = null; Reader err = null; try { r = new InputStreamReader(p.getInputStream()); err = new InputStreamReader(p.getErrorStream()); String output = commandOutput(r); String errorMsg = commandOutput(err); p.waitFor(); return output + errorMsg.trim(); } catch (InterruptedException e) { if (isVerbose()) { e.printStackTrace(); } return e.getMessage(); } finally { try { if (r != null) { r.close(); } } finally { if (err != null) { err.close(); } } } } static String commandOutput(Reader r) throws IOException { StringBuilder sb = new StringBuilder(); int c; while ((c = r.read()) > 0) { if (c != '\r') { sb.append((char) c); } } return sb.toString(); } static int getJdkVersion() { parseVersion(); return jdkVersion; } static int getUpdateVersion() { parseVersion(); return jdkUpdate; } private static int jdkVersion = 0; private static int jdkUpdate = 0; private static synchronized void parseVersion() { if (jdkVersion > 0) { return; } // parse java.runtime.version // valid format of the version string is: // n.n.n[_uu[c]][-<identifer>]-bxx String cs = System.getProperty("java.runtime.version"); if (cs.length() >= 5 && Character.isDigit(cs.charAt(0)) && cs.charAt(1) == '.' && Character.isDigit(cs.charAt(2)) && cs.charAt(3) == '.' && Character.isDigit(cs.charAt(4))) { jdkVersion = Character.digit(cs.charAt(2), 10); cs = cs.substring(5, cs.length()); if (cs.charAt(0) == '_' && cs.length() >= 3 && Character.isDigit(cs.charAt(1)) && Character.isDigit(cs.charAt(2))) { int nextChar = 3; try { String uu = cs.substring(1, 3); jdkUpdate = Integer.valueOf(uu).intValue(); } catch (NumberFormatException e) { // not conforming to the naming convention return; } } } else { throw new InternalError("Invalid java.runtime.version" + cs); } } /** * Returns this java string as a null-terminated byte array */ private static byte[] stringToByteArray(String str) { return (str + "\u0000").getBytes(); } /** * Converts a null-terminated byte array to java string */ private static String byteArrayToString(byte[] array) { return new String(array, 0, array.length -1); } /** * Gets the stclient path using a well known location from * the Windows platform Registry, ensuring the path returned * by the registry is really the one we are looking for, * otherwise it will return null. */ private static File getWindowsStClientFile(boolean wow64) { File out = null; String regKey = (wow64 == true) ? "software\\Wow6432Node\\" + REGKEY_TAIL : "software\\" + REGKEY_TAIL; String keyName = "" ; // use the default key String path = getRegistryKey(regKey, keyName); if (path != null && (new File(path)).exists() && path.toLowerCase().endsWith(STCLIENT_TAIL.toLowerCase())) { out = new File(path); } if (isVerbose()) { System.out.println("stclient=" + out); } return out; } /** * Finds a stclient in 32 and 64 bit environments, first by querying * the windows registry, if not then get the well known paths for * 64bit see http://support.microsoft.com/kb/896459 */ static File getWindowsStClientFile() { File stclient = null; if (System.getProperty("os.arch").equals("x86")) { // try to get the default entry stclient = getWindowsStClientFile(false); if (stclient != null) { return stclient; } } else { // we are on 64-bit system // try the wow64 area stclient = getWindowsStClientFile(true); if (stclient != null) { return stclient; } // try the default hard coded path, maybe wow64 registry is missing stclient = new File(WIN32_STCLIENT); if (stclient.canExecute()) { if (isVerbose()) { System.out.println("stclient(default)=" + stclient); } return stclient; } } if (isVerbose()) { System.out.println("stclient not found"); } return null; } /** * This uses reflection to access a private java windows registry * interface, any changes to that Class must be appropriately adjusted. * Returns a null if unsuccessful. */ private static String getRegistryKey(String regKey, String keyName) { String out = null; try { Class<?> clazz = Class.forName("java.util.prefs.WindowsPreferences"); // Get the registry methods Method winRegOpenKeyM = clazz.getDeclaredMethod("WindowsRegOpenKey", int.class, byte[].class, int.class); winRegOpenKeyM.setAccessible(true); Method winRegCloseKeyM = clazz.getDeclaredMethod("WindowsRegCloseKey", int.class); winRegCloseKeyM.setAccessible(true); Method winRegQueryValueM = clazz.getDeclaredMethod("WindowsRegQueryValueEx", int.class, byte[].class); winRegQueryValueM.setAccessible(true); // Get all the constants we need int HKLM = getValueFromStaticField("HKEY_LOCAL_MACHINE", clazz); int KEY_READ = getValueFromStaticField("KEY_READ", clazz); int ERROR_CODE = getValueFromStaticField("ERROR_CODE", clazz); int NATIVE_HANDLE = getValueFromStaticField("NATIVE_HANDLE", clazz); int ERROR_SUCCESS = getValueFromStaticField("ERROR_SUCCESS", clazz); // Convert keys byte[] reg = stringToByteArray(regKey); byte[] key = stringToByteArray(keyName); // Open the registry int[] result = (int[]) winRegOpenKeyM.invoke(null, HKLM, reg, KEY_READ); if (result[ERROR_CODE] == ERROR_SUCCESS) { byte[] stvalue = (byte[]) winRegQueryValueM.invoke(null, result[NATIVE_HANDLE], key); out = byteArrayToString(stvalue); winRegCloseKeyM.invoke(null, result[NATIVE_HANDLE]); } } catch (Exception ex) { if (isVerbose()) { ex.printStackTrace(); } } return out; } private static int getValueFromStaticField(String fldName, Class<?> klass) throws Exception { Field f = klass.getDeclaredField(fldName); f.setAccessible(true); return f.getInt(null); } }