changeset 651:faa3673d7624

6581243: Service Tag and Product Registration Support in JDK 7 Summary: Include service tag creation and product registration support in JDK Reviewed-by: ksrini
author mchung
date Thu, 02 Oct 2008 16:50:41 -0700
parents b3234ba261fa
children d74db4a9799a
files make/com/sun/Makefile make/com/sun/servicetag/Makefile src/share/classes/com/sun/servicetag/BrowserSupport.java src/share/classes/com/sun/servicetag/Installer.java src/share/classes/com/sun/servicetag/LinuxSystemEnvironment.java src/share/classes/com/sun/servicetag/RegistrationData.java src/share/classes/com/sun/servicetag/RegistrationDocument.java src/share/classes/com/sun/servicetag/Registry.java src/share/classes/com/sun/servicetag/ServiceTag.java src/share/classes/com/sun/servicetag/SolarisServiceTag.java src/share/classes/com/sun/servicetag/SolarisSystemEnvironment.java src/share/classes/com/sun/servicetag/SunConnection.java src/share/classes/com/sun/servicetag/SystemEnvironment.java src/share/classes/com/sun/servicetag/UnauthorizedAccessException.java src/share/classes/com/sun/servicetag/Util.java src/share/classes/com/sun/servicetag/WindowsSystemEnvironment.java src/share/classes/com/sun/servicetag/package.html src/share/classes/com/sun/servicetag/resources/Putback-Notes.txt src/share/classes/com/sun/servicetag/resources/javase_5_swordfish.properties src/share/classes/com/sun/servicetag/resources/javase_6_swordfish.properties src/share/classes/com/sun/servicetag/resources/javase_7_swordfish.properties src/share/classes/com/sun/servicetag/resources/jdk_header.png src/share/classes/com/sun/servicetag/resources/product_registration.xsd src/share/classes/com/sun/servicetag/resources/register.html src/share/classes/com/sun/servicetag/resources/register_ja.html src/share/classes/com/sun/servicetag/resources/register_zh_CN.html test/com/sun/servicetag/DeleteServiceTag.java test/com/sun/servicetag/DuplicateNotFound.java test/com/sun/servicetag/FindServiceTags.java test/com/sun/servicetag/InstanceUrnCheck.java test/com/sun/servicetag/InvalidRegistrationData.java test/com/sun/servicetag/InvalidServiceTag.java test/com/sun/servicetag/JavaServiceTagTest.java test/com/sun/servicetag/JavaServiceTagTest1.java test/com/sun/servicetag/NewRegistrationData.java test/com/sun/servicetag/SvcTagClient.java test/com/sun/servicetag/SystemRegistryTest.java test/com/sun/servicetag/TestLoadFromXML.java test/com/sun/servicetag/UpdateServiceTagTest.java test/com/sun/servicetag/Util.java test/com/sun/servicetag/ValidRegistrationData.java test/com/sun/servicetag/environ.properties test/com/sun/servicetag/missing-environ-field.xml test/com/sun/servicetag/newer-registry-version.xml test/com/sun/servicetag/registration.xml test/com/sun/servicetag/servicetag1.properties test/com/sun/servicetag/servicetag2.properties test/com/sun/servicetag/servicetag3.properties test/com/sun/servicetag/servicetag4.properties test/com/sun/servicetag/servicetag5.properties
diffstat 50 files changed, 7829 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/make/com/sun/Makefile	Mon Sep 29 22:10:00 2008 -0700
+++ b/make/com/sun/Makefile	Thu Oct 02 16:50:41 2008 -0700
@@ -41,7 +41,7 @@
 # Omit mirror since it's built with the apt tool.
 SUBDIRS = $(SCRIPT_SUBDIR) image security crypto/provider jndi jmx \
     java inputmethods org xml rowset net/httpserver net/ssl demo \
-    tools jarsigner tracing
+    tools jarsigner tracing servicetag
 
 all build clean clobber::
 	$(SUBDIRS-loop)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/com/sun/servicetag/Makefile	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,80 @@
+# Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+
+BUILDDIR = ../../..
+PACKAGE = com.sun.servicetag
+PRODUCT = sun
+include $(BUILDDIR)/common/Defs.gmk
+
+#
+# Files to compile
+#
+AUTO_FILES_JAVA_DIRS = com/sun/servicetag
+
+#
+# Rules
+#
+include $(BUILDDIR)/common/Classes.gmk
+
+SERVICETAG_LIBDIR = $(LIBDIR)/servicetag
+SERVICETAG_RESOURCES_DIR = $(CLASSDESTDIR)/com/sun/servicetag/resources
+FILES_copy = $(SERVICETAG_RESOURCES_DIR)/product_registration.xsd \
+             $(SERVICETAG_RESOURCES_DIR)/register.html \
+             $(SERVICETAG_RESOURCES_DIR)/register_ja.html \
+             $(SERVICETAG_RESOURCES_DIR)/register_zh_CN.html \
+             $(SERVICETAG_LIBDIR)/jdk_header.png
+
+# Add all properties files to the FILES_copy list
+SWORDFISH_properties := $(shell \
+       $(CD) $(SHARE_SRC)/classes/com/sun/servicetag/resources; \
+       $(FIND) . -name 'javase_*_swordfish.properties' -print ; \
+    )
+FILES_copy += $(shell \
+   for f in $(SWORDFISH_properties) ; do \
+       echo $(SERVICETAG_RESOURCES_DIR)/$$f ; \
+   done \
+)
+
+
+#
+#OTHER_JAVACFLAGS += -Xlint:unchecked
+
+build: install-servicetag-lib copy-files
+
+copy-files: $(FILES_copy)
+
+$(CLASSBINDIR)/%: $(SHARE_SRC)/classes/%
+	$(install-file)
+
+$(SERVICETAG_LIBDIR)/jdk_header.png: $(SHARE_SRC)/classes/com/sun/servicetag/resources/jdk_header.png
+	$(install-file)
+	$(CHMOD) 444 $@
+
+install-servicetag-lib:
+	@$(RM) -rf $(SERVICETAG_LIBDIR)
+	$(MKDIR) $(SERVICETAG_LIBDIR)
+
+clean clobber::
+	@$(RM) $(FILES_copy)
+
+.PHONY: copy-files
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/BrowserSupport.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.servicetag;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.io.IOException;
+import java.net.URI;
+
+/**
+ * BrowserSupport class.
+ *
+ * The implementation of the com.sun.servicetag API needs to be
+ * compiled with JDK 5 as well since the consumer of this API
+ * may require to support JDK 5 (e.g. NetBeans).
+ *
+ * The Desktop.browse() method can be backported in this class
+ * if needed.  The current implementation only supports JDK 6.
+ */
+class BrowserSupport {
+    private static boolean isBrowseSupported = false;
+    private static Method browseMethod = null;
+    private static Object desktop = null;
+    private static volatile Boolean result = false;
+
+
+    private static void initX() {
+        if  (desktop != null) {
+            return;
+        }
+        boolean supported = false;
+        Method browseM = null;
+        Object desktopObj = null;
+        try {
+            // Determine if java.awt.Desktop is supported
+            Class<?> desktopCls = Class.forName("java.awt.Desktop", true, null);
+            Method getDesktopM = desktopCls.getMethod("getDesktop");
+            browseM = desktopCls.getMethod("browse", URI.class);
+
+            Class<?> actionCls = Class.forName("java.awt.Desktop$Action", true, null);
+            final Method isDesktopSupportedMethod = desktopCls.getMethod("isDesktopSupported");
+            Method isSupportedMethod = desktopCls.getMethod("isSupported", actionCls);
+            Field browseField = actionCls.getField("BROWSE");
+            // isDesktopSupported calls getDefaultToolkit which can block
+            // infinitely, see 6636099 for details, to workaround we call
+            // in a  thread and time it out, noting that the issue is specific
+            // to X11, it does not hurt for Windows.
+            Thread xthread = new Thread() {
+                public void run() {
+                    try {
+                        // support only if Desktop.isDesktopSupported() and
+                        // Desktop.isSupported(Desktop.Action.BROWSE) return true.
+                        result = (Boolean) isDesktopSupportedMethod.invoke(null);
+                    } catch (IllegalAccessException e) {
+                        // should never reach here
+                        InternalError x =
+                            new InternalError("Desktop.getDesktop() method not found");
+                        x.initCause(e);
+                    } catch (InvocationTargetException e) {
+                        // browser not supported
+                        if (Util.isVerbose()) {
+                            e.printStackTrace();
+                        }
+                    }
+                }
+            };
+            // set it to daemon, so that the vm will exit.
+            xthread.setDaemon(true);
+            xthread.start();
+            try {
+                xthread.join(5 * 1000);
+            } catch (InterruptedException ie) {
+                // ignore the exception
+            }
+            if (result.booleanValue()) {
+                desktopObj = getDesktopM.invoke(null);
+                result = (Boolean) isSupportedMethod.invoke(desktopObj, browseField.get(null));
+                supported = result.booleanValue();
+            }
+        } catch (ClassNotFoundException e) {
+            // browser not supported
+            if (Util.isVerbose()) {
+                e.printStackTrace();
+            }
+        } catch (NoSuchMethodException e) {
+            // browser not supported
+            if (Util.isVerbose()) {
+                e.printStackTrace();
+            }
+        } catch (NoSuchFieldException e) {
+            // browser not supported
+            if (Util.isVerbose()) {
+                e.printStackTrace();
+            }
+        } catch (IllegalAccessException e) {
+            // should never reach here
+            InternalError x =
+                    new InternalError("Desktop.getDesktop() method not found");
+            x.initCause(e);
+            throw x;
+        } catch (InvocationTargetException e) {
+            // browser not supported
+            if (Util.isVerbose()) {
+                e.printStackTrace();
+            }
+        }
+        isBrowseSupported = supported;
+        browseMethod = browseM;
+        desktop = desktopObj;
+    }
+
+    static boolean isSupported() {
+        initX();
+        return isBrowseSupported;
+    }
+
+    /**
+     * Launches the default browser to display a {@code URI}.
+     * If the default browser is not able to handle the specified
+     * {@code URI}, the application registered for handling
+     * {@code URIs} of the specified type is invoked. The application
+     * is determined from the protocol and path of the {@code URI}, as
+     * defined by the {@code URI} class.
+     * <p>
+     * This method calls the Desktop.getDesktop().browse() method.
+     * <p>
+     * @param uri the URI to be displayed in the user default browser
+     *
+     * @throws NullPointerException if {@code uri} is {@code null}
+     * @throws UnsupportedOperationException if the current platform
+     * does not support the {@link Desktop.Action#BROWSE} action
+     * @throws IOException if the user default browser is not found,
+     * or it fails to be launched, or the default handler application
+     * failed to be launched
+     * @throws IllegalArgumentException if the necessary permissions
+     * are not available and the URI can not be converted to a {@code URL}
+     */
+    static void browse(URI uri) throws IOException {
+        if (uri == null) {
+            throw new NullPointerException("null uri");
+        }
+        if (!isSupported()) {
+            throw new UnsupportedOperationException("Browse operation is not supported");
+        }
+
+        // Call Desktop.browse() method
+        try {
+            if (Util.isVerbose()) {
+                System.out.println("desktop: " + desktop + ":browsing..." + uri);
+            }
+            browseMethod.invoke(desktop, uri);
+        } catch (IllegalAccessException e) {
+            // should never reach here
+            InternalError x =
+                new InternalError("Desktop.getDesktop() method not found");
+            x.initCause(e);
+                throw x;
+        } catch (InvocationTargetException e) {
+            Throwable x = e.getCause();
+            if (x != null) {
+                if (x instanceof UnsupportedOperationException) {
+                    throw (UnsupportedOperationException) x;
+                } else if (x instanceof IllegalArgumentException) {
+                    throw (IllegalArgumentException) x;
+                } else if (x instanceof IOException) {
+                    throw (IOException) x;
+                } else if (x instanceof SecurityException) {
+                    throw (SecurityException) x;
+                } else {
+                    // ignore
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/Installer.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,965 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.servicetag;
+
+import java.io.*;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.Set;
+import java.util.List;
+import java.util.ArrayList;
+import static com.sun.servicetag.Util.*;
+
+/**
+ * Service Tag Installer for Java SE.
+ */
+public class Installer {
+    // System properties for testing
+    private static String SVCTAG_DIR_PATH =
+        "servicetag.dir.path";
+    private static String SVCTAG_ENABLE_REGISTRATION =
+        "servicetag.registration.enabled";
+    private final static String SUN_VENDOR = "Sun Microsystems";
+    private final static String REGISTRATION_XML = "registration.xml";
+    private final static String SERVICE_TAG_FILE = "servicetag";
+    private final static String REGISTRATION_HTML_NAME = "register";
+
+    private final static Locale[] knownSupportedLocales =
+        new Locale[] { Locale.ENGLISH,
+                       Locale.JAPANESE,
+                       Locale.SIMPLIFIED_CHINESE};
+
+    private final static String javaHome = System.getProperty("java.home");
+    private static File svcTagDir;
+    private static File serviceTagFile;
+    private static File regXmlFile;
+    private static RegistrationData registration;
+    private static boolean supportRegistration;
+    private static String registerHtmlParent;
+    private static Set<Locale> supportedLocales = new HashSet<Locale>();
+    private static Properties swordfishProps = null;
+    private static String[] jreArchs = null;
+    static {
+        String dir = System.getProperty(SVCTAG_DIR_PATH);
+        if (dir == null) {
+            svcTagDir = new File(getJrePath(), "lib" + File.separator + SERVICE_TAG_FILE);
+        } else {
+            svcTagDir = new File(dir);
+        }
+        serviceTagFile = new File(svcTagDir, SERVICE_TAG_FILE);
+        regXmlFile = new File(svcTagDir, REGISTRATION_XML);
+        if (System.getProperty(SVCTAG_ENABLE_REGISTRATION) == null) {
+            supportRegistration = isJdk();
+        } else {
+            supportRegistration = true;
+        }
+    }
+
+    private Installer() {
+    }
+
+    // Implementation of ServiceTag.getJavaServiceTag(String) method
+    static ServiceTag getJavaServiceTag(String source) throws IOException {
+        if (!System.getProperty("java.vendor").startsWith(SUN_VENDOR)) {
+            // Products bundling this implementation may run on
+            // Mac OS which is not a Sun JDK
+            return null;
+        }
+        boolean cleanup = false;
+        try {
+            // Check if we have the swordfish entries for this JRE version
+            if (loadSwordfishEntries() == null) {
+                return null;
+            }
+
+            ServiceTag st = getJavaServiceTag();
+            // Check if the service tag created by this bundle owner
+            if (st != null && st.getSource().equals(source)) {
+                // Install the system service tag if supported
+                // stclient may be installed after the service tag creation
+                if (Registry.isSupported()) {
+                    installSystemServiceTag();
+                }
+                return st;
+            }
+
+            // in case any exception thrown during the cleanup
+            cleanup = true;
+
+            // re-create a new one for this bundle owner
+            // first delete the registration data
+            deleteRegistrationData();
+            cleanup = false;
+
+            // create service tag and generate new register.html pages
+            return createServiceTag(source);
+        } finally {
+            if (cleanup) {
+                if (regXmlFile.exists()) {
+                    regXmlFile.delete();
+                }
+                if (serviceTagFile.exists()) {
+                    serviceTagFile.delete();
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the Java SE registration data located in
+     * the <JRE>/lib/servicetag/registration.xml by default.
+     *
+     * @throws IllegalArgumentException if the registration data
+     *         is of invalid format.
+     */
+    private static synchronized RegistrationData getRegistrationData()
+            throws IOException {
+        if (registration != null) {
+            return registration;
+        }
+        if (regXmlFile.exists()) {
+            BufferedInputStream in = null;
+            try {
+                in = new BufferedInputStream(new FileInputStream(regXmlFile));
+                registration = RegistrationData.loadFromXML(in);
+            } catch (IllegalArgumentException ex) {
+                System.err.println("Error: Bad registration data \"" +
+                                    regXmlFile + "\":" + ex.getMessage());
+                throw ex;
+            } finally {
+                if (in != null) {
+                    in.close();
+                }
+            }
+        } else {
+            registration = new RegistrationData();
+        }
+        return registration;
+    }
+
+    /**
+     * Write the registration data to the registration.xml file.
+     *
+     * The offline registration page has to be regenerated with
+     * the new registration data.
+     *
+     * @throws java.io.IOException
+     */
+    private static synchronized void writeRegistrationXml()
+            throws IOException {
+        if (!svcTagDir.exists()) {
+            // This check is for NetBeans or other products that
+            // bundles this com.sun.servicetag implementation for
+            // pre-6u5 release.
+            if (!svcTagDir.mkdir()) {
+                throw new IOException("Failed to create directory: " + svcTagDir);
+            }
+        }
+
+        // regenerate the new offline registration page
+        deleteRegistrationHtmlPage();
+        getRegistrationHtmlPage();
+
+        BufferedOutputStream out = null;
+        try {
+            out = new BufferedOutputStream(new FileOutputStream(regXmlFile));
+            getRegistrationData().storeToXML(out);
+        } catch (IllegalArgumentException ex) {
+            System.err.println("Error: Bad registration data \"" +
+                                regXmlFile + "\":" + ex.getMessage());
+            throw ex;
+        } finally {
+            if (out != null) {
+                out.close();
+            }
+        }
+    }
+
+    /**
+     * Returns the instance urn(s) stored in the servicetag file
+     * or empty set if file not exists.
+     */
+    private static Set<String> getInstalledURNs() throws IOException {
+        Set<String> urnSet = new HashSet<String>();
+        if (serviceTagFile.exists()) {
+            BufferedReader in = null;
+            try {
+                in = new BufferedReader(new FileReader(serviceTagFile));
+                String urn;
+                while ((urn = in.readLine()) != null) {
+                    urn = urn.trim();
+                    if (urn.length() > 0) {
+                        urnSet.add(urn);
+                    }
+                }
+            } finally {
+                if (in != null) {
+                    in.close();
+                }
+            }
+        }
+        return urnSet;
+    }
+
+    /**
+     * Return the Java SE service tag(s) if it exists.
+     * Typically only one Java SE service tag but it could have two for
+     * Solaris 32-bit and 64-bit on the same install directory.
+     *
+     * @return the service tag(s) for Java SE
+     */
+    private static ServiceTag[] getJavaServiceTagArray() throws IOException {
+        RegistrationData regData = getRegistrationData();
+        Set<ServiceTag> svcTags = regData.getServiceTags();
+        Set<ServiceTag> result = new HashSet<ServiceTag>();
+
+        Properties props = loadSwordfishEntries();
+        String jdkUrn = props.getProperty("servicetag.jdk.urn");
+        String jreUrn = props.getProperty("servicetag.jre.urn");
+        for (ServiceTag st : svcTags) {
+            if (st.getProductURN().equals(jdkUrn) ||
+                st.getProductURN().equals(jreUrn)) {
+                result.add(st);
+            }
+        }
+        return result.toArray(new ServiceTag[0]);
+    }
+
+    /**
+     * Returns the Java SE service tag for this running platform;
+     * or null if not exist.
+     * This method will return the 64-bit service tag if the JDK
+     * supports both 32-bit and 64-bit if already created.
+     */
+    private static ServiceTag getJavaServiceTag() throws IOException {
+        String definedId = getProductDefinedId();
+        for (ServiceTag st : getJavaServiceTagArray()) {
+            if (st.getProductDefinedInstanceID().equals(definedId)) {
+                return st;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Create a service tag for Java SE and install in the system
+     * service tag registry if supported.
+     *
+     * A registration data <JRE>/lib/servicetag/registration.xml
+     * will be created to storeToXML the XML entry for Java SE service tag.
+     * If the system supports service tags, this method will install
+     * the Java SE service tag in the system service tag registry and
+     * its <tt>instance_urn</tt> will be stored to <JRE>/lib/servicetag/servicetag.
+     *
+     * If <JRE>/lib/servicetag/registration.xml exists but is not installed
+     * in the system service tag registry (i.e. servicetag doesn't exist),
+     * this method will install it as described above.
+     *
+     * If the system supports service tag, stclient will be used
+     * to create the Java SE service tag.
+     *
+     * A Solaris 32-bit and 64-bit JDK will be installed in the same
+     * directory but the registration.xml will have 2 service tags.
+     * The servicetag file will also contain 2 instance_urns for that case.
+     */
+    private static ServiceTag createServiceTag(String svcTagSource)
+            throws IOException {
+        // determine if a new service tag is needed to be created
+        ServiceTag newSvcTag = null;
+        if (getJavaServiceTag() == null) {
+            newSvcTag = newServiceTag(svcTagSource);
+        }
+
+        // Add the new service tag in the registration data
+        if (newSvcTag != null) {
+            RegistrationData regData = getRegistrationData();
+
+            // Add the service tag to the registration data in JDK/JRE
+            newSvcTag = regData.addServiceTag(newSvcTag);
+
+            // add if there is a service tag for the OS
+            ServiceTag osTag = SolarisServiceTag.getServiceTag();
+            if (osTag != null && regData.getServiceTag(osTag.getInstanceURN()) == null) {
+                regData.addServiceTag(osTag);
+            }
+            // write to the registration.xml
+            writeRegistrationXml();
+        }
+
+        // Install the system service tag if supported
+        if (Registry.isSupported()) {
+            installSystemServiceTag();
+        }
+        return newSvcTag;
+    }
+
+    private static void installSystemServiceTag() throws IOException {
+        // only install the service tag in the registry if
+        // it has permission to write the servicetag file.
+        if ((!serviceTagFile.exists() && !svcTagDir.canWrite()) ||
+                (serviceTagFile.exists() && !serviceTagFile.canWrite())) {
+            return;
+        }
+
+        Set<String> urns = getInstalledURNs();
+        ServiceTag[] javaSvcTags = getJavaServiceTagArray();
+        if (urns.size() < javaSvcTags.length) {
+            for (ServiceTag st : javaSvcTags) {
+                // Add the service tag in the system service tag registry
+                // if not installed
+                String instanceURN = st.getInstanceURN();
+                if (!urns.contains(instanceURN)) {
+                    Registry.getSystemRegistry().addServiceTag(st);
+                }
+            }
+        }
+        writeInstalledUrns();
+    }
+
+    private static ServiceTag newServiceTag(String svcTagSource) throws IOException {
+        // Load the swoRDFish information for the service tag creation
+        Properties props = loadSwordfishEntries();
+
+        // Determine the product URN and name
+        String productURN;
+        String productName;
+
+        if (isJdk()) {
+            // <HOME>/jre exists which implies it's a JDK
+            productURN = props.getProperty("servicetag.jdk.urn");
+            productName = props.getProperty("servicetag.jdk.name");
+        } else {
+            // Otherwise, it's a JRE
+            productURN = props.getProperty("servicetag.jre.urn");
+            productName = props.getProperty("servicetag.jre.name");
+        }
+
+        return ServiceTag.newInstance(ServiceTag.generateInstanceURN(),
+                                      productName,
+                                      System.getProperty("java.version"),
+                                      productURN,
+                                      props.getProperty("servicetag.parent.name"),
+                                      props.getProperty("servicetag.parent.urn"),
+                                      getProductDefinedId(),
+                                      SUN_VENDOR,
+                                      System.getProperty("os.arch"),
+                                      getZoneName(),
+                                      svcTagSource);
+    }
+
+    /**
+     * Delete the registration data, the offline registration pages and
+     * the service tags in the system service tag registry if installed.
+     *
+     * The registration.xml and servicetag file will be removed.
+     */
+    private static synchronized void deleteRegistrationData()
+            throws IOException {
+        try {
+            // delete the offline registration page
+            deleteRegistrationHtmlPage();
+
+            // Remove the service tag from the system ST registry if exists
+            Set<String> urns = getInstalledURNs();
+            if (urns.size() > 0 && Registry.isSupported()) {
+                for (String u : urns) {
+                    Registry.getSystemRegistry().removeServiceTag(u);
+                }
+            }
+            registration = null;
+        } finally {
+            // Delete the registration.xml and servicetag files if exists
+            if (regXmlFile.exists()) {
+                if (!regXmlFile.delete()) {
+                    throw new IOException("Failed to delete " + regXmlFile);
+                }
+            }
+            if (serviceTagFile.exists()) {
+                if (!serviceTagFile.delete()) {
+                    throw new IOException("Failed to delete " + serviceTagFile);
+                }
+            }
+        }
+    }
+
+    /**
+     * Updates the registration data to contain one single service tag
+     * for the running Java runtime.
+     */
+    private static synchronized void updateRegistrationData(String svcTagSource)
+            throws IOException {
+        RegistrationData regData = getRegistrationData();
+        ServiceTag curSvcTag = newServiceTag(svcTagSource);
+
+        ServiceTag[] javaSvcTags = getJavaServiceTagArray();
+        Set<String> urns = getInstalledURNs();
+        for (ServiceTag st : javaSvcTags) {
+            if (!st.getProductDefinedInstanceID().equals(curSvcTag.getProductDefinedInstanceID())) {
+                String instanceURN = st.getInstanceURN();
+                regData.removeServiceTag(instanceURN);
+
+                // remove it from the system service tag registry if exists
+                if (urns.contains(instanceURN) && Registry.isSupported()) {
+                    Registry.getSystemRegistry().removeServiceTag(instanceURN);
+                }
+            }
+        }
+        writeRegistrationXml();
+        writeInstalledUrns();
+    }
+
+    private static void writeInstalledUrns() throws IOException {
+        // if the Registry is not supported,
+        // remove the servicetag file
+        if (!Registry.isSupported() && serviceTagFile.exists()) {
+            serviceTagFile.delete();
+            return;
+        }
+
+        PrintWriter out = null;
+        try {
+            out = new PrintWriter(serviceTagFile);
+
+            ServiceTag[] javaSvcTags = getJavaServiceTagArray();
+            for (ServiceTag st : javaSvcTags) {
+                // Write the instance_run to the servicetag file
+                String instanceURN = st.getInstanceURN();
+                out.println(instanceURN);
+            }
+        } finally {
+            if (out != null) {
+                out.close();
+            }
+        }
+    }
+
+    /**
+     * Load the values associated with the swoRDFish metadata entries
+     * for Java SE. The swoRDFish metadata entries are different for
+     * different release.
+     *
+     * @param version Version of Java SE
+     */
+    private static synchronized Properties loadSwordfishEntries() throws IOException {
+        if (swordfishProps != null) {
+            return swordfishProps;
+        }
+
+        // The version string for Java SE 6 is 1.6.0
+        // We just need the minor number in the version string
+        int version = Util.getJdkVersion();
+
+        String filename = "/com/sun/servicetag/resources/javase_" +
+                version + "_swordfish.properties";
+        InputStream in = Installer.class.getClass().getResourceAsStream(filename);
+        if (in == null) {
+            return null;
+        }
+        swordfishProps = new Properties();
+        try {
+            swordfishProps.load(in);
+        } finally {
+            in.close();
+        }
+        return swordfishProps;
+    }
+
+    /**
+     * Returns the product defined instance ID for Java SE.
+     * It is a list of comma-separated name/value pairs:
+     *    "id=<full-version>  <arch> [<arch>]*"
+     *    "dir=<java.home system property value>"
+     *
+     * where <full-version> is the full version string of the JRE,
+     *       <arch> is the architecture that the runtime supports
+     *       (i.e. "sparc", "sparcv9", "i386", "amd64" (ISA list))
+     *
+     * For Solaris, it can be dual mode that can support both
+     * 32-bit and 64-bit. the "id" will be set to
+     *     "1.6.0_03-b02 sparc sparcv9"
+     *
+     * The "dir" property is included in the service tag to enable
+     * the Service Tag software to determine if a service tag for
+     * Java SE is invalid and perform appropriate service tag
+     * cleanup if necessary.  See RFE# 6574781 Service Tags Enhancement.
+     *
+     */
+    private static String getProductDefinedId() {
+        StringBuilder definedId = new StringBuilder();
+        definedId.append("id=");
+        definedId.append(System.getProperty("java.runtime.version"));
+
+        String[] archs = getJreArchs();
+        for (String name : archs) {
+            definedId.append(" " + name);
+        }
+
+        String location = ",dir=" + javaHome;
+        if ((definedId.length() + location.length()) < 256) {
+            definedId.append(",dir=");
+            definedId.append(javaHome);
+        } else {
+            // if it exceeds the limit, we will not include the location
+            if (isVerbose()) {
+                System.err.println("Warning: Product defined instance ID exceeds the field limit:");
+            }
+        }
+
+        return definedId.toString();
+    }
+
+    /**
+     * Returns the architectures that the runtime supports
+     *  (i.e. "sparc", "sparcv9", "i386", "amd64" (ISA list))
+     * The directory name where libjava.so is located.
+     *
+     * On Windows, returns the "os.arch" system property value.
+     */
+    private synchronized static String[] getJreArchs() {
+        if (jreArchs != null) {
+            return jreArchs;
+        }
+
+        Set<String> archs = new HashSet<String>();
+
+        String os = System.getProperty("os.name");
+        if (os.equals("SunOS") || os.equals("Linux")) {
+            // Traverse the directories under <JRE>/lib.
+            // If <JRE>/lib/<arch>/libjava.so exists, add <arch>
+            // to the product defined ID
+            File dir = new File(getJrePath() + File.separator + "lib");
+            if (dir.isDirectory()) {
+                String[] children = dir.list();
+                for (String name : children) {
+                    File f = new File(dir, name + File.separator + "libjava.so");
+                    if (f.exists()) {
+                        archs.add(name);
+                    }
+                }
+            }
+        } else {
+            // Windows - append the os.arch
+            archs.add(System.getProperty("os.arch"));
+        }
+        jreArchs = archs.toArray(new String[0]);
+        return jreArchs;
+    }
+
+    /**
+     * Return the zonename if zone is supported; otherwise, return
+     * "global".
+     */
+    private static String getZoneName() throws IOException {
+        String zonename = "global";
+
+        String command = "/usr/bin/zonename";
+        File f = new File(command);
+        // com.sun.servicetag package has to be compiled with JDK 5 as well
+        // JDK 5 doesn't support the File.canExecute() method.
+        // Risk not checking isExecute() for the zonename command is very low.
+        if (f.exists()) {
+            ProcessBuilder pb = new ProcessBuilder(command);
+            Process p = pb.start();
+            String output = commandOutput(p);
+            if (p.exitValue() == 0) {
+                zonename = output.trim();
+            }
+
+        }
+        return zonename;
+    }
+
+    private synchronized static String getRegisterHtmlParent() throws IOException {
+        if (registerHtmlParent == null) {
+            File htmlDir;    // register.html is put under the JDK directory
+            if (getJrePath().endsWith(File.separator + "jre")) {
+                htmlDir = new File(getJrePath(), "..");
+            } else {
+                // j2se non-image build
+                htmlDir = new File(getJrePath());
+            }
+
+            // initialize the supported locales
+            initSupportedLocales(htmlDir);
+
+            // Determine the location of the offline registration page
+            String path = System.getProperty(SVCTAG_DIR_PATH);
+            if (path == null) {
+                // Default is <JDK>/register.html
+                registerHtmlParent = htmlDir.getCanonicalPath();
+            } else {
+                File f = new File(path);
+                registerHtmlParent = f.getCanonicalPath();
+                if (!f.isDirectory()) {
+                    throw new InternalError("Path " + path + " set in \"" +
+                            SVCTAG_DIR_PATH + "\" property is not a directory");
+                }
+            }
+        }
+        return registerHtmlParent;
+    }
+
+    /**
+     * Returns the File object of the offline registration page localized
+     * for the default locale in the JDK directory.
+     */
+    static synchronized File getRegistrationHtmlPage() throws IOException {
+        if (!supportRegistration) {
+            // No register.html page generated if JRE
+            return null;
+        }
+
+        String parent = getRegisterHtmlParent();
+
+        // check if the offline registration page is already generated
+        File f = new File(parent, REGISTRATION_HTML_NAME + ".html");
+        if (!f.exists()) {
+            // Generate the localized version of the offline registration Page
+            generateRegisterHtml(parent);
+        }
+
+        String name = REGISTRATION_HTML_NAME;
+        Locale locale = getDefaultLocale();
+        if (!locale.equals(Locale.ENGLISH) && supportedLocales.contains(locale)) {
+            // if the locale is not English and is supported by JDK
+            // set to the appropriate offline registration page;
+            // otherwise,set to register.html.
+            name = REGISTRATION_HTML_NAME + "_" + locale.toString();
+        }
+        File htmlFile = new File(parent, name + ".html");
+        if (isVerbose()) {
+            System.out.print("Offline registration page: " + htmlFile);
+            System.out.println((htmlFile.exists() ?
+                               "" : " not exist. Use register.html"));
+        }
+        if (htmlFile.exists()) {
+            return htmlFile;
+        } else {
+            return new File(parent,
+                            REGISTRATION_HTML_NAME + ".html");
+        }
+    }
+
+    private static Locale getDefaultLocale() {
+        List<Locale> candidateLocales = getCandidateLocales(Locale.getDefault());
+        for (Locale l : candidateLocales) {
+            if (supportedLocales.contains(l)) {
+                return l;
+            }
+        }
+        return Locale.getDefault();
+    }
+
+    private static List<Locale> getCandidateLocales(Locale locale) {
+        String language = locale.getLanguage();
+        String country = locale.getCountry();
+        String variant = locale.getVariant();
+
+        List<Locale> locales = new ArrayList<Locale>(3);
+        if (variant.length() > 0) {
+            locales.add(locale);
+        }
+        if (country.length() > 0) {
+            locales.add((locales.size() == 0) ?
+                        locale : new Locale(language, country, ""));
+        }
+        if (language.length() > 0) {
+            locales.add((locales.size() == 0) ?
+                        locale : new Locale(language, "", ""));
+        }
+        return locales;
+    }
+
+    // Remove the offline registration pages
+    private static void deleteRegistrationHtmlPage() throws IOException {
+        String parent = getRegisterHtmlParent();
+        if (parent == null) {
+            return;
+        }
+
+        for (Locale locale : supportedLocales) {
+            String name = REGISTRATION_HTML_NAME;
+            if (!locale.equals(Locale.ENGLISH)) {
+                name += "_" + locale.toString();
+            }
+            File f = new File(parent, name + ".html");
+            if (f.exists()) {
+                if (!f.delete()) {
+                    throw new IOException("Failed to delete " + f);
+                }
+            }
+        }
+    }
+
+    private static void initSupportedLocales(File jdkDir) {
+        if (supportedLocales.isEmpty()) {
+            // initialize with the known supported locales
+            for (Locale l : knownSupportedLocales) {
+                supportedLocales.add(l);
+            }
+        }
+
+        // Determine unknown supported locales if any
+        // by finding the localized version of README.html
+        // This prepares if a new locale in JDK is supported in
+        // e.g. in the OpenSource world
+        FilenameFilter ff = new FilenameFilter() {
+            public boolean accept(File dir, String name) {
+                String fname = name.toLowerCase();
+                if (fname.startsWith("readme") && fname.endsWith(".html")) {
+                    return true;
+                }
+                return false;
+            }
+        };
+
+        String[] readmes = jdkDir.list(ff);
+        for (String name : readmes) {
+            String basename = name.substring(0, name.length() - ".html".length());
+            String[] ss = basename.split("_");
+            switch (ss.length) {
+                case 1:
+                    // English version
+                    break;
+                case 2:
+                    supportedLocales.add(new Locale(ss[1]));
+                    break;
+                case 3:
+                    supportedLocales.add(new Locale(ss[1], ss[2]));
+                    break;
+                default:
+                    // ignore
+                    break;
+            }
+        }
+        if (isVerbose()) {
+            System.out.println("Supported locales: ");
+            for (Locale l : supportedLocales) {
+                System.out.println(l);
+            }
+        }
+    }
+
+    private static final String JDK_HEADER_PNG_KEY = "@@JDK_HEADER_PNG@@";
+    private static final String JDK_VERSION_KEY = "@@JDK_VERSION@@";
+    private static final String REGISTRATION_URL_KEY = "@@REGISTRATION_URL@@";
+    private static final String REGISTRATION_PAYLOAD_KEY = "@@REGISTRATION_PAYLOAD@@";
+
+    @SuppressWarnings("unchecked")
+    private static void generateRegisterHtml(String parent) throws IOException {
+        int version = Util.getJdkVersion();
+        int update = Util.getUpdateVersion();
+        String jdkVersion = "Version " + version;
+        if (update > 0) {
+            // product name is not translated
+            jdkVersion += " Update " + update;
+        }
+        RegistrationData regData = getRegistrationData();
+        // Make sure it uses the canonical path before getting the URI.
+        File img = new File(svcTagDir.getCanonicalPath(), "jdk_header.png");
+        String headerImageSrc = img.toURI().toString();
+
+        // Format the registration data in one single line
+        StringBuilder payload = new StringBuilder();
+        String xml = regData.toString().replaceAll("\"", "%22");
+        BufferedReader reader = new BufferedReader(new StringReader(xml));
+        try {
+            String line = null;
+            while ((line = reader.readLine()) != null) {
+                payload.append(line.trim());
+            }
+        } finally {
+            reader.close();
+        }
+
+        String resourceFilename = "/com/sun/servicetag/resources/register";
+        for (Locale locale : supportedLocales) {
+            String name = REGISTRATION_HTML_NAME;
+            String resource = resourceFilename;
+            if (!locale.equals(Locale.ENGLISH)) {
+                name += "_" + locale.toString();
+                resource += "_" + locale.toString();
+            }
+            File f = new File(parent, name + ".html");
+            InputStream in = null;
+            BufferedReader br = null;
+            PrintWriter pw = null;
+            String registerURL = SunConnection.
+                getRegistrationURL(regData.getRegistrationURN(),
+                                   locale,
+                                   String.valueOf(version)).toString();
+            try {
+                in = Installer.class.getClass().getResourceAsStream(resource + ".html");
+                if (in == null) {
+                    // if the resource file is missing
+                    if (isVerbose()) {
+                        System.out.println("Missing resouce file: " + resource + ".html");
+                    }
+                    continue;
+                }
+                if (isVerbose()) {
+                    System.out.println("Generating " + f + " from " + resource + ".html");
+                }
+
+                br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
+                pw = new PrintWriter(f, "UTF-8");
+                String line = null;
+                while ((line = br.readLine()) != null) {
+                    String output = line;
+                    if (line.contains(JDK_VERSION_KEY)) {
+                        output = line.replace(JDK_VERSION_KEY, jdkVersion);
+                    } else if (line.contains(JDK_HEADER_PNG_KEY)) {
+                        output = line.replace(JDK_HEADER_PNG_KEY, headerImageSrc);
+                    } else if (line.contains(REGISTRATION_URL_KEY)) {
+                        output = line.replace(REGISTRATION_URL_KEY, registerURL);
+                    } else if (line.contains(REGISTRATION_PAYLOAD_KEY)) {
+                        output = line.replace(REGISTRATION_PAYLOAD_KEY, payload.toString());
+                    }
+                    pw.println(output);
+                }
+                f.setReadOnly();
+                pw.flush();
+            } finally {
+                if (pw != null) {
+                    pw.close();
+                }
+                if (in != null) {
+                    in.close();
+                }
+                if (br!= null) {
+                    br.close();
+                }
+            }
+        }
+    }
+
+    private static final int MAX_SOURCE_LEN = 63;
+
+    /**
+     * A utility class to create a service tag for Java SE.
+     * <p>
+     * <b>Usage:</b><br>
+     * <blockquote><tt>
+     * &lt;JAVA_HOME&gt;/bin/java com.sun.servicetag.Installer
+     * </tt></blockquote>
+     * <p>
+     */
+    public static void main(String[] args) {
+        String source = "Manual ";
+        String runtimeName = System.getProperty("java.runtime.name");
+        if (runtimeName.startsWith("OpenJDK")) {
+            source = "OpenJDK ";
+        }
+        source += System.getProperty("java.runtime.version");
+        if (source.length() > MAX_SOURCE_LEN) {
+            source = source.substring(0, MAX_SOURCE_LEN);
+        }
+
+        // Parse the options (arguments starting with "-" )
+        boolean delete = false;
+        boolean update = false;
+        boolean register = false;
+        int count = 0;
+        while (count < args.length) {
+            String arg = args[count];
+            if (arg.trim().length() == 0) {
+                // skip empty arguments
+                count++;
+                continue;
+            }
+
+            if (arg.equals("-source")) {
+                source = args[++count];
+            } else if (arg.equals("-delete")) {
+                delete = true;
+            } else if (arg.equals("-register")) {
+                register = true;
+            } else {
+                usage();
+                return;
+            }
+            count++;
+        }
+        try {
+            if (delete) {
+                deleteRegistrationData();
+            } else {
+                ServiceTag[] javaSvcTags = getJavaServiceTagArray();
+                String[] archs = getJreArchs();
+                if (javaSvcTags.length > archs.length) {
+                    // 64-bit has been uninstalled
+                    // so remove the service tag
+                    updateRegistrationData(source);
+                } else {
+                    // create the service tag
+                    createServiceTag(source);
+                }
+            }
+
+            if (register) {
+                // Registration is only supported by JDK
+                // For testing purpose, override with a "servicetag.enable.registration" property
+
+                RegistrationData regData = getRegistrationData();
+                if (supportRegistration && !regData.getServiceTags().isEmpty()) {
+                    SunConnection.register(regData,
+                                           getDefaultLocale(),
+                                           String.valueOf(Util.getJdkVersion()));
+                }
+            }
+            System.exit(0);
+        } catch (IOException e) {
+            System.err.println("I/O Error: " + e.getMessage());
+            if (isVerbose()) {
+                e.printStackTrace();
+            }
+        } catch (IllegalArgumentException ex) {
+            if (isVerbose()) {
+                ex.printStackTrace();
+            }
+        } catch (Exception e) {
+            System.err.println("Error: " + e.getMessage());
+            if (isVerbose()) {
+                e.printStackTrace();
+            }
+        }
+        System.exit(1);
+    }
+
+    private static void usage() {
+        System.out.println("Usage:");
+        System.out.print("    " + Installer.class.getName());
+        System.out.println(" [-delete|-source <source>|-register]");
+        System.out.println("       to create a service tag for the Java platform");
+        System.out.println("");
+        System.out.println("Internal Options:");
+        System.out.println("    -source: to specify the source of the service tag to be created");
+        System.out.println("    -delete: to delete the service tag ");
+        System.out.println("    -register: to register the JDK");
+        System.out.println("    -help:   to print this help message");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/LinuxSystemEnvironment.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.servicetag;
+
+// This class is a copy of the com.sun.scn.servicetags.LinuxSystemEnvironment
+// class from the Sun Connection source.
+//
+// The Service Tags team maintains the latest version of the implementation
+// for system environment data collection.  JDK will include a copy of
+// the most recent released version for a JDK release. We rename
+// the package to com.sun.servicetag so that the Sun Connection
+// product always uses the latest version from the com.sun.scn.servicetags
+// package. JDK and users of the com.sun.servicetag API
+// (e.g. NetBeans and SunStudio) will use the version in JDK.
+//
+// So we keep this class in src/share/classes instead of src/<os>/classes.
+
+import java.io.*;
+
+/**
+ * Linux implementation of the SystemEnvironment class.
+ */
+class LinuxSystemEnvironment extends SystemEnvironment {
+    LinuxSystemEnvironment() {
+        setHostId(getLinuxHostId());
+        setSystemModel(getCommandOutput("/bin/uname", "-i"));
+        setSystemManufacturer(getLinuxSystemManufacturer());
+        setCpuManufacturer(getLinuxCpuManufacturer());
+        setSerialNumber(getLinuxSN());
+    }
+    private String dmiInfo = null;
+
+    private static final int SN  = 1;
+    private static final int SYS = 2;
+    private static final int CPU = 3;
+
+    private String getLinuxHostId() {
+        String output = getCommandOutput("/usr/bin/hostid");
+        // trim off the leading 0x
+        if (output.startsWith("0x")) {
+            output = output.substring(2);
+        }
+        return output;
+    }
+
+    /**
+     * Tries to obtain and return the cpu manufacturer.
+     * @return The cpu manufacturer (an empty string if not found or an error occurred)
+     */
+    private String getLinuxCpuManufacturer() {
+        String tmp = getLinuxPSNInfo(CPU);
+        if (tmp.length() > 0) {
+            return tmp;
+        }
+
+        String contents = getFileContent("/proc/cpuinfo");
+        for (String line : contents.split("\n")) {
+            if (line.contains("vendor_id")) {
+                String[] ss = line.split(":", 2);
+                if (ss.length > 1) {
+                    return ss[1].trim();
+                }
+            }
+        }
+
+        // returns an empty string if it can't be found or an error happened
+        return getLinuxDMIInfo("dmi type 4", "manufacturer");
+    }
+
+
+    /**
+     * Tries to obtain and return the system manufacturer.
+     * @return The system manufacturer (an empty string if not found or an error occurred)
+     */
+    private String getLinuxSystemManufacturer() {
+        String tmp = getLinuxPSNInfo(SYS);
+        if (tmp.length() > 0) {
+            return tmp;
+        }
+
+        // returns an empty string if it can't be found or an error happened
+        return getLinuxDMIInfo("dmi type 1", "manufacturer");
+    }
+
+    /**
+     * Tries to obtain and return the serial number of the system.
+     * @return The serial number (an empty string if not found or an error occurred)
+     */
+    private String getLinuxSN() {
+        String tmp = getLinuxPSNInfo(SN);
+        if (tmp.length() > 0) {
+            return tmp;
+        }
+
+        // returns an empty string if it can't be found or an error happened
+        return getLinuxDMIInfo("dmi type 1", "serial number");
+    }
+
+    private String getLinuxPSNInfo(int target) {
+        // try to read from the psn file if it exists
+        String contents = getFileContent("/var/run/psn");
+        String[] ss = contents.split("\n");
+        if (target <= ss.length) {
+            return ss[target-1];
+        }
+
+        // default case is to return ""
+        return "";
+    }
+
+    // reads from dmidecode with the given type and target
+    // returns an empty string if nothing was found or an error occurred
+    //
+    // Sample output segment:
+    // Handle 0x0001
+    //         DMI type 1, 25 bytes.
+    //         System Information
+    //                 Manufacturer: System manufacturer
+    //                 Product Name: System Product Name
+    //                 Version: System Version
+    //                 Serial Number: System Serial Number
+    //                 UUID: 3091D719-B25B-D911-959D-6D1B12C7686E
+    //                 Wake-up Type: Power Switch
+
+    private synchronized String getLinuxDMIInfo(String dmiType, String target) {
+        // only try to get dmidecode information once, after that, we can
+        // reuse the output
+        if (dmiInfo == null) {
+            Thread dmidecodeThread = new Thread() {
+                public void run() {
+                    dmiInfo = getCommandOutput("/usr/sbin/dmidecode");
+                }
+            };
+            dmidecodeThread.start();
+
+            try {
+                dmidecodeThread.join(2000);
+                if (dmidecodeThread.isAlive()) {
+                    dmidecodeThread.interrupt();
+                    dmiInfo = "";
+                }
+            } catch (InterruptedException ie) {
+                dmidecodeThread.interrupt();
+            }
+        }
+
+        if (dmiInfo.length() == 0) {
+            return "";
+        }
+        boolean dmiFlag = false;
+        for (String s : dmiInfo.split("\n")) {
+            String line = s.toLowerCase();
+            if (dmiFlag) {
+                if (line.contains(target)) {
+                    String key = target + ":";
+                    int indx = line.indexOf(key) + key.length();
+                    if (line.contains(key) && indx < line.length()) {
+                        return line.substring(indx).trim();
+                    }
+                    String[] ss = line.split(":");
+                    return ss[ss.length-1];
+                }
+            } else if (line.contains(dmiType)) {
+                dmiFlag = true;
+            }
+        }
+        return "";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/RegistrationData.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,475 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.servicetag;
+
+import java.io.*;
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import static com.sun.servicetag.RegistrationDocument.*;
+
+/**
+ * A {@code RegistrationData} object is a container of one or more
+ * {@link #getServiceTags service tags} that identify the
+ * components for product registration.
+ * Each {@code RegistrationData} object has a {@link #getRegistrationURN
+ * uniform resource name} (URN) as its identifier.
+ * <a name="EnvMap"></a>
+ * It also has an <i>environment map</i> with
+ * the following elements:
+ * <blockquote>
+ *       <table border=0>
+ *       <tr>
+ *          <td><tt>hostname</tt></td>
+ *          <td>Hostname of the system</td>
+ *          <td>e.g. woody</td>
+ *       </tr>
+ *       <tr>
+ *          <td><tt>hostId</tt></td>
+ *          <td>Host ID of the system</td>
+ *          <td>e.g. 83abc1ab</td>
+ *       </tr>
+ *       <tr>
+ *          <td><tt>osName</tt></td>
+ *          <td>Operating system name</td>
+ *          <td> e.g. SunOS</td>
+ *       </tr>
+ *       <tr>
+ *          <td><tt>osVersion</tt></td>
+ *          <td>Operating system version</td>
+ *          <td> e.g. 5.10</td>
+ *       </tr>
+ *       <tr>
+ *          <td><tt>osArchitecture</tt></td>
+ *          <td>Operating system architecture</td>
+ *          <td> e.g. sparc</td>
+ *       </tr>
+ *       <tr>
+ *          <td><tt>systemModel</tt></td>
+ *          <td>System model</td>
+ *          <td> e.g. SUNW,Sun-Fire-V440</td>
+ *       </tr>
+ *       <tr>
+ *          <td><tt>systemManufacturer</tt></td>
+ *          <td>System manufacturer</td>
+ *          <td> e.g. Sun Microsystems</td>
+ *       </tr>
+ *       <tr>
+ *          <td><tt>cpuManufacturer</tt></td>
+ *          <td>CPU manufacturer</td>
+ *          <td> e.g. Sun Microsystems</td>
+ *       </tr>
+ *       <tr>
+ *          <td><tt>serialNumber</tt></td>
+ *          <td>System serial number</td>
+ *          <td> e.g. BEL078932</td>
+ *       </tr>
+ *       </table>
+ *  </blockquote>
+ * The <tt>hostname</tt> and <tt>osName</tt> element must have a non-empty value.
+ * If an element is not available on a system and their value will be
+ * empty.
+ * <p>
+ * <a name="XMLSchema">
+ * <b>Registration XML Schema</b></a>
+ * <p>
+ * A {@code RegistrationData} object can be {@link #loadFromXML loaded} from
+ * and {@link #storeToXML stored} into an XML file in the format described
+ * by the
+ * <a href="https://sn-tools.central.sun.com/twiki/pub/ServiceTags/RegistrationRelayService/product_registration.xsd">
+ * registration data schema</a>.  The registration data schema is defined by the
+ * Service Tags Technology.
+ * <p>
+ * Typically the registration data is constructed at installation time
+ * and stored in an XML file for later service tag lookup or registration.
+ *
+ * <p>
+ * <b>Example Usage</b>
+ * <p>
+ * The examples below show how the {@code RegistrationData} can be
+ * used for product registration.
+ * Exception handling is not shown in these examples for clarity.
+ * <ol>
+ * <li>This example shows how the JDK creates a JDK service tag, installs it
+ * in the system service tag registry and adds it to the registration data.
+ * <br>
+ * <blockquote><pre>
+ *   // create a service tag object with an instance_urn
+ *   ServiceTag st = ServiceTag.newInstance(ServiceTag.generateInstanceURN(),
+ *                                          ....);
+ *   // Adds to the system service tag registry if supported
+ *   if (Registry.isSupported()) {
+ *       Registry.getSystemRegistry().addServiceTag(st);
+ *   }
+ *
+ *   // add to the registration data
+ *   RegistrationData registration  = new RegistrationData();
+ *   registration.addServiceTag(st);
+ * </pre></blockquote>
+ * </li>
+ * <li>At this point, the registration data is ready to
+ * send to Sun Connection for registration. This example shows how to register
+ * the JDK via the <i>Registration Relay Service</i>.
+ * <p>
+ * There are several registration services for Sun Connection. For example,
+ * the <a href="https://sn-tools.central.sun.com/twiki/bin/view/ServiceTags/RegistrationRelayService">
+ * Registration Relay Service</a> is a web application interface that
+ * processes the registration data payload sent via HTTP post
+ * and hosts the registration user interface for a specified
+ * registration URL.  Refer to the
+ * Registration Relay Service Specification for details.
+ * <p>
+ * <blockquote><pre>
+ *   // Open the connection to the URL of the registration service
+ *   HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
+ *   con.setDoInput(true);
+ *   con.setDoOutput(true);
+ *   con.setUseCaches(false);
+ *   con.setAllowUserInteraction(false);
+ *   con.setRequestMethod("POST");
+ *   con.setRequestProperty("Content-Type", "text/xml;charset=\"utf-8\"");
+ *   con.connect();
+ *
+ *   // send the registration data to the registration service
+ *   OutputStream out = con.getOutputStream();
+ *   registration.storeToXML(out);
+ *   out.close();
+ * </pre></blockquote>
+ * </li>
+ * <li>This example shows how to store the registration data in an XML file.
+ *     for later service tag lookup or registration.
+ * <br>
+ * <blockquote><pre>
+ *   BufferedOutputStream out = new BufferedOutputStream(
+ *       new FileOutputStream(""&lt;JAVA_HOME&gt;/lib/servicetag/registration.xml"));
+ *   registration.storeToXML(out);
+ *   out.close();
+ * </pre></blockquote>
+ * </li>
+ * <li>This example shows how to install service tags that are in the
+ * registration data in the system service tag registry when determined
+ * to be available.  The system service tag registry might not have existed
+ * when the registration data was constructed.
+ * <br>
+ * <blockquote><pre>
+ *   if (Registry.isSupported()) {
+ *       Set&lt;ServiceTag&gt; svctags = registration.getServiceTags();
+ *       for (ServiceTag st : svctags) {
+ *           Registry.getSystemRegistry().addServiceTag(st);
+ *       }
+ *   }
+ * </pre></blockquote>
+ * </li>
+ * </ol>
+ *
+ * @see <a href="https://sunconnection.sun.com/inventory">Sun Connection Inventory Channel</a>
+ */
+public class RegistrationData {
+    private final Map<String, String> environment = initEnvironment();
+    private final Map<String, ServiceTag> svcTagMap =
+        new LinkedHashMap<String, ServiceTag>();
+    private final String urn;
+
+    /**
+     * Creates a {@code RegistrationData} object with a generated
+     * {@link #getRegistrationURN registration URN}.
+     * The following keys in the {@link #getEnvironmentMap environment map}
+     * will be initialized for the configuration of the
+     * running system:
+     * <blockquote>
+     * <tt>hostname</tt>, <tt>osName</tt>,  <tt>osVersion</tt> and
+     * <tt>osArchitecture</tt>
+     * </blockquote>
+     * and the value of other keys may be empty.
+     */
+    public RegistrationData() {
+        this(Util.generateURN());
+        SystemEnvironment sysEnv = SystemEnvironment.getSystemEnvironment();
+        setEnvironment(ST_NODE_HOSTNAME, sysEnv.getHostname());
+        setEnvironment(ST_NODE_HOST_ID, sysEnv.getHostId());
+        setEnvironment(ST_NODE_OS_NAME, sysEnv.getOsName());
+        setEnvironment(ST_NODE_OS_VERSION, sysEnv.getOsVersion());
+        setEnvironment(ST_NODE_OS_ARCH, sysEnv.getOsArchitecture());
+        setEnvironment(ST_NODE_SYSTEM_MODEL, sysEnv.getSystemModel());
+        setEnvironment(ST_NODE_SYSTEM_MANUFACTURER, sysEnv.getSystemManufacturer());
+        setEnvironment(ST_NODE_CPU_MANUFACTURER, sysEnv.getCpuManufacturer());
+        setEnvironment(ST_NODE_SERIAL_NUMBER, sysEnv.getSerialNumber());
+    }
+
+    // package private
+    RegistrationData(String urn) {
+        this.urn = urn;
+    }
+
+    private Map<String, String> initEnvironment() {
+        Map<String, String> map = new LinkedHashMap<String, String>();
+        map.put(ST_NODE_HOSTNAME, "");
+        map.put(ST_NODE_HOST_ID, "");
+        map.put(ST_NODE_OS_NAME, "");
+        map.put(ST_NODE_OS_VERSION, "");
+        map.put(ST_NODE_OS_ARCH, "");
+        map.put(ST_NODE_SYSTEM_MODEL, "");
+        map.put(ST_NODE_SYSTEM_MANUFACTURER, "");
+        map.put(ST_NODE_CPU_MANUFACTURER, "");
+        map.put(ST_NODE_SERIAL_NUMBER, "");
+        return map;
+    }
+
+    /**
+     * Returns the uniform resource name of this registration data
+     * in this format:
+     * <tt>urn:st:&lt;32-char {@link java.util.UUID uuid}&gt;</tt>
+     *
+     * @return the URN of this registration data.
+     */
+    public String getRegistrationURN() {
+        return urn;
+    }
+
+    /**
+     * Returns a map containing the environment information for this
+     * registration data.  See the set of <a href="#EnvMap">keys</a>
+     * in the environment map. Subsequent update to the environment
+     * map via the {@link #setEnvironment setEnvironment} method will not be reflected
+     * in the returned map.
+     *
+     * @return an environment map for this registration data.
+     */
+    public Map<String, String> getEnvironmentMap() {
+        return new LinkedHashMap<String,String>(environment);
+    }
+
+    /**
+     * Sets an element of the specified {@code name} in the environment map
+     * with the given {@code value}.
+     *
+     * @throws IllegalArgumentException if {@code name} is not a valid key
+     * in the environment map, or {@code value} is not valid.
+     */
+    public void setEnvironment(String name, String value) {
+        if (name == null) {
+            throw new NullPointerException("name is null");
+        }
+        if (value == null) {
+            throw new NullPointerException("value is null");
+        }
+        if (environment.containsKey(name)) {
+            if (name.equals(ST_NODE_HOSTNAME) || name.equals(ST_NODE_OS_NAME)) {
+                if (value.length() == 0) {
+                    throw new IllegalArgumentException("\"" +
+                        name + "\" requires non-empty value.");
+                }
+            }
+            environment.put(name, value);
+        } else {
+            throw new IllegalArgumentException("\"" +
+                 name + "\" is not an environment element.");
+        }
+    }
+
+    /**
+     * Returns all service tags in this registration data.
+     *
+     * @return  a {@link Set Set} of the service tags
+     * in this registration data.
+     */
+    public Set<ServiceTag> getServiceTags() {
+        return new HashSet<ServiceTag>(svcTagMap.values());
+    }
+
+    /**
+     * Adds a service tag to this registration data.
+     * If the given service tag has an empty <tt>instance_urn</tt>,
+     * this method will generate a URN and place it in the copy
+     * of the service tag in this registration data.
+     * This method will return the {@code ServiceTag} object
+     * added to this registration data.
+     *
+     * @param st {@code ServiceTag} object to be added.
+     * @return a {@code ServiceTag} object added to this registration data.
+     *
+     * @throws IllegalArgumentException if
+     *   a service tag of the same {@link ServiceTag#getInstanceURN
+     *   <tt>instance_urn</tt>} already exists in the registry.
+     */
+    public synchronized ServiceTag addServiceTag(ServiceTag st) {
+        ServiceTag svcTag = ServiceTag.newInstanceWithUrnTimestamp(st);
+
+        String instanceURN = svcTag.getInstanceURN();
+        if (svcTagMap.containsKey(instanceURN)) {
+            throw new IllegalArgumentException("Instance_urn = " + instanceURN +
+                    " already exists in the registration data.");
+        } else {
+            svcTagMap.put(instanceURN, svcTag);
+        }
+        return svcTag;
+    }
+
+    /**
+     * Returns a service tag of the given <tt>instance_urn</tt> in this registration
+     * data.
+     *
+     * @param instanceURN the <tt>instance_urn</tt> of the service tag
+     * @return the {@code ServiceTag} object of the given  <tt>instance_urn</tt>
+     *         if exists; otherwise return {@code null}.
+     */
+    public synchronized ServiceTag getServiceTag(String instanceURN) {
+        if (instanceURN == null) {
+            throw new NullPointerException("instanceURN is null");
+        }
+        return svcTagMap.get(instanceURN);
+    }
+
+    /**
+     * Removes a service tag of the given <tt>instance_urn</tt> from this
+     * registration data.
+     *
+     * @param instanceURN the <tt>instance_urn</tt> of
+     * the service tag to be removed.
+     *
+     * @return the removed {@code ServiceTag} object;
+     * or {@code null} if the service tag does not exist in this
+     * registration data.
+     */
+    public synchronized ServiceTag removeServiceTag(String instanceURN) {
+        if (instanceURN == null) {
+            throw new NullPointerException("instanceURN is null");
+        }
+
+        ServiceTag svcTag = null;
+        if (svcTagMap.containsKey(instanceURN)) {
+            svcTag = svcTagMap.remove(instanceURN);
+        }
+        return svcTag;
+    }
+
+     /**
+     * Updates the <tt>product_defined_instance_id</tt> in the service tag
+     * of the given <tt>instance_urn</tt> in this registration data.
+     *
+     * @param instanceURN the <tt>instance_urn</tt> of the service tag to be updated.
+     * @param productDefinedInstanceID the value of the
+     * <tt>product_defined_instance_id</tt> to be set.
+     *
+     * @return the updated {@code ServiceTag} object;
+     * or {@code null} if the service tag does not exist in this
+     * registration data.
+     */
+    public synchronized ServiceTag updateServiceTag(String instanceURN,
+                                                    String productDefinedInstanceID) {
+        ServiceTag svcTag = getServiceTag(instanceURN);
+        if (svcTag == null) {
+            return null;
+        }
+
+        svcTag = ServiceTag.newInstanceWithUrnTimestamp(svcTag);
+        // update the product defined instance ID field
+        svcTag.setProductDefinedInstanceID(productDefinedInstanceID);
+        svcTagMap.put(instanceURN, svcTag);
+        return svcTag;
+    }
+
+    /**
+     * Reads the registration data from the XML document on the
+     * specified input stream.  The XML document must be
+     * in the format described by the <a href="#XMLSchema">
+     * registration data schema</a>.
+     * The specified stream is closed after this method returns.
+     *
+     * @param in the input stream from which to read the XML document.
+     * @return a {@code RegistrationData} object read from the input
+     * stream.
+     *
+     * @throws IllegalArgumentException if the input stream
+     * contains an invalid registration data.
+     *
+     * @throws IOException if an error occurred when reading from the input stream.
+     */
+    public static RegistrationData loadFromXML(InputStream in) throws IOException {
+        try {
+            return RegistrationDocument.load(in);
+        } finally {
+            in.close();
+        }
+    }
+
+    /**
+     * Writes the registration data to the specified output stream
+     * in the format described by the <a href="#XMLSchema">
+     * registration data schema</a> with "UTF-8" encoding.
+     * The specified stream remains open after this method returns.
+     *
+     * @param os the output stream on which to write the XML document.
+     *
+     * @throws IOException if an error occurred when writing to the output stream.
+     */
+    public void storeToXML(OutputStream os) throws IOException {
+        RegistrationDocument.store(os, this);
+        os.flush();
+    }
+
+    /**
+     * Returns a newly allocated byte array containing the registration
+     * data in XML format.
+     *
+     * @return a newly allocated byte array containing the registration
+     * data in XML format.
+     */
+    public byte[] toXML() {
+        try {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            storeToXML(out);
+            return out.toByteArray();
+        } catch (IOException e) {
+            // should not reach here
+            return new byte[0];
+        }
+    }
+
+    /**
+     * Returns a string representation of this registration data in XML
+     * format.
+     *
+     * @return a string representation of this registration data in XML
+     *         format.
+     */
+    @Override
+    public String toString() {
+        try {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            storeToXML(out);
+            return out.toString("UTF-8");
+        } catch (IOException e) {
+            // should not reach here
+            return "Error creating the return string.";
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/RegistrationDocument.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.servicetag;
+
+import java.io.*;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+import org.xml.sax.InputSource;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
+
+// For write operation
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+/**
+ * XML Support Class for Product Registration.
+ */
+class RegistrationDocument {
+
+    private static final String REGISTRATION_DATA_SCHEMA =
+            "/com/sun/servicetag/resources/product_registration.xsd";
+    private static final String REGISTRATION_DATA_VERSION = "1.0";
+    private static final String SERVICE_TAG_VERSION = "1.0";
+    final static String ST_NODE_REGISTRATION_DATA = "registration_data";
+    final static String ST_ATTR_REGISTRATION_VERSION = "version";
+    final static String ST_NODE_ENVIRONMENT = "environment";
+    final static String ST_NODE_HOSTNAME = "hostname";
+    final static String ST_NODE_HOST_ID = "hostId";
+    final static String ST_NODE_OS_NAME = "osName";
+    final static String ST_NODE_OS_VERSION = "osVersion";
+    final static String ST_NODE_OS_ARCH = "osArchitecture";
+    final static String ST_NODE_SYSTEM_MODEL = "systemModel";
+    final static String ST_NODE_SYSTEM_MANUFACTURER = "systemManufacturer";
+    final static String ST_NODE_CPU_MANUFACTURER = "cpuManufacturer";
+    final static String ST_NODE_SERIAL_NUMBER = "serialNumber";
+    final static String ST_NODE_REGISTRY = "registry";
+    final static String ST_ATTR_REGISTRY_URN = "urn";
+    final static String ST_ATTR_REGISTRY_VERSION = "version";
+    final static String ST_NODE_SERVICE_TAG = "service_tag";
+    final static String ST_NODE_INSTANCE_URN = "instance_urn";
+    final static String ST_NODE_PRODUCT_NAME = "product_name";
+    final static String ST_NODE_PRODUCT_VERSION = "product_version";
+    final static String ST_NODE_PRODUCT_URN = "product_urn";
+    final static String ST_NODE_PRODUCT_PARENT_URN = "product_parent_urn";
+    final static String ST_NODE_PRODUCT_PARENT = "product_parent";
+    final static String ST_NODE_PRODUCT_DEFINED_INST_ID = "product_defined_inst_id";
+    final static String ST_NODE_PRODUCT_VENDOR = "product_vendor";
+    final static String ST_NODE_PLATFORM_ARCH = "platform_arch";
+    final static String ST_NODE_TIMESTAMP = "timestamp";
+    final static String ST_NODE_CONTAINER = "container";
+    final static String ST_NODE_SOURCE = "source";
+    final static String ST_NODE_INSTALLER_UID = "installer_uid";
+
+    static RegistrationData load(InputStream in) throws IOException {
+        Document document = initializeDocument(in);
+
+        // Gets the registration URN
+        Element root = getRegistrationDataRoot(document);
+        Element registryRoot =
+                getSingletonElementFromRoot(root, ST_NODE_REGISTRY);
+        String urn = registryRoot.getAttribute(ST_ATTR_REGISTRY_URN);
+
+        // Construct a new RegistrationData object from the DOM tree
+        // Initialize the environment map and service tags
+        RegistrationData regData = new RegistrationData(urn);
+        addServiceTags(registryRoot, regData);
+
+        Element envRoot = getSingletonElementFromRoot(root, ST_NODE_ENVIRONMENT);
+        buildEnvironmentMap(envRoot, regData);
+        return regData;
+    }
+
+    static void store(OutputStream os, RegistrationData registration)
+            throws IOException {
+        // create a new document with the root node
+        Document document = initializeDocument();
+
+        // create the nodes for the environment map and the service tags
+        // in the registration data
+        addEnvironmentNodes(document,
+                            registration.getEnvironmentMap());
+        addServiceTagRegistry(document,
+                              registration.getRegistrationURN(),
+                              registration.getServiceTags());
+        transform(document, os);
+    }
+
+    // initialize a document from an input stream
+    private static Document initializeDocument(InputStream in) throws IOException {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        try {
+            // XML schema for validation
+            SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+            URL xsdUrl = RegistrationDocument.class.getResource(REGISTRATION_DATA_SCHEMA);
+            Schema schema = sf.newSchema(xsdUrl);
+            Validator validator = schema.newValidator();
+
+            DocumentBuilder builder = factory.newDocumentBuilder();
+            Document doc = builder.parse(new InputSource(in));
+            validator.validate(new DOMSource(doc));
+            return doc;
+        } catch (SAXException sxe) {
+            IllegalArgumentException e = new IllegalArgumentException("Error generated in parsing");
+            e.initCause(sxe);
+            throw e;
+        } catch (ParserConfigurationException pce) {
+            // Parser with specific options can't be built
+            // should not reach here
+            InternalError x = new InternalError("Error in creating the new document");
+            x.initCause(pce);
+            throw x;
+        }
+    }
+
+    // initialize a new document for the registration data
+    private static Document initializeDocument() throws IOException {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        try {
+            DocumentBuilder builder = factory.newDocumentBuilder();
+            Document doc = builder.newDocument();
+
+            // initialize the document with the registration_data root
+            Element root = doc.createElement(ST_NODE_REGISTRATION_DATA);
+            doc.appendChild(root);
+            root.setAttribute(ST_ATTR_REGISTRATION_VERSION, REGISTRATION_DATA_VERSION);
+
+            return doc;
+        } catch (ParserConfigurationException pce) {
+            // Parser with specified options can't be built
+            // should not reach here
+            InternalError x = new InternalError("Error in creating the new document");
+            x.initCause(pce);
+            throw x;
+        }
+    }
+
+    // Transform the current DOM tree with the given output stream.
+    private static void transform(Document document, OutputStream os) {
+        try {
+            // Use a Transformer for output
+            TransformerFactory tFactory = TransformerFactory.newInstance();
+            tFactory.setAttribute("indent-number", new Integer(3));
+
+            Transformer transformer = tFactory.newTransformer();
+
+            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+            transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
+            transformer.transform(new DOMSource(document),
+                new StreamResult(new BufferedWriter(new OutputStreamWriter(os, "UTF-8"))));
+        } catch (UnsupportedEncodingException ue) {
+            // Should not reach here
+            InternalError x = new InternalError("Error generated during transformation");
+            x.initCause(ue);
+            throw x;
+        } catch (TransformerConfigurationException tce) {
+            // Error generated by the parser
+            // Should not reach here
+            InternalError x = new InternalError("Error in creating the new document");
+            x.initCause(tce);
+            throw x;
+        } catch (TransformerException te) {
+            // Error generated by the transformer
+            InternalError x = new InternalError("Error generated during transformation");
+            x.initCause(te);
+            throw x;
+        }
+    }
+
+    private static void addServiceTagRegistry(Document document,
+                                              String registryURN,
+                                              Set<ServiceTag> svcTags) {
+        // add service tag registry node and its attributes
+        Element reg = document.createElement(ST_NODE_REGISTRY);
+        reg.setAttribute(ST_ATTR_REGISTRY_URN, registryURN);
+        reg.setAttribute(ST_ATTR_REGISTRY_VERSION, SERVICE_TAG_VERSION);
+
+        Element root = getRegistrationDataRoot(document);
+        root.appendChild(reg);
+
+        // adds the elements for the service tags
+        for (ServiceTag st : svcTags) {
+            addServiceTagElement(document, reg, st);
+        }
+    }
+
+    private static void addServiceTagElement(Document document,
+                                             Element registryRoot,
+                                             ServiceTag st) {
+        Element svcTag = document.createElement(ST_NODE_SERVICE_TAG);
+        registryRoot.appendChild(svcTag);
+        addChildElement(document, svcTag,
+                        ST_NODE_INSTANCE_URN, st.getInstanceURN());
+        addChildElement(document, svcTag,
+                        ST_NODE_PRODUCT_NAME, st.getProductName());
+        addChildElement(document, svcTag,
+                        ST_NODE_PRODUCT_VERSION, st.getProductVersion());
+        addChildElement(document, svcTag,
+                        ST_NODE_PRODUCT_URN, st.getProductURN());
+        addChildElement(document, svcTag,
+                        ST_NODE_PRODUCT_PARENT_URN, st.getProductParentURN());
+        addChildElement(document, svcTag,
+                        ST_NODE_PRODUCT_PARENT, st.getProductParent());
+        addChildElement(document, svcTag,
+                        ST_NODE_PRODUCT_DEFINED_INST_ID,
+                        st.getProductDefinedInstanceID());
+        addChildElement(document, svcTag,
+                        ST_NODE_PRODUCT_VENDOR, st.getProductVendor());
+        addChildElement(document, svcTag,
+                        ST_NODE_PLATFORM_ARCH, st.getPlatformArch());
+        addChildElement(document, svcTag,
+                        ST_NODE_TIMESTAMP, Util.formatTimestamp(st.getTimestamp()));
+        addChildElement(document, svcTag,
+                        ST_NODE_CONTAINER, st.getContainer());
+        addChildElement(document, svcTag,
+                        ST_NODE_SOURCE, st.getSource());
+        addChildElement(document, svcTag,
+                        ST_NODE_INSTALLER_UID,
+                        String.valueOf(st.getInstallerUID()));
+    }
+
+    private static void addChildElement(Document document, Element root,
+                                        String element, String text) {
+        Element node = document.createElement(element);
+        node.appendChild(document.createTextNode(text));
+        root.appendChild(node);
+    }
+
+    // Constructs service tags from the document
+    private static void addServiceTags(Element registryRoot,
+                                       RegistrationData registration) {
+        NodeList children = registryRoot.getElementsByTagName(ST_NODE_SERVICE_TAG);
+        int length = (children == null ? 0 : children.getLength());
+        for (int i = 0; i < length; i++) {
+            Element svcTagElement = (Element) children.item(i);
+            ServiceTag st = getServiceTag(svcTagElement);
+            registration.addServiceTag(st);
+        }
+    }
+
+    // build environment map from the document
+    private static void buildEnvironmentMap(Element envRoot,
+                                         RegistrationData registration) {
+        registration.setEnvironment(ST_NODE_HOSTNAME, getTextValue(envRoot, ST_NODE_HOSTNAME));
+        registration.setEnvironment(ST_NODE_HOST_ID, getTextValue(envRoot, ST_NODE_HOST_ID));
+        registration.setEnvironment(ST_NODE_OS_NAME, getTextValue(envRoot, ST_NODE_OS_NAME));
+        registration.setEnvironment(ST_NODE_OS_VERSION, getTextValue(envRoot, ST_NODE_OS_VERSION));
+        registration.setEnvironment(ST_NODE_OS_ARCH, getTextValue(envRoot, ST_NODE_OS_ARCH));
+        registration.setEnvironment(ST_NODE_SYSTEM_MODEL, getTextValue(envRoot, ST_NODE_SYSTEM_MODEL));
+        registration.setEnvironment(ST_NODE_SYSTEM_MANUFACTURER, getTextValue(envRoot, ST_NODE_SYSTEM_MANUFACTURER));
+        registration.setEnvironment(ST_NODE_CPU_MANUFACTURER, getTextValue(envRoot, ST_NODE_CPU_MANUFACTURER));
+        registration.setEnvironment(ST_NODE_SERIAL_NUMBER, getTextValue(envRoot, ST_NODE_SERIAL_NUMBER));
+    }
+
+    // add the nodes representing the environment map in the document
+    private static void addEnvironmentNodes(Document document,
+                                            Map<String, String> envMap) {
+        Element root = getRegistrationDataRoot(document);
+        Element env = document.createElement(ST_NODE_ENVIRONMENT);
+        root.appendChild(env);
+        Set<Map.Entry<String, String>> keys = envMap.entrySet();
+        for (Map.Entry<String, String> entry : keys) {
+            addChildElement(document, env, entry.getKey(), entry.getValue());
+        }
+    }
+
+    private static Element getRegistrationDataRoot(Document doc) {
+        Element root = doc.getDocumentElement();
+        if (!root.getNodeName().equals(ST_NODE_REGISTRATION_DATA)) {
+            throw new IllegalArgumentException("Not a " +
+                    ST_NODE_REGISTRATION_DATA +
+                    " node \"" + root.getNodeName() + "\"");
+        }
+        return root;
+    }
+
+    private static Element getSingletonElementFromRoot(Element root, String name) {
+        NodeList children = root.getElementsByTagName(name);
+        int length = (children == null ? 0 : children.getLength());
+        if (length != 1) {
+            throw new IllegalArgumentException("Invalid number of " + name +
+                    " nodes = " + length);
+        }
+        Element e = (Element) children.item(0);
+        if (!e.getNodeName().equals(name)) {
+            throw new IllegalArgumentException("Not a  " + name +
+                    " node \"" + e.getNodeName() + "\"");
+        }
+        return e;
+    }
+
+    // Constructs one ServiceTag instance from a service tag element root
+    private static ServiceTag getServiceTag(Element svcTagElement) {
+        return new ServiceTag(
+            getTextValue(svcTagElement, ST_NODE_INSTANCE_URN),
+            getTextValue(svcTagElement, ST_NODE_PRODUCT_NAME),
+            getTextValue(svcTagElement, ST_NODE_PRODUCT_VERSION),
+            getTextValue(svcTagElement, ST_NODE_PRODUCT_URN),
+            getTextValue(svcTagElement, ST_NODE_PRODUCT_PARENT),
+            getTextValue(svcTagElement, ST_NODE_PRODUCT_PARENT_URN),
+            getTextValue(svcTagElement, ST_NODE_PRODUCT_DEFINED_INST_ID),
+            getTextValue(svcTagElement, ST_NODE_PRODUCT_VENDOR),
+            getTextValue(svcTagElement, ST_NODE_PLATFORM_ARCH),
+            getTextValue(svcTagElement, ST_NODE_CONTAINER),
+            getTextValue(svcTagElement, ST_NODE_SOURCE),
+            Util.getIntValue(getTextValue(svcTagElement, ST_NODE_INSTALLER_UID)),
+            Util.parseTimestamp(getTextValue(svcTagElement, ST_NODE_TIMESTAMP))
+        );
+    }
+
+    private static String getTextValue(Element e, String tagName) {
+        String value = "";
+        NodeList nl = e.getElementsByTagName(tagName);
+        if (nl != null && nl.getLength() > 0) {
+            Element el = (Element) nl.item(0);
+            Node node = el.getFirstChild();
+            if (node != null) {
+                value = node.getNodeValue();
+            }
+        }
+        return value;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/Registry.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,552 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.servicetag;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import static com.sun.servicetag.Util.*;
+import static com.sun.servicetag.RegistrationDocument.*;
+
+/**
+ * A service tag registry is a XML-based registry containing
+ * the list of {@link ServiceTag service tags} installed in the system.
+ * The {@code Registry} class provides interfaces
+ * to add, remove, update, and get a service tag from a service tag
+ * registry.
+ * This {@code Registry} class may not be supported
+ * on all systems. The {@link #isSupported} method
+ * can be called to determine if it is supported.
+ * <p>
+ * A registry may implement restrictions to only allow certain users
+ * to {@link #updateServiceTag update} and
+ * to {@link #removeServiceTag remove} a service tag record. Typically,
+ * only the owner of the service tag, the owner of the registry
+ * and superuser are authorized to update or remove a service tag in
+ * the registry.
+ *
+ * @see <a href="https://sn-tools.central.sun.com/twiki/bin/view/ServiceTags/ServiceTagDevGuideHelper">
+ * Service Tag User Guide</a>
+ */
+public class Registry {
+
+    private static final String STCLIENT_SOLARIS = "/usr/bin/stclient";
+    private static final String STCLIENT_LINUX = "/opt/sun/servicetag/bin/stclient";
+    // stclient exit value (see sthelper.h)
+    private static final int ST_ERR_NOT_AUTH = 245;
+    private static final int ST_ERR_REC_NOT_FOUND = 225;
+
+    // The stclient output has to be an exported interface
+    private static final String INSTANCE_URN_DESC = "Product instance URN=";
+    private static boolean initialized = false;
+    private static boolean supportsHelperClass = true; // default
+    private static File stclient = null;
+    private static String stclientPath = null;
+    private static Registry registry = new Registry();
+
+    // System properties for testing
+    private static String SVCTAG_STCLIENT_CMD = "servicetag.stclient.cmd";
+    private static String SVCTAG_STHELPER_SUPPORTED = "servicetag.sthelper.supported";
+
+    private Registry() {
+    }
+
+    private synchronized static String getSTclient() {
+        if (!initialized) {
+            // the system property always overrides the default setting
+            if (System.getProperty(SVCTAG_STHELPER_SUPPORTED) != null) {
+                supportsHelperClass = Boolean.getBoolean(SVCTAG_STHELPER_SUPPORTED);
+            }
+
+            // This is only used for testing
+            stclientPath = System.getProperty(SVCTAG_STCLIENT_CMD);
+            if (stclientPath != null) {
+                return stclientPath;
+            }
+
+            // Initialization to determine the platform's stclient pathname
+            String os = System.getProperty("os.name");
+            if (os.equals("SunOS")) {
+                stclient = new File(STCLIENT_SOLARIS);
+            } else if (os.equals("Linux")) {
+                stclient = new File(STCLIENT_LINUX);
+            } else if (os.startsWith("Windows")) {
+                stclient = getWindowsStClientFile();
+            } else {
+                if (isVerbose()) {
+                    System.out.println("Running on non-Sun JDK");
+                }
+            }
+            initialized = true;
+        }
+
+        // com.sun.servicetag package has to be compiled with JDK 5 as well
+        // JDK 5 doesn't support the File.canExecute() method.
+        // Risk not checking isExecute() for the stclient command is very low.
+
+        if (stclientPath == null && stclient != null && stclient.exists()) {
+            stclientPath = stclient.getAbsolutePath();
+        }
+        return stclientPath;
+    }
+
+    /**
+     * Returns the system service tag registry. The {@code Registry} class
+     * may not be supported on some platforms; use the {@link #isSupported}
+     * method to determine if it is supported.
+     *
+     * @return the {@code Registry} object for the system service tag registry.
+     *
+     * @throws UnsupportedOperationException if the {@code Registry} class is
+     * not supported.
+     */
+    public static Registry getSystemRegistry() {
+        if (isSupported()) {
+            return registry;
+        } else {
+            throw new UnsupportedOperationException("Registry class is not supported");
+        }
+    }
+
+    /**
+     * Returns {@code true} if the {@code Registry} class is supported on this system.
+     *
+     * @return {@code true} if the {@code Registry} class is supported;
+     * otherwise, return {@code false}.
+     */
+    public static boolean isSupported() {
+        return (getSTclient() != null && supportsHelperClass);
+    }
+
+    private static List<String> getCommandList() {
+        // Set up the arguments to call stclient
+        List<String> command = new ArrayList<String>();
+        if (System.getProperty(SVCTAG_STCLIENT_CMD) != null) {
+            // This is for jtreg testing use. This will be set to something
+            // like:
+            // $JAVA_HOME/bin/java -cp $TEST_DIR \
+            //    -Dstclient.registry.path=$TEST_DIR/registry.xml \
+            //    SvcTagClient
+            //
+            // On Windows, the JAVA_HOME and TEST_DIR path could contain
+            // space e.g. c:\Program Files\Java\jdk1.6.0_05\bin\java.
+            // The SVCTAG_STCLIENT_CMD must be set with a list of
+            // space-separated parameters.  If a parameter contains spaces,
+            // it must be quoted with '"'.
+
+            String cmd = getSTclient();
+            int len = cmd.length();
+            int i = 0;
+            while (i < len) {
+                char separator = ' ';
+                if (cmd.charAt(i) == '"') {
+                    separator = '"';
+                    i++;
+                }
+                // look for the separator or matched the closing '"'
+                int j;
+                for (j = i+1; j < len; j++) {
+                    if (cmd.charAt(j) == separator) {
+                        break;
+                    }
+                }
+
+                if (i == j-1) {
+                    // add an empty parameter
+                    command.add("\"\"");
+                } else {
+                    // double quotes and space are not included
+                    command.add(cmd.substring(i,j));
+                }
+
+                // skip spaces
+                for (i = j+1; i < len; i++) {
+                    if (!Character.isSpaceChar(cmd.charAt(i))) {
+                        break;
+                    }
+                }
+            }
+            if (isVerbose()) {
+                System.out.println("Command list:");
+                for (String s : command) {
+                    System.out.println(s);
+                }
+            }
+        } else {
+            command.add(getSTclient());
+        }
+        return command;
+    }
+
+    // Returns null if the service tag record not found;
+    // or throw UnauthorizedAccessException or IOException
+    // based on the exitValue.
+    private static ServiceTag checkReturnError(int exitValue,
+                                               String output,
+                                               ServiceTag st) throws IOException {
+        switch (exitValue) {
+            case ST_ERR_REC_NOT_FOUND:
+                return null;
+            case ST_ERR_NOT_AUTH:
+                if (st != null) {
+                    throw new UnauthorizedAccessException(
+                        "Not authorized to access " + st.getInstanceURN() +
+                        " installer_uid=" + st.getInstallerUID());
+                } else  {
+                    throw new UnauthorizedAccessException(
+                        "Not authorized:" + output);
+                }
+            default:
+                throw new IOException("stclient exits with error" +
+                     " (" + exitValue + ")\n" + output);
+        }
+    }
+
+    /**
+     * Adds a service tag to this registry.
+     * If the given service tag has an empty <tt>instance_urn</tt>,
+     * this helper class will generate a URN and place it in the
+     * copy of the service tag in this registry.
+     * This method will return the {@code ServiceTag} representing
+     * the service tag entry to this registry.
+     *
+     * @param st {@code ServiceTag} object
+     * @return a {@code ServiceTag} object representing the service tag
+     *         entry to this registry.
+     *
+     * @throws IllegalArgumentException if a service tag of the same
+     * <tt>instance_urn</tt> already exists in this registry.
+     *
+     * @throws java.io.IOException if an I/O error occurs in this operation.
+     */
+    public ServiceTag addServiceTag(ServiceTag st) throws IOException {
+        List<String> command = getCommandList();
+        command.add("-a");
+        if (st.getInstanceURN().length() > 0) {
+            ServiceTag sysSvcTag = getServiceTag(st.getInstanceURN());
+            if (sysSvcTag != null) {
+                throw new IllegalArgumentException("Instance_urn = " +
+                    st.getInstanceURN() + " already exists");
+            }
+            command.add("-i");
+            command.add(st.getInstanceURN());
+        }
+        command.add("-p");
+        command.add(st.getProductName());
+        command.add("-e");
+        command.add(st.getProductVersion());
+        command.add("-t");
+        command.add(st.getProductURN());
+        if (st.getProductParentURN().length() > 0) {
+            command.add("-F");
+            command.add(st.getProductParentURN());
+        }
+        command.add("-P");
+        command.add(st.getProductParent());
+        if (st.getProductDefinedInstanceID().length() > 0) {
+            command.add("-I");
+            command.add(st.getProductDefinedInstanceID());
+        }
+        command.add("-m");
+        command.add(st.getProductVendor());
+        command.add("-A");
+        command.add(st.getPlatformArch());
+        command.add("-z");
+        command.add(st.getContainer());
+        command.add("-S");
+        command.add(st.getSource());
+
+        BufferedReader in = null;
+        try {
+            ProcessBuilder pb = new ProcessBuilder(command);
+            Process p = pb.start();
+            String output = commandOutput(p);
+            if (isVerbose()) {
+                System.out.println("Output from stclient -a command:");
+                System.out.println(output);
+            }
+            String urn = "";
+            if (p.exitValue() == 0) {
+                // Obtain the instance urn from the stclient output
+                in = new BufferedReader(new StringReader(output));
+                String line = null;
+                while ((line = in.readLine()) != null) {
+                    line = line.trim();
+                    if (line.startsWith(INSTANCE_URN_DESC)) {
+                        urn = line.substring(INSTANCE_URN_DESC.length());
+                        break;
+                    }
+                }
+                if (urn.length() == 0) {
+                    throw new IOException("Error in creating service tag:\n" +
+                        output);
+                }
+                return getServiceTag(urn);
+            } else {
+                return checkReturnError(p.exitValue(), output, st);
+            }
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+    }
+
+    /**
+     * Removes a service tag of the given <tt>instance_urn</tt> from this
+     * registry.
+     *
+     * @param instanceURN the <tt>instance_urn</tt> of the service tag
+     *        to be removed.
+     *
+     * @return the {@code ServiceTag} object removed from this registry;
+     * or {@code null} if the service tag does not exist in this registry.
+     *
+     * @throws UnauthorizedAccessException if the user is not authorized to
+     * remove the service tag of the given <tt>instance_urn</tt>
+     * from this registry.
+     *
+     * @throws java.io.IOException if an I/O error occurs in this operation.
+     */
+    public ServiceTag removeServiceTag(String instanceURN) throws IOException {
+        ServiceTag st = getServiceTag(instanceURN);
+        if (st == null) {
+            return null;
+        }
+
+        List<String> command = getCommandList();
+        command.add("-d");
+        command.add("-i");
+        command.add(instanceURN);
+
+        ProcessBuilder pb = new ProcessBuilder(command);
+        Process p = pb.start();
+        String output = commandOutput(p);
+        if (isVerbose()) {
+            System.out.println("Output from stclient -d command:");
+            System.out.println(output);
+        }
+        if (p.exitValue() == 0) {
+            return st;
+        } else {
+            return checkReturnError(p.exitValue(), output, st);
+        }
+    }
+
+    /**
+     * Updates the <tt>product_defined_instance_id</tt> in the service tag
+     * of the specified <tt>instance_urn</tt> in this registry.
+     *
+     * @param instanceURN the <tt>instance_urn</tt> of the service tag to be updated.
+     * @param productDefinedInstanceID the value of the
+     * <tt>product_defined_instance_id</tt> to be set.
+     *
+     * @return the updated {@code ServiceTag} object;
+     * or {@code null} if the service tag does not exist in this
+     * registry.
+     *
+     * @throws UnauthorizedAccessException if the user is not authorized to
+     * update the service tag from this registry.
+     *
+     * @throws IOException if an I/O error occurs in this operation.
+     */
+    public ServiceTag updateServiceTag(String instanceURN,
+                                       String productDefinedInstanceID)
+            throws IOException {
+        ServiceTag svcTag = getServiceTag(instanceURN);
+        if (svcTag == null) {
+            return null;
+        }
+
+        List<String> command = getCommandList();
+        command.add("-u");
+        command.add("-i");
+        command.add(instanceURN);
+        command.add("-I");
+        if (productDefinedInstanceID.length() > 0) {
+            command.add(productDefinedInstanceID);
+        } else {
+            command.add("\"\"");
+        }
+
+        ProcessBuilder pb = new ProcessBuilder(command);
+        Process p = pb.start();
+        String output = commandOutput(p);
+        if (isVerbose()) {
+            System.out.println("Output from stclient -u command:");
+            System.out.println(output);
+        }
+
+        if (p.exitValue() == 0) {
+            return getServiceTag(instanceURN);
+        } else {
+            return checkReturnError(p.exitValue(), output, svcTag);
+        }
+    }
+
+    /**
+     * Returns a {@code ServiceTag} object of the given  <tt>instance_urn</tt>
+     * in this registry.
+     *
+     * @param instanceURN the  <tt>instance_urn</tt> of the service tag
+     * @return a {@code ServiceTag} object of the given <tt>instance_urn</tt>
+     * in this registry; or {@code null} if not found.
+     *
+     * @throws java.io.IOException if an I/O error occurs in this operation.
+     */
+    public ServiceTag getServiceTag(String instanceURN) throws IOException {
+        if (instanceURN == null) {
+            throw new NullPointerException("instanceURN is null");
+        }
+
+        List<String> command = getCommandList();
+        command.add("-g");
+        command.add("-i");
+        command.add(instanceURN);
+
+        ProcessBuilder pb = new ProcessBuilder(command);
+        Process p = pb.start();
+        String output = commandOutput(p);
+        if (isVerbose()) {
+            System.out.println("Output from stclient -g command:");
+            System.out.println(output);
+        }
+        if (p.exitValue() == 0) {
+            return parseServiceTag(output);
+        } else {
+            return checkReturnError(p.exitValue(), output, null);
+        }
+    }
+
+    private ServiceTag parseServiceTag(String output) throws IOException {
+        BufferedReader in = null;
+        try {
+            Properties props = new Properties();
+            // parse the service tag output from stclient
+            in = new BufferedReader(new StringReader(output));
+            String line = null;
+            while ((line = in.readLine()) != null) {
+                if ((line = line.trim()).length() > 0) {
+                    String[] ss = line.trim().split("=", 2);
+                    if (ss.length == 2) {
+                        props.setProperty(ss[0].trim(), ss[1].trim());
+                    } else {
+                        props.setProperty(ss[0].trim(), "");
+                    }
+                }
+            }
+
+            String urn = props.getProperty(ST_NODE_INSTANCE_URN);
+            String productName = props.getProperty(ST_NODE_PRODUCT_NAME);
+            String productVersion = props.getProperty(ST_NODE_PRODUCT_VERSION);
+            String productURN = props.getProperty(ST_NODE_PRODUCT_URN);
+            String productParent = props.getProperty(ST_NODE_PRODUCT_PARENT);
+            String productParentURN = props.getProperty(ST_NODE_PRODUCT_PARENT_URN);
+            String productDefinedInstanceID =
+                props.getProperty(ST_NODE_PRODUCT_DEFINED_INST_ID);
+            String productVendor = props.getProperty(ST_NODE_PRODUCT_VENDOR);
+            String platformArch = props.getProperty(ST_NODE_PLATFORM_ARCH);
+            String container = props.getProperty(ST_NODE_CONTAINER);
+            String source = props.getProperty(ST_NODE_SOURCE);
+            int installerUID =
+                Util.getIntValue(props.getProperty(ST_NODE_INSTALLER_UID));
+            Date timestamp =
+                Util.parseTimestamp(props.getProperty(ST_NODE_TIMESTAMP));
+
+            return new ServiceTag(urn,
+                                  productName,
+                                  productVersion,
+                                  productURN,
+                                  productParent,
+                                  productParentURN,
+                                  productDefinedInstanceID,
+                                  productVendor,
+                                  platformArch,
+                                  container,
+                                  source,
+                                  installerUID,
+                                  timestamp);
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+
+    }
+
+    /**
+     * Returns the service tags of the specified
+     * <tt>product_urn</tt> in this registry.
+     *
+     * @param productURN the  <tt>product_urn</tt> to look up
+     * @return a {@code Set} of {@code ServiceTag} objects
+     * of the specified <tt>product_urn</tt> in this registry.
+     *
+     * @throws java.io.IOException if an I/O error occurs in this operation.
+     */
+    public Set<ServiceTag> findServiceTags(String productURN) throws IOException {
+        if (productURN == null) {
+            throw new NullPointerException("productURN is null");
+        }
+
+        List<String> command = getCommandList();
+        command.add("-f");
+        command.add("-t");
+        command.add(productURN);
+
+        BufferedReader in = null;
+        try {
+            ProcessBuilder pb = new ProcessBuilder(command);
+            Process p = pb.start();
+            String output = commandOutput(p);
+
+            Set<ServiceTag> instances = new HashSet<ServiceTag>();
+            if (p.exitValue() == 0) {
+                // parse the service tag output from stclient
+                in = new BufferedReader(new StringReader(output));
+                String line = null;
+                while ((line = in.readLine()) != null) {
+                    String s = line.trim();
+                    if (s.startsWith("urn:st:")) {
+                        instances.add(getServiceTag(s));
+                    }
+                }
+            } else {
+                checkReturnError(p.exitValue(), output, null);
+            }
+            return instances;
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/ServiceTag.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,634 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.servicetag;
+
+import java.util.Date;
+import java.io.IOException;
+import static com.sun.servicetag.RegistrationDocument.*;
+
+/**
+ * A service tag is an XML-based data structure that identifies a product or
+ * a component on a system. The service tag schema is defined by the
+ * Service Tags Technology. The location of the DTD file is platform dependent.
+ * On Solaris, see <tt>/usr/share/lib/xml/dtd/servicetag.dtd</tt>.
+ * <p>
+ * A valid {@code ServiceTag} instance must comply to the service tag schema
+ * and contain the following fields:
+ * <ul>
+ *   <li>{@link #getInstanceURN <tt>instance_urn</tt>}</li>
+ *   <li>{@link #getProductName <tt>product_name</tt>}</li>
+ *   <li>{@link #getProductVersion <tt>product_version</tt>}</li>
+ *   <li>{@link #getProductURN <tt>product_urn</tt>}</li>
+ *   <li>{@link #getProductParent <tt>product_parent</tt>}</li>
+ *   <li>{@link #getProductParentURN <tt>product_parent_urn</tt>}</li>
+ *   <li>{@link #getProductDefinedInstanceID <tt>product_defined_inst_id</tt>}</li>
+ *   <li>{@link #getProductVendor <tt>product_vendor</tt>}</li>
+ *   <li>{@link #getPlatformArch <tt>platform_arch</tt>}</li>
+ *   <li>{@link #getContainer <tt>container</tt>}</li>
+ *   <li>{@link #getSource <tt>source</tt>}</li>
+ *   <li>{@link #getInstallerUID <tt>installer_uid</tt>}</li>
+ *   <li>{@link #getTimestamp <tt>timestamp</tt>}</li>
+ * </ul>
+ *
+ * The <tt>instance_urn</tt> can be specified when a {@code ServiceTag}
+ * object is created, or it can be generated when it is added to
+ * a {@link RegistrationData} object, or {@link Registry
+ * system service tag registry}. The <tt>installer_uid</tt> and
+ * <tt>timestamp</tt> are set when a {@code ServiceTag} object
+ * is added to a {@link RegistrationData} object, or {@link Registry
+ * system service tag registry}.
+ *
+ * @see <a href="https://sunconnection.sun.com/FAQ/sc_faq.html">Service Tags FAQ</a>
+ */
+public class ServiceTag {
+
+    private String instanceURN;
+    private String productName;
+    private String productVersion;
+    private String productURN;
+    private String productParent;
+    private String productParentURN;
+    private String productDefinedInstanceID;
+    private String productVendor;
+    private String platformArch;
+    private String container;
+    private String source;
+    private int installerUID;
+    private Date timestamp;
+
+    // Service Tag Field Lengths (defined in sthelper.h)
+    // Since the constants defined in sthelper.h includes the null-terminated
+    // character, so minus 1 from the sthelper.h defined values.
+    private final int MAX_URN_LEN             = 256 - 1;
+    private final int MAX_PRODUCT_NAME_LEN    = 256 - 1;
+    private final int MAX_PRODUCT_VERSION_LEN = 64 - 1;
+    private final int MAX_PRODUCT_PARENT_LEN  = 256 - 1;
+    private final int MAX_PRODUCT_VENDOR_LEN  = 64 - 1;
+    private final int MAX_PLATFORM_ARCH_LEN   = 64 - 1;
+    private final int MAX_CONTAINER_LEN       = 64 - 1;
+    private final int MAX_SOURCE_LEN          = 64 - 1;
+
+    // private constructors
+    private ServiceTag() {
+    }
+    // package private
+    ServiceTag(String instanceURN,
+               String productName,
+               String productVersion,
+               String productURN,
+               String productParent,
+               String productParentURN,
+               String productDefinedInstanceID,
+               String productVendor,
+               String platformArch,
+               String container,
+               String source,
+               int installerUID,
+               Date timestamp) {
+        setInstanceURN(instanceURN);
+        setProductName(productName);
+        setProductVersion(productVersion);
+        setProductURN(productURN);
+        setProductParentURN(productParentURN);
+        setProductParent(productParent);
+        setProductDefinedInstanceID(productDefinedInstanceID);
+        setProductVendor(productVendor);
+        setPlatformArch(platformArch);
+        setContainer(container);
+        setSource(source);
+        setInstallerUID(installerUID);
+        setTimestamp(timestamp);
+    }
+
+    /**
+     * Creates a service tag object with no <tt>instance_urn</tt>.
+     *
+     * @param productName               the name of the product.
+     * @param productVersion            the version of the product.
+     * @param productURN                the uniform resource name of the product
+     * @param productParent             the name of the product's parent.
+     * @param productParentURN          the uniform resource name of the product's parent.
+     * @param productDefinedInstanceID  the instance identifier.
+     * @param productVendor             the vendor of the product.
+     * @param platformArch              the operating system architecture.
+     * @param container                 the container of the product.
+     * @param source                    the source of the product.
+     *
+     * @throws IllegalArgumentException if any value of the input fields
+     *    does not conform to the service tag XML schema.
+     */
+    public static ServiceTag newInstance(String productName,
+                                         String productVersion,
+                                         String productURN,
+                                         String productParent,
+                                         String productParentURN,
+                                         String productDefinedInstanceID,
+                                         String productVendor,
+                                         String platformArch,
+                                         String container,
+                                         String source) {
+          return new ServiceTag("", /* empty instance_urn */
+                                productName,
+                                productVersion,
+                                productURN,
+                                productParent,
+                                productParentURN,
+                                productDefinedInstanceID,
+                                productVendor,
+                                platformArch,
+                                container,
+                                source,
+                                -1,
+                                null);
+    }
+
+    /**
+     * Creates a service tag object with a specified <tt>instance_urn</tt>.
+     *
+     * @param instanceURN               the uniform resource name of this instance.
+     * @param productName               the name of the product.
+     * @param productVersion            the version of the product.
+     * @param productURN                the uniform resource name of the product
+     * @param productParent             the name of the product's parent.
+     * @param productParentURN          the uniform resource name of the product's parent.
+     * @param productDefinedInstanceID  the instance identifier.
+     * @param productVendor             the vendor of the product.
+     * @param platformArch              the operating system architecture.
+     * @param container                 the container of the product.
+     * @param source                    the source of the product.
+     *
+     * @throws IllegalArgumentException if any value of the input fields
+     *    does not conform to the service tag XML schema.
+     */
+    public static ServiceTag newInstance(String instanceURN,
+                                         String productName,
+                                         String productVersion,
+                                         String productURN,
+                                         String productParent,
+                                         String productParentURN,
+                                         String productDefinedInstanceID,
+                                         String productVendor,
+                                         String platformArch,
+                                         String container,
+                                         String source) {
+          return new ServiceTag(instanceURN,
+                                productName,
+                                productVersion,
+                                productURN,
+                                productParent,
+                                productParentURN,
+                                productDefinedInstanceID,
+                                productVendor,
+                                platformArch,
+                                container,
+                                source,
+                                -1,
+                                null);
+    }
+
+    // Creates a copy of the ServiceTag instance
+    // with instance_urn and timestamp initialized
+    static ServiceTag newInstanceWithUrnTimestamp(ServiceTag st) {
+        String instanceURN =
+            (st.getInstanceURN().length() == 0 ? Util.generateURN() :
+                                                 st.getInstanceURN());
+        ServiceTag svcTag = new ServiceTag(instanceURN,
+                                           st.getProductName(),
+                                           st.getProductVersion(),
+                                           st.getProductURN(),
+                                           st.getProductParent(),
+                                           st.getProductParentURN(),
+                                           st.getProductDefinedInstanceID(),
+                                           st.getProductVendor(),
+                                           st.getPlatformArch(),
+                                           st.getContainer(),
+                                           st.getSource(),
+                                           st.getInstallerUID(),
+                                           new Date());
+        return svcTag;
+    }
+
+    /**
+     * Returns a uniform resource name (URN) in this format:
+     * <blockquote>
+     * "<tt>urn:st:<32-char {@link java.util.UUID uuid}></tt>"
+     * </blockquote>
+     * @return a URN.
+     */
+    public static String generateInstanceURN() {
+        return Util.generateURN();
+    }
+
+    /**
+     * Returns the uniform resource name of this service tag instance.
+     *
+     * @return  the <tt>instance_urn</tt> of this service tag.
+     */
+    public String getInstanceURN() {
+        return instanceURN;
+    }
+
+    /**
+     * Returns the name of the product.
+     *
+     * @return the product name.
+     */
+    public String getProductName() {
+        return productName;
+    }
+
+    /**
+     * Returns the version of the product.
+     *
+     * @return the product version.
+     */
+    public String getProductVersion() {
+        return productVersion;
+    }
+
+    /**
+     * Returns the uniform resource name of the product.
+     *
+     * @return the product URN.
+     */
+    public String getProductURN() {
+        return productURN;
+    }
+
+    /**
+     * Returns the uniform resource name of the product's parent.
+     *
+     * @return the product's parent URN.
+     */
+    public String getProductParentURN() {
+        return productParentURN;
+    }
+
+    /**
+     * Returns the name of the product's parent.
+     *
+     * @return the product's parent name.
+     */
+    public String getProductParent() {
+        return productParent;
+    }
+
+    /**
+     * Returns the identifier defined for this product instance.
+     *
+     * @return  the identifier defined for this product instance.
+     */
+    public String getProductDefinedInstanceID() {
+        return productDefinedInstanceID;
+    }
+
+    /**
+     * Returns the vendor of the product.
+     *
+     * @return the product vendor.
+     */
+    public String getProductVendor() {
+        return productVendor;
+    }
+
+    /**
+     * Returns the platform architecture on which the product
+     * is running on.
+     *
+     * @return the platform architecture on which the product is running on.
+     */
+    public String getPlatformArch() {
+        return platformArch;
+    }
+
+    /**
+     * Returns the timestamp.  This timestamp is set when this service tag
+     * is added to or updated in a {@code RegistrationData} object or
+     * the system service tag registry.
+     * This method may return {@code null}.
+     *
+     * @return timestamp when this service tag
+     * is added to or updated in a {@code RegistrationData} object or
+     * the system service tag registry, or {@code null}.
+     */
+    public Date getTimestamp() {
+        if (timestamp != null) {
+            return (Date) timestamp.clone();
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * Returns the container of the product.
+     *
+     * @return the container of the product.
+     */
+    public String getContainer() {
+        return container;
+    }
+
+    /**
+     * Returns the source of this service tag.
+     *
+     * @return  source of this service tag.
+     */
+    public String getSource() {
+        return source;
+    }
+
+    /**
+     * Returns the UID. The UID is set when this service tag
+     * is added to or updated in the system service tag registry.
+     * This is platform dependent whose default value is {@code -1}.
+     * When this service tag is added to a {@code RegistrationData},
+     * the UID is not set.
+     *
+     * @return the UID of whom this service tag
+     * is added to or updated in the system service tag registry,
+     * or {@code -1}.
+     */
+    public int getInstallerUID() {
+        return installerUID;
+    }
+
+    // The following setter methods are used to validate the
+    // input field when constructing a ServiceTag instance
+
+    private void setInstanceURN(String instanceURN) {
+        if (instanceURN == null) {
+            throw new NullPointerException("Parameter instanceURN cannot be null");
+        }
+        if (instanceURN.length() > MAX_URN_LEN) {
+            throw new IllegalArgumentException("instanceURN \"" + instanceURN +
+                "\" exceeds maximum length " + MAX_URN_LEN);
+        }
+        this.instanceURN = instanceURN;
+    }
+
+    private void setProductName(String productName) {
+        if (productName == null) {
+            throw new NullPointerException("Parameter productName cannot be null");
+        }
+        if (productName.length() == 0) {
+            throw new IllegalArgumentException("product name cannot be empty");
+        }
+        if (productName.length() > MAX_PRODUCT_NAME_LEN) {
+            throw new IllegalArgumentException("productName \"" + productName +
+                "\" exceeds maximum length " + MAX_PRODUCT_NAME_LEN);
+        }
+        this.productName = productName;
+    }
+
+    private void setProductVersion(String productVersion) {
+        if (productVersion == null) {
+            throw new NullPointerException("Parameter productVersion cannot be null");
+        }
+
+        if (productVersion.length() == 0) {
+            throw new IllegalArgumentException("product version cannot be empty");
+        }
+        if (productVersion.length() > MAX_PRODUCT_VERSION_LEN) {
+            throw new IllegalArgumentException("productVersion \"" +
+                productVersion + "\" exceeds maximum length " +
+                MAX_PRODUCT_VERSION_LEN);
+        }
+        this.productVersion = productVersion;
+    }
+
+    private void setProductURN(String productURN) {
+        if (productURN == null) {
+            throw new NullPointerException("Parameter productURN cannot be null");
+        }
+        if (productURN.length() == 0) {
+            throw new IllegalArgumentException("product URN cannot be empty");
+        }
+        if (productURN.length() > MAX_URN_LEN) {
+            throw new IllegalArgumentException("productURN \"" + productURN +
+                "\" exceeds maximum length " + MAX_URN_LEN);
+        }
+        this.productURN = productURN;
+    }
+
+    private void setProductParentURN(String productParentURN) {
+        if (productParentURN == null) {
+            throw new NullPointerException("Parameter productParentURN cannot be null");
+        }
+        // optional field - can be empty
+        if (productParentURN.length() > MAX_URN_LEN) {
+            throw new IllegalArgumentException("productParentURN \"" +
+                productParentURN + "\" exceeds maximum length " +
+                MAX_URN_LEN);
+        }
+        this.productParentURN = productParentURN;
+    }
+
+    private void setProductParent(String productParent) {
+        if (productParent == null) {
+            throw new NullPointerException("Parameter productParent cannot be null");
+        }
+        if (productParent.length() == 0) {
+            throw new IllegalArgumentException("product parent cannot be empty");
+        }
+        if (productParent.length() > MAX_PRODUCT_PARENT_LEN) {
+            throw new IllegalArgumentException("productParent \"" +
+                productParent + "\" exceeds maximum length " +
+                MAX_PRODUCT_PARENT_LEN);
+        }
+        this.productParent = productParent;
+    }
+
+    void setProductDefinedInstanceID(String productDefinedInstanceID) {
+        if (productDefinedInstanceID == null) {
+            throw new NullPointerException("Parameter productDefinedInstanceID cannot be null");
+        }
+        if (productDefinedInstanceID.length() > MAX_URN_LEN) {
+            throw new IllegalArgumentException("productDefinedInstanceID \"" +
+                productDefinedInstanceID + "\" exceeds maximum length " +
+                MAX_URN_LEN);
+        }
+        // optional field - can be empty
+        this.productDefinedInstanceID = productDefinedInstanceID;
+    }
+
+    private void setProductVendor(String productVendor) {
+        if (productVendor == null) {
+            throw new NullPointerException("Parameter productVendor cannot be null");
+        }
+        if (productVendor.length() == 0) {
+            throw new IllegalArgumentException("product vendor cannot be empty");
+        }
+        if (productVendor.length() > MAX_PRODUCT_VENDOR_LEN) {
+            throw new IllegalArgumentException("productVendor \"" +
+                productVendor + "\" exceeds maximum length " +
+                MAX_PRODUCT_VENDOR_LEN);
+        }
+        this.productVendor = productVendor;
+    }
+
+    private void setPlatformArch(String platformArch) {
+        if (platformArch == null) {
+            throw new NullPointerException("Parameter platformArch cannot be null");
+        }
+        if (platformArch.length() == 0) {
+            throw new IllegalArgumentException("platform architecture cannot be empty");
+        }
+        if (platformArch.length() > MAX_PLATFORM_ARCH_LEN) {
+            throw new IllegalArgumentException("platformArch \"" +
+                platformArch + "\" exceeds maximum length " +
+                MAX_PLATFORM_ARCH_LEN);
+        }
+        this.platformArch = platformArch;
+    }
+
+    private void setTimestamp(Date timestamp) {
+        // can be null
+        this.timestamp = timestamp;
+    }
+
+    private void setContainer(String container) {
+        if (container == null) {
+            throw new NullPointerException("Parameter container cannot be null");
+        }
+        if (container.length() == 0) {
+            throw new IllegalArgumentException("container cannot be empty");
+        }
+        if (container.length() > MAX_CONTAINER_LEN) {
+            throw new IllegalArgumentException("container \"" +
+                container + "\" exceeds maximum length " +
+                MAX_CONTAINER_LEN);
+        }
+        this.container = container;
+    }
+
+    private void setSource(String source) {
+        if (source == null) {
+            throw new NullPointerException("Parameter source cannot be null");
+        }
+        if (source.length() == 0) {
+            throw new IllegalArgumentException("source cannot be empty");
+        }
+        if (source.length() > MAX_SOURCE_LEN) {
+            throw new IllegalArgumentException("source \"" + source +
+                "\" exceeds maximum length " + MAX_SOURCE_LEN);
+        }
+        this.source = source;
+    }
+
+    private void setInstallerUID(int installerUID) {
+        this.installerUID = installerUID;
+    }
+
+    /**
+     * Compares this service tag to the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and is a {@code ServiceTag} object whose
+     * <tt>instance_urn</tt> is the same as the
+     * <tt>instance_urn</tt> of this service tag.
+     *
+     * @return {@code true} if this service tag is the same as
+     * the specified object.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null || !(obj instanceof ServiceTag)) {
+            return false;
+        }
+        ServiceTag st = (ServiceTag) obj;
+        if (st == this) {
+            return true;
+        }
+        return st.getInstanceURN().equals(getInstanceURN());
+    }
+
+    /**
+     * Returns the hash code value for this service tag.
+     * @return the hash code value for this service tag.
+     */
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 19 * hash + (this.instanceURN != null ? this.instanceURN.hashCode() : 0);
+        return hash;
+    }
+
+    /**
+     * Returns the string representation of this service tag.
+     * The format is implementation specific.
+     *
+     * @return the string representation of this service tag.
+     */
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(ST_NODE_INSTANCE_URN).append("=").append(instanceURN).append("\n");
+        sb.append(ST_NODE_PRODUCT_NAME).append("=").append(productName).append("\n");
+        sb.append(ST_NODE_PRODUCT_VERSION).append("=").append(productVersion).append("\n");
+        sb.append(ST_NODE_PRODUCT_URN).append("=").append(productURN).append("\n");
+        sb.append(ST_NODE_PRODUCT_PARENT_URN).append("=").append(productParentURN).append("\n");
+        sb.append(ST_NODE_PRODUCT_PARENT).append("=").append(productParent).append("\n");
+        sb.append(ST_NODE_PRODUCT_DEFINED_INST_ID).append("=").append(productDefinedInstanceID).append("\n");
+        sb.append(ST_NODE_PRODUCT_VENDOR).append("=").append(productVendor).append("\n");
+        sb.append(ST_NODE_PLATFORM_ARCH).append("=").append(platformArch).append("\n");
+        sb.append(ST_NODE_TIMESTAMP).append("=").append(Util.formatTimestamp(timestamp)).append("\n");
+        sb.append(ST_NODE_CONTAINER).append("=").append(container).append("\n");
+        sb.append(ST_NODE_SOURCE).append("=").append(source).append("\n");
+        sb.append(ST_NODE_INSTALLER_UID).append("=").append(String.valueOf(installerUID)).append("\n");
+        return sb.toString();
+    }
+
+
+    /**
+     * Returns the {@link ServiceTag} instance for the running Java
+     * platform. The {@link ServiceTag#setSource source} field
+     * of the {@code ServiceTag} will be set to the given {@code source}.
+     * This method will return {@code null} if there is no service tag
+     * for the running Java platform.
+     * <p>
+     * This method is designed for Sun software that bundles the JDK
+     * or the JRE to use. It is recommended that the {@code source}
+     * string contains information about the bundling software
+     * such as the name and the version of the software bundle,
+     * for example,
+     * <blockquote>
+     * <tt>NetBeans IDE 6.0 with JDK 6 Update 5 Bundle</tt>
+     * </blockquote>
+     * in a NetBeans/JDK bundle.
+     * <p>
+     * At the first time to call this method the application
+     * is required to have the write permission to the installed
+     * directory of this running JDK or JRE instance.
+     *
+     * @param source the source that bundles the JDK or the JRE.
+     * @return a {@code ServiceTag} object for the Java platform,
+     *         or {@code null} if not supported.
+     * @throws IOException if an error occurs in this operation.
+     */
+    public static ServiceTag getJavaServiceTag(String source) throws IOException {
+        return Installer.getJavaServiceTag(source);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/SolarisServiceTag.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.servicetag;
+
+import java.io.IOException;
+import java.util.Set;
+
+/**
+ * Utility class to obtain the service tag for the Solaris Operating System.
+ */
+class SolarisServiceTag {
+    private final static String[] SolarisProductURNs = new String[] {
+        "urn:uuid:a7a38948-2bd5-11d6-98ce-9d3ac1c0cfd7", /* Solaris 8 */
+        "urn:uuid:4f82caac-36f3-11d6-866b-85f428ef944e", /* Solaris 9 */
+        "urn:uuid:a19de03b-48bc-11d9-9607-080020a9ed93", /* Solaris 9 sparc */
+        "urn:uuid:4c35c45b-4955-11d9-9607-080020a9ed93", /* Solaris 9 x86 */
+        "urn:uuid:5005588c-36f3-11d6-9cec-fc96f718e113", /* Solaris 10 */
+        "urn:uuid:6df19e63-7ef5-11db-a4bd-080020a9ed93"  /* Solaris 11 */
+    };
+
+    /**
+     * Returns null if not found.
+     *
+     * There is only one service tag for the operating system.
+     */
+    static ServiceTag getServiceTag() throws IOException {
+        if (Registry.isSupported()) {
+            Registry streg = Registry.getSystemRegistry();
+            for (String parentURN : SolarisProductURNs) {
+                Set<ServiceTag> instances = streg.findServiceTags(parentURN);
+                for (ServiceTag st : instances) {
+                    // there should have only one service tag for the OS
+                    return st;
+                }
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/SolarisSystemEnvironment.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.servicetag;
+
+// This class is a copy of the com.sun.scn.servicetags.SolarisSystemEnvironment
+// class from the Sun Connection source.
+//
+// The Service Tags team maintains the latest version of the implementation
+// for system environment data collection.  JDK will include a copy of
+// the most recent released version for a JDK release. We rename
+// the package to com.sun.servicetag so that the Sun Connection
+// product always uses the latest version from the com.sun.scn.servicetags
+// package. JDK and users of the com.sun.servicetag API
+// (e.g. NetBeans and SunStudio) will use the version in JDK.
+//
+// So we keep this class in src/share/classes instead of src/<os>/classes.
+
+import java.io.*;
+
+/**
+ * Solaris implementation of the SystemEnvironment class.
+ */
+class SolarisSystemEnvironment extends SystemEnvironment {
+    SolarisSystemEnvironment() {
+        setHostId(getCommandOutput("/usr/bin/hostid"));
+        setSystemModel(getCommandOutput("/usr/bin/uname", "-i"));
+        setSystemManufacturer(getSolarisSystemManufacturer());
+        setCpuManufacturer(getSolarisCpuManufacturer());
+        setSerialNumber(getSolarisSN());
+    }
+
+    /**
+     * Tries to obtain the cpu manufacturer.
+     * @return The cpu manufacturer (an empty string if not found or an error occurred)
+     */
+    private String getSolarisCpuManufacturer() {
+        // not fully accurate, this could be another manufacturer (fujitsu for example)
+        if ("sparc".equalsIgnoreCase(System.getProperty("os.arch"))) {
+            return "Sun Microsystems, Inc";
+        }
+
+        // if we're here, then we'll try smbios (type 3)
+        return getSmbiosData("3", "Manufacturer: ");
+    }
+
+    /**
+     * Tries to obtain the system manufacturer.
+     * @return The system manufacturer (an empty string if not found or an error occurred)
+     */
+    private String getSolarisSystemManufacturer() {
+        // not fully accurate, this could be another manufacturer (fujitsu for example)
+        if ("sparc".equalsIgnoreCase(System.getProperty("os.arch"))) {
+            return "Sun Microsystems, Inc";
+        }
+
+        // if we're here, then we'll try smbios (type 1)
+        return getSmbiosData("1", "Manufacturer: ");
+    }
+
+    /**
+     * Tries to obtain the serial number.
+     * @return The serial number (empty string if not found or an error occurred)
+     */
+    private String getSolarisSN() {
+        // try to read from the psn file if it exists
+        String tmp = getFileContent("/var/run/psn");
+        if (tmp.length() > 0) {
+            return tmp.trim();
+        }
+
+        // if we're here, then we'll try sneep
+        String tmpSN = getSneepSN();
+        if (tmpSN.length() > 0) {
+            return tmpSN;
+        }
+
+        // if we're here, then we'll try smbios (type 1)
+        tmpSN = getSmbiosData("1", "Serial Number: ");
+        if (tmpSN.length() > 0) {
+            return tmpSN;
+        }
+
+        // if we're here, then we'll try smbios (type 3)
+        tmpSN = getSmbiosData("3", "Serial Number: ");
+        if (tmpSN.length() > 0) {
+            return tmpSN;
+        }
+
+        // give up and return
+        return "";
+    }
+
+    // Sample smbios output segment:
+    // ID    SIZE TYPE
+    // 1     150  SMB_TYPE_SYSTEM (system information)
+    //
+    //   Manufacturer: Sun Microsystems
+    //   Product: Sun Fire X4600
+    //   Version: To Be Filled By O.E.M.
+    //   Serial Number: 00:14:4F:45:0C:2A
+    private String getSmbiosData(String type, String target) {
+        String output = getCommandOutput("/usr/sbin/smbios", "-t", type);
+        for (String s : output.split("\n")) {
+            if (s.contains(target)) {
+                int indx = s.indexOf(target) + target.length();
+                if (indx < s.length()) {
+                    String tmp = s.substring(indx).trim();
+                    String lowerCaseStr = tmp.toLowerCase();
+                    if (!lowerCaseStr.startsWith("not available")
+                            && !lowerCaseStr.startsWith("to be filled by o.e.m")) {
+                        return tmp;
+                    }
+                }
+            }
+        }
+
+        return "";
+    }
+
+    private String getSneepSN() {
+        String basedir = getCommandOutput("pkgparam","SUNWsneep","BASEDIR");
+        File f = new File(basedir + "/bin/sneep");
+        if (f.exists()) {
+            String sneepSN = getCommandOutput(basedir + "/bin/sneep");
+            if (sneepSN.equalsIgnoreCase("unknown")) {
+                return "";
+            } else {
+                return sneepSN;
+            }
+        } else {
+            return "";
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/SunConnection.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.servicetag;
+
+import java.io.*;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.io.OutputStreamWriter;
+import java.util.Locale;
+import javax.net.ssl.HttpsURLConnection;
+
+/**
+ * Sun Connection Class for Product Registration.
+ *
+ * Registration Web Application Interface
+ * 1) POST the product registry to the output stream of the registration
+ *    relay service.
+ * 2) Open the webapp URL from a browser with the following parameters:
+ *    registry-urn
+ *    product=jdk
+ *    locale=<default-locale>
+ *    version=<version>
+ *
+ * @see https://sn-tools.central.sun.com/twiki/pub/ServiceTags/RegistrationRelayService/
+ *
+ */
+class SunConnection {
+
+    private static String JDK_REGISTRATION_URL = "https://inventory.sun.com/";
+    private static String SANDBOX_TESTING_URL = "https://inventory-beta.sun.com/";
+    private static String REGISTRATION_WEB_PATH = "RegistrationWeb/register";
+
+    // System properties for testing
+    private static String SVCTAG_REGISTER_TESTING = "servicetag.register.testing";
+    private static String SVCTAG_REGISTRATION_URL = "servicetag.registration.url";
+    private static String SVCTAG_CONNECTION_TIMEOUT = "servicetag.connection.timeout";
+
+    private SunConnection() {
+    }
+
+    /**
+     * Returns a URL for JDK registration interfacing with the Sun Connection
+     * registration relay service in this form:
+     *   <registration-url>/<registry_urn>?product=jdk&locale=<locale>
+     *
+     * The <registration-url> can be overridden by an environment
+     * variable or a system property.
+     *
+     * 1) "servicetag.register.testing" system property to switch to the
+     *    Sun Connection registration sandbox testing.
+     * 2) "servicetag.registration.url" system property to override
+     *    the URL
+     * 3) Default production URL
+     *
+     */
+    static URL getRegistrationURL(String registrationURN, Locale locale, String version) {
+        String url = System.getProperty(SVCTAG_REGISTRATION_URL);
+        if (url == null) {
+            if (System.getProperty(SVCTAG_REGISTER_TESTING) != null) {
+                url = SANDBOX_TESTING_URL;
+            } else {
+                url = JDK_REGISTRATION_URL;
+            }
+        }
+        url += REGISTRATION_WEB_PATH;
+
+        // trim whitespaces
+        url = url.trim();
+        if (url.length() == 0) {
+            throw new InternalError("Empty registration url set");
+        }
+
+        // Add the registry_urn in the URL's query
+        String registerURL = rewriteURL(url, registrationURN, locale, version);
+        try {
+            return new URL(registerURL);
+        } catch (MalformedURLException ex) {
+            // should never reach here
+            InternalError x =
+                new InternalError(ex.getMessage());
+            x.initCause(ex);
+            throw x;
+        }
+    }
+
+    private static String rewriteURL(String url, String registryURN, Locale locale, String version) {
+        StringBuilder sb = new StringBuilder(url.trim());
+        int len = sb.length();
+        if (sb.charAt(len-1) != '/') {
+            sb.append('/');
+        }
+        sb.append(registryURN);
+        sb.append("?");
+        sb.append("product=jdk");
+        sb.append("&");
+        sb.append("locale=").append(locale.toString());
+        sb.append("&");
+        sb.append("version=").append(version);
+        return sb.toString();
+    }
+
+    /**
+     * Registers all products in the given product registry.  If it fails
+     * to post the service tag registry, open the browser with the offline
+     * registration page.
+     *
+     * @param regData registration data to be posted to the Sun Connection
+     *             for registration.
+     * @param locale Locale
+     * @param version JDK version
+     *
+     * @throws IOException if I/O error occurs in this operation
+     */
+    public static void register(RegistrationData regData,
+                                Locale locale,
+                                String version) throws IOException {
+        // Gets the URL for SunConnection registration relay service
+        URL url = getRegistrationURL(regData.getRegistrationURN(),
+                                     locale,
+                                     version);
+
+        // Post the Product Registry to Sun Connection
+        boolean succeed = postRegistrationData(url, regData);
+        if (succeed) {
+            // service tags posted successfully
+            // now prompt for registration
+            openBrowser(url);
+        } else {
+            // open browser with the offline registration page
+            openOfflineRegisterPage();
+        }
+    }
+
+    /**
+     * Opens a browser for JDK product registration.
+     * @param url Registration Webapp URL
+     */
+    private static void openBrowser(URL url) throws IOException {
+        if (!BrowserSupport.isSupported()) {
+            if (Util.isVerbose()) {
+                System.out.println("Browser is not supported");
+            }
+            return;
+        }
+
+        try {
+            BrowserSupport.browse(url.toURI());
+        } catch (URISyntaxException ex) {
+            InternalError x = new InternalError("Error in registering: " + ex.getMessage());
+            x.initCause(ex);
+            throw x;
+        } catch (IllegalArgumentException ex) {
+            if (Util.isVerbose()) {
+                ex.printStackTrace();
+            }
+        } catch (UnsupportedOperationException ex) {
+            // ignore if not supported
+            if (Util.isVerbose()) {
+                ex.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * POST service tag registry to Sun Connection
+     * @param loc the URL of the webapp to handle the POST request
+     * @param streg the Service Tag registry
+     * @return true if posting succeeds; otherwise, false.
+     */
+    private static boolean postRegistrationData(URL url,
+                                                RegistrationData registration) {
+        try {
+            HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
+            con.setDoInput(true);
+            con.setDoOutput(true);
+            con.setUseCaches(false);
+            con.setAllowUserInteraction(false);
+
+            // default 10 seconds timeout
+            String timeout = System.getProperty(SVCTAG_CONNECTION_TIMEOUT, "10");
+            con.setConnectTimeout(Util.getIntValue(timeout) * 1000);
+
+            if (Util.isVerbose()) {
+                System.out.println("Connecting to post registration data at " + url);
+            }
+
+            con.setRequestMethod("POST");
+            con.setRequestProperty("Content-Type", "text/xml;charset=\"utf-8\"");
+            con.connect();
+
+            OutputStream out = con.getOutputStream();
+            registration.storeToXML(out);
+            out.flush();
+            out.close();
+
+            int returnCode = con.getResponseCode();
+            if (Util.isVerbose()) {
+                System.out.println("POST return status = " + returnCode);
+                printReturnData(con, returnCode);
+            }
+            return (returnCode == HttpURLConnection.HTTP_OK);
+        } catch (MalformedURLException me) {
+            // should never reach here
+            InternalError x = new InternalError("Error in registering: " + me.getMessage());
+            x.initCause(me);
+            throw x;
+        } catch (Exception ioe) {
+            // SocketTimeoutException, IOException or UnknownHostException
+            if (Util.isVerbose()) {
+                ioe.printStackTrace();
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Opens the offline registratioin page in the browser.
+     *
+     */
+    private static void openOfflineRegisterPage()
+            throws IOException {
+        if (!BrowserSupport.isSupported()) {
+            if (Util.isVerbose()) {
+                System.out.println("Browser is not supported");
+            }
+            return;
+        }
+
+        File registerPage = Installer.getRegistrationHtmlPage();
+        try {
+            BrowserSupport.browse(registerPage.toURI());
+        } catch (FileNotFoundException ex) {
+            // should never reach here
+            InternalError x =
+                new InternalError("Error in launching " + registerPage + ": " + ex.getMessage());
+            x.initCause(ex);
+            throw x;
+        } catch (IllegalArgumentException ex) {
+            if (Util.isVerbose()) {
+                ex.printStackTrace();
+            }
+        } catch (UnsupportedOperationException ex) {
+            // ignore if not supported
+            if (Util.isVerbose()) {
+                ex.printStackTrace();
+            }
+        }
+    }
+
+    private static void printReturnData(HttpURLConnection con, int returnCode)
+            throws IOException {
+        BufferedReader reader = null;
+        try {
+            if (returnCode < 400) {
+                reader = new BufferedReader(
+                             new InputStreamReader(con.getInputStream()));
+            } else {
+                reader = new BufferedReader(
+                             new InputStreamReader(con.getErrorStream()));
+            }
+            StringBuilder sb = new StringBuilder();
+            String line;
+            while ((line = reader.readLine()) != null) {
+                sb.append(line).append("\n");
+            }
+            System.out.println("Response is : ");
+            System.out.println(sb.toString());
+        } finally {
+            if (reader != null) {
+                reader.close();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/SystemEnvironment.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.servicetag;
+
+// This class is a copy of the com.sun.scn.servicetags.SystemEnvironment
+// class from the Sun Connection source.
+//
+// The Service Tags team maintains the latest version of the implementation
+// for system environment data collection.  JDK will include a copy of
+// the most recent released version for a JDK release. We rename
+// the package to com.sun.servicetag so that the Sun Connection
+// product always uses the latest version from the com.sun.scn.servicetags
+// package. JDK and users of the com.sun.servicetag API
+// (e.g. NetBeans and SunStudio) will use the version in JDK.
+
+import java.io.*;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * SystemEnvironment class collects the environment data with the
+ * best effort from the underlying platform.
+ */
+public class SystemEnvironment {
+    private String hostname;
+    private String hostId;
+    private String osName;
+    private String osVersion;
+    private String osArchitecture;
+    private String systemModel;
+    private String systemManufacturer;
+    private String cpuManufacturer;
+    private String serialNumber;
+    private static SystemEnvironment sysEnv = null;
+
+    public static synchronized SystemEnvironment getSystemEnvironment() {
+        if (sysEnv == null) {
+            String os = System.getProperty("os.name");
+            if (os.equals("SunOS")) {
+                sysEnv = new SolarisSystemEnvironment();
+            } else if (os.equals("Linux")) {
+                sysEnv = new LinuxSystemEnvironment();
+            } else if (os.startsWith("Windows")) {
+                sysEnv = new WindowsSystemEnvironment();
+            } else {
+                sysEnv = new SystemEnvironment();
+            }
+        }
+        return sysEnv;
+    }
+
+    // package-private
+    SystemEnvironment() {
+        try {
+            this.hostname = InetAddress.getLocalHost().getHostName();
+        } catch (UnknownHostException ex) {
+            this.hostname = "Unknown host";
+        }
+        this.hostId = "";
+        this.osName = System.getProperty("os.name");
+        this.osVersion = System.getProperty("os.version");
+        this.osArchitecture = System.getProperty("os.arch");
+        this.systemModel = "";
+        this.systemManufacturer = "";
+        this.cpuManufacturer = "";
+        this.serialNumber = "";
+    }
+
+
+    /**
+     * Sets the hostname.
+     * @param hostname The hostname to set.
+     */
+    public void setHostname(String hostname) {
+        this.hostname = hostname;
+    }
+
+    /**
+     * Sets the OS name.
+     * @param osName The osName to set.
+     */
+    public void setOsName(String osName) {
+        this.osName = osName;
+    }
+
+    /**
+     * Sets the OS version.
+     * @param osVersion The osVersion to set.
+     */
+    public void setOsVersion(String osVersion) {
+        this.osVersion = osVersion;
+    }
+
+    /**
+     * Sets the OS architecture.
+     * @param osArchitecture The osArchitecture to set.
+     */
+    public void setOsArchitecture(String osArchitecture) {
+        this.osArchitecture = osArchitecture;
+    }
+
+    /**
+     * Sets the system model.
+     * @param systemModel The systemModel to set.
+     */
+    public void setSystemModel(String systemModel) {
+        this.systemModel = systemModel;
+    }
+
+    /**
+     * Sets the system manufacturer.
+     * @param systemManufacturer The systemManufacturer to set.
+     */
+    public void setSystemManufacturer(String systemManufacturer) {
+        this.systemManufacturer = systemManufacturer;
+    }
+
+    /**
+     * Sets the cpu manufacturer.
+     * @param cpuManufacturer The cpuManufacturer to set.
+     */
+    public void setCpuManufacturer(String cpuManufacturer) {
+        this.cpuManufacturer = cpuManufacturer;
+    }
+
+    /**
+     * Sets the serial number.
+     * @param serialNumber The serialNumber to set.
+     */
+    public void setSerialNumber(String serialNumber) {
+        this.serialNumber = serialNumber;
+    }
+
+    /**
+     * Sets the hostid.  Truncates to a max length of 16 chars.
+     * @param hostId The hostid to set.
+     */
+    public void setHostId(String hostId) {
+        if (hostId == null || hostId.equals("null")) {
+            hostId = "";
+        }
+        if (hostId.length() > 16) {
+            hostId = hostId.substring(0,16);
+        }
+        this.hostId = hostId;
+    }
+
+    /**
+     * Returns the hostname.
+     * @return The hostname.
+     */
+    public String getHostname() {
+        return hostname;
+    }
+
+    /**
+     * Returns the osName.
+     * @return The osName.
+     */
+    public String getOsName() {
+        return osName;
+    }
+
+    /**
+     * Returns the osVersion.
+     * @return The osVersion.
+     */
+    public String getOsVersion() {
+        return osVersion;
+    }
+
+    /**
+     * Returns the osArchitecture.
+     * @return The osArchitecture.
+     */
+    public String getOsArchitecture() {
+        return osArchitecture;
+    }
+
+    /**
+     * Returns the systemModel.
+     * @return The systemModel.
+     */
+    public String getSystemModel() {
+        return systemModel;
+    }
+
+    /**
+     * Returns the systemManufacturer.
+     * @return The systemManufacturer.
+     */
+    public String getSystemManufacturer() {
+        return systemManufacturer;
+    }
+
+    /**
+     * Returns the serialNumber.
+     * @return The serialNumber.
+     */
+    public String getSerialNumber() {
+        return serialNumber;
+    }
+
+    /**
+     * Returns the hostId.
+     * @return The hostId.
+     */
+    public String getHostId() {
+        return hostId;
+    }
+
+    /**
+     * Returns the cpuManufacturer.
+     * @return The cpuManufacturer.
+     */
+    public String getCpuManufacturer() {
+        return cpuManufacturer;
+    }
+
+    protected String getCommandOutput(String... command) {
+        StringBuilder sb = new StringBuilder();
+        BufferedReader br = null;
+        Process p = null;
+        try {
+            ProcessBuilder pb = new ProcessBuilder(command);
+            p = pb.start();
+            p.waitFor();
+
+            if (p.exitValue() == 0) {
+                br = new BufferedReader(new InputStreamReader(p.getInputStream()));
+                String line = null;
+                while ((line = br.readLine()) != null) {
+                    line = line.trim();
+                    if (line.length() > 0) {
+                        if (sb.length() > 0) {
+                            sb.append("\n");
+                        }
+                        sb.append(line);
+                    }
+                }
+            }
+            return sb.toString();
+        } catch (InterruptedException ie) {
+            // in case the command hangs
+            if (p != null) {
+                p.destroy();
+            }
+            return "";
+        } catch (Exception e) {
+            // ignore exception
+            return "";
+        } finally {
+            if (p != null) {
+                try {
+                    p.getErrorStream().close();
+                } catch (IOException e) {
+                    // ignore
+                }
+                try {
+                    p.getInputStream().close();
+                } catch (IOException e) {
+                    // ignore
+                }
+                try {
+                    p.getOutputStream().close();
+                } catch (IOException e) {
+                    // ignore
+                }
+                p = null;
+            }
+            if (br != null) {
+                try {
+                    br.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    protected String getFileContent(String filename) {
+        File f = new File(filename);
+        if (!f.exists()) {
+            return "";
+        }
+
+        StringBuilder sb = new StringBuilder();
+        BufferedReader br = null;
+        try {
+            br = new BufferedReader(new FileReader(f));
+            String line = null;
+            while ((line = br.readLine()) != null) {
+                line = line.trim();
+                if (line.length() > 0) {
+                    if (sb.length() > 0) {
+                        sb.append("\n");
+                    }
+                    sb.append(line);
+                }
+            }
+            return sb.toString();
+        } catch (Exception e) {
+            // ignore exception
+            return "";
+        } finally {
+            if (br != null) {
+                try {
+                    br.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/UnauthorizedAccessException.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.servicetag;
+
+/**
+ * Thrown if the user is not authorized to
+ * {@link Registry#updateServiceTag update} or
+ * {@link Registry#removeServiceTag remove}
+ * a service tag from a {@link Registry}.
+ */
+public class UnauthorizedAccessException extends RuntimeException {
+
+    /**
+     * Constructs an <code>UnauthorizedAccessException</code> object
+     * without detail message.
+     */
+    public UnauthorizedAccessException() {
+    }
+
+
+    /**
+     * Constructs an <code>UnauthorizedAccessException</code> object
+     * with the specified detail message.
+     *
+     * @param msg the detail message.
+     */
+    public UnauthorizedAccessException(String msg) {
+        super(msg);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/Util.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 {
+            if (r != null) {
+                r.close();
+            }
+            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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/WindowsSystemEnvironment.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.servicetag;
+
+// This class is a copy of the com.sun.scn.servicetags.WindowsSystemEnvironment
+// class from the Sun Connection source.
+//
+// The Service Tags team maintains the latest version of the implementation
+// for system environment data collection.  JDK will include a copy of
+// the most recent released version for a JDK release. We rename
+// the package to com.sun.servicetag so that the Sun Connection
+// product always uses the latest version from the com.sun.scn.servicetags
+// package. JDK and users of the com.sun.servicetag API
+// (e.g. NetBeans and SunStudio) will use the version in JDK.
+//
+// So we keep this class in src/share/classes instead of src/<os>/classes.
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Windows implementation of the SystemEnvironment class.
+ */
+class WindowsSystemEnvironment extends SystemEnvironment {
+    WindowsSystemEnvironment() {
+        super();
+
+        // run a call to make sure things are initialized
+        // ignore the first call result as the system may
+        // give inconsistent data on the first invocation ever
+        getWmicResult("computersystem", "get", "model");
+
+        setSystemModel(getWmicResult("computersystem", "get", "model"));
+        setSystemManufacturer(getWmicResult("computersystem", "get", "manufacturer"));
+        setSerialNumber(getWmicResult("bios", "get", "serialnumber"));
+
+        String cpuMfr = getWmicResult("cpu", "get", "manufacturer");
+        // this isn't as good an option, but if we couldn't get anything
+        // from wmic, try the processor_identifier
+        if (cpuMfr.length() == 0) {
+            String procId = System.getenv("processor_identifer");
+            if (procId != null) {
+                String[] s = procId.split(",");
+                cpuMfr = s[s.length - 1].trim();
+            }
+        }
+        setCpuManufacturer(cpuMfr);
+
+        // try to remove the temp file that gets created from running wmic cmds
+        try {
+            // look in the current working directory
+            File f = new File("TempWmicBatchFile.bat");
+            if (f.exists()) {
+                f.delete();
+            }
+        } catch (Exception e) {
+            // ignore the exception
+        }
+    }
+
+
+    /**
+     * This method invokes wmic outside of the normal environment
+     * collection routines.
+     *
+     * An initial call to wmic can be costly in terms of time.
+     *
+     * <code>
+     * Details of why the first call is costly can be found at:
+     *
+     * http://support.microsoft.com/kb/290216/en-us
+     *
+     * "When you run the Wmic.exe utility for the first time, the utility
+     * compiles its .mof files into the repository. To save time during
+     * Windows installation, this operation takes place as necessary."
+     * </code>
+     */
+    private String getWmicResult(String alias, String verb, String property) {
+        String res = "";
+        BufferedReader in = null;
+        try {
+            ProcessBuilder pb = new ProcessBuilder("cmd", "/C", "WMIC", alias, verb, property);
+            Process p = pb.start();
+            // need this for executing windows commands (at least
+            // needed for executing wmic command)
+            BufferedWriter bw = new BufferedWriter(
+                new OutputStreamWriter(p.getOutputStream()));
+            bw.write(13);
+            bw.flush();
+            bw.close();
+
+            p.waitFor();
+            if (p.exitValue() == 0) {
+                in = new BufferedReader(new InputStreamReader(p.getInputStream()));
+                String line = null;
+                while ((line = in.readLine()) != null) {
+                    line = line.trim();
+                    if (line.length() == 0) {
+                        continue;
+                    }
+                    res = line;
+                }
+                // return the *last* line read
+                return res;
+            }
+
+        } catch (Exception e) {
+            // ignore the exception
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+        return res.trim();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/package.html	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,71 @@
+CTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+particular file as subject to the "Classpath" exception as provided
+by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+CA 95054 USA or visit www.sun.com if you need additional information or
+have any questions.
+
+-->
+
+</head>
+<body bgcolor="white">
+
+This package contains classes that allow the creation
+and manipulation of service tags.
+This com.sun.servicetag package is intended for
+<b>Sun internal use</b> only.
+<p>
+<dl>
+<dt><b>Service Tag</b></dt>
+<dd>A service tag is an XML-based data structure that contains identifying
+information about an instance of a product or component on a system.
+</dd>
+</dl>
+<dl>
+<dt><b>Service Tag Registry</b></dt>
+<dd>A service tag registry is a XML-based registry that contains
+the service tags of all the tagged components on a system.  The
+service tag registry is present on systems that have the
+Service Tags software installed.
+</dd>
+</dl>
+<dl>
+<dt><b>Registration Data</b></dt>
+<dd>A registration data is a container of one or more
+service tags that identify the
+components for product registration and will be used to interface
+with the Sun Connection registration services.
+</dd>
+</dl>
+
+This package contains the methods to create service tags, set up the
+registration data for product registration, add service tags to and
+remove them from the system service tag registry.
+<p>
+All methods defined in this package will throw {@code NullPointerException}
+if {@code null} is passed in any input parameter unless it is stated otherwise.
+In addition, they are multi-thread safe.
+</body>
+</html>
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/resources/Putback-Notes.txt	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,25 @@
+README for auto-generating of the offline registration page.
+
+1. register.html is defined by the xDesign team.
+
+2. Before putback in the workspace, we need to modify the 
+   register.html to contain the following:
+
+   (a) replace the pathname of the jdk_header.png image to
+       <img src="@@JDK_HEADER_PNG@@" ....>
+
+   (b) replace the product name from:
+           Java Development Kit Version 6 Update 5 (e.g.)
+       to:
+           Java Development Kit @@JDK_VERSION@@ 
+
+   (c) replace the form action for the "Register My JDK" button with:
+
+       <form name="form1" method="post" action="@@REGISTRATION_URL@@" enctype="text/xml">
+
+   (d) Add this input in the form for posting data after 
+       the <form name=....> line:
+ 
+       <input type="hidden" name="servicetag_payload" value="@@REGISTRATION_PAYLOAD@@">
+
+3. The jdk_header.png is located under <JRE>/lib/servicetag directory.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/resources/javase_5_swordfish.properties	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,29 @@
+# Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+
+servicetag.jdk.urn     = urn:uuid:d5bed446-05f2-42ed-ba0a-153105a52413
+servicetag.jdk.name    = J2SE 5.0 Development Kit
+servicetag.jre.urn     = urn:uuid:5c6686aa-fd05-46a6-ba3e-700e2d5f7043
+servicetag.jre.name    = J2SE 5.0 Runtime Environment
+servicetag.parent.urn  = urn:uuid:f3c20172-557a-11d7-93d0-d6a41ea318df
+servicetag.parent.name = Java 2 Platform, Standard Edition 5.0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/resources/javase_6_swordfish.properties	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,29 @@
+# Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+
+servicetag.jdk.urn     = urn:uuid:b58ef9a8-5ae8-11db-a023-080020a9ed93
+servicetag.jdk.name    = Java SE 6 Development Kit
+servicetag.jre.urn     = urn:uuid:92d1de8c-1e59-42c6-a280-1c379526bcbc
+servicetag.jre.name    = Java SE 6 Runtime Environment
+servicetag.parent.urn  = urn:uuid:fdc90b21-018d-4cab-b866-612c7c119ed3
+servicetag.parent.name = Java Platform Standard Edition 6 (Java SE 6)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/resources/javase_7_swordfish.properties	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,29 @@
+# Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+
+servicetag.jdk.urn     = JSEZ9-007-ZZZZ
+servicetag.jdk.name    = Java SE 7 Development Kit
+servicetag.jre.urn     = JSERE-007-ZZZZ
+servicetag.jre.name    = Java SE 7 Runtime Environment
+servicetag.parent.urn  = urn:uuid:dc1704fe-264f-11dc-9482-080020a9ed93
+servicetag.parent.name = Java Platform Standard Edition 7 (Java SE 7)
Binary file src/share/classes/com/sun/servicetag/resources/jdk_header.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/resources/product_registration.xsd	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,301 @@
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+<xs:element name="registration_data">
+  <xs:complexType>
+    <xs:sequence>
+      <xs:element name="environment"
+                  minOccurs="1"
+                  maxOccurs="1">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element ref="hostname"
+                        minOccurs='1'
+                        maxOccurs='1'/>
+            <xs:element ref="hostId"
+                        minOccurs='1'
+                        maxOccurs='1'/>
+            <xs:element ref="osName"
+                        minOccurs='1'
+                        maxOccurs='1'/>
+            <xs:element ref="osVersion"
+                        minOccurs='1'
+                        maxOccurs='1'/>
+            <xs:element ref="osArchitecture"
+                        minOccurs='1'
+                        maxOccurs='1'/>
+            <xs:element ref="systemModel"
+                        minOccurs='1'
+                        maxOccurs='1'/>
+            <xs:element ref="systemManufacturer"
+                        minOccurs='1'
+                        maxOccurs='1'/>
+            <xs:element ref="cpuManufacturer"
+                        minOccurs='1'
+                        maxOccurs='1'/>
+            <xs:element ref="serialNumber"
+                        minOccurs='1'
+                        maxOccurs='1'/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="registry"
+                  minOccurs="1"
+                  maxOccurs="1">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element name="service_tag"
+                        minOccurs="0"
+                        maxOccurs="1024">
+              <xs:complexType>
+                <xs:sequence>
+                  <xs:element ref="instance_urn"
+                              minOccurs='1'
+                              maxOccurs='1'/>
+                  <xs:element ref="product_name"
+                              minOccurs='1'
+                              maxOccurs='1'/>
+                  <xs:element ref="product_version"
+                              minOccurs='1'
+                              maxOccurs='1'/>
+                  <xs:element ref="product_urn"
+                              minOccurs='1'
+                              maxOccurs='1'/>
+                  <xs:element ref="product_parent_urn"
+                              minOccurs='1'
+                              maxOccurs='1'/>
+                  <xs:element ref="product_parent"
+                              minOccurs='1'
+                              maxOccurs='1'/>
+                  <xs:element ref="product_defined_inst_id"
+                              minOccurs='1'
+                              maxOccurs='1'/>
+                  <xs:element ref="product_vendor"
+                              minOccurs='1'
+                              maxOccurs='1'/>
+                  <xs:element ref="platform_arch"
+                              minOccurs='1'
+                              maxOccurs='1'/>
+                  <xs:element ref="timestamp"
+                              minOccurs='1'
+                              maxOccurs='1'/>
+                  <xs:element ref="container"
+                              minOccurs='1'
+                              maxOccurs='1'/>
+                  <xs:element ref="source"
+                              minOccurs='1'
+                              maxOccurs='1'/>
+                  <xs:element ref="installer_uid"
+                              minOccurs='1'
+                              maxOccurs='1'/>
+                </xs:sequence>
+              </xs:complexType>
+            </xs:element>
+          </xs:sequence>
+          <xs:attribute name="urn"
+                        type="xs:string"
+                        use="required"/>
+          <xs:attribute name="version"
+                        type="xs:string"
+                        use="required"/>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+    <xs:attribute name="version"
+                  type="xs:string"
+                  use="required"/>
+  </xs:complexType>
+</xs:element>
+
+  <!-- definition of simple elements -->
+  <xs:element name="hostname">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="1"/>
+        <xs:maxLength value="255"/>
+      </xs:restriction>
+    </xs:simpleType>
+   </xs:element>
+
+  <xs:element name="hostId">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="0"/>
+        <xs:maxLength value="16"/>
+      </xs:restriction>
+    </xs:simpleType>
+   </xs:element>
+
+  <xs:element name="osName">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="1"/>
+        <xs:maxLength value="256"/>
+      </xs:restriction>
+    </xs:simpleType>
+   </xs:element>
+
+  <xs:element name="osVersion">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="0"/>
+        <xs:maxLength value="50"/>
+      </xs:restriction>
+    </xs:simpleType>
+   </xs:element>
+
+  <xs:element name="osArchitecture">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="0"/>
+        <xs:maxLength value="256"/>
+      </xs:restriction>
+    </xs:simpleType>
+   </xs:element>
+
+  <xs:element name="systemModel">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="0"/>
+        <xs:maxLength value="50"/>
+      </xs:restriction>
+    </xs:simpleType>
+   </xs:element>
+
+  <xs:element name="systemManufacturer">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="0"/>
+        <xs:maxLength value="50"/>
+      </xs:restriction>
+    </xs:simpleType>
+   </xs:element>
+
+  <xs:element name="cpuManufacturer">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="0"/>
+        <xs:maxLength value="50"/>
+      </xs:restriction>
+    </xs:simpleType>
+   </xs:element>
+
+  <xs:element name="serialNumber">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="0"/>
+        <xs:maxLength value="256"/>
+      </xs:restriction>
+    </xs:simpleType>
+   </xs:element>
+
+  <xs:element name="instance_urn">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="1"/>
+        <xs:maxLength value="255"/>
+      </xs:restriction>
+    </xs:simpleType>
+   </xs:element>
+
+  <xs:element name="product_name">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:maxLength value="255"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+
+  <xs:element name="product_version">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:maxLength value="63"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+
+  <xs:element name="product_urn">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="1"/>
+        <xs:maxLength value="255"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+
+  <xs:element name="product_parent_urn">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="0"/>
+        <xs:maxLength value="255"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+
+  <xs:element name="product_parent">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="1"/>
+        <xs:maxLength value="255"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+
+  <xs:element name="product_defined_inst_id">
+      <xs:simpleType>
+          <xs:restriction base="xs:string">
+              <xs:minLength value="0"/>
+              <xs:maxLength value="255"/>
+          </xs:restriction>
+      </xs:simpleType>
+  </xs:element>
+
+  <xs:element name="product_vendor">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="1"/>
+        <xs:maxLength value="63"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+
+  <xs:element name="platform_arch">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:minLength value="1"/>
+        <xs:maxLength value="63"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+
+  <xs:element name="timestamp">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:maxLength value="24"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+
+  <xs:element name="container">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:maxLength value="63"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+
+  <xs:element name="source">
+    <xs:simpleType>
+      <xs:restriction base="xs:string">
+        <xs:maxLength value="63"/>
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+
+  <xs:element name="installer_uid">
+    <xs:simpleType>
+      <xs:restriction base="xs:integer">
+      </xs:restriction>
+    </xs:simpleType>
+  </xs:element>
+
+</xs:schema>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/resources/register.html	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Register your JDK</title>
+
+<!--
+Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+particular file as subject to the "Classpath" exception as provided
+by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+CA 95054 USA or visit www.sun.com if you need additional information or
+have any questions.
+-->
+
+<style type="text/css">
+<!--
+.style1 {font-family: Arial, Helvetica, sans-serif}
+.style3 {font-family: Arial, Helvetica, sans-serif; font-size: small; }
+input.buttonblue,input.defbutton{ background: #3F6580;border-right:1px solid #304C60;border-bottom:1px solid #304C60;border-left:1px solid #BACDD9;border-top:1px solid #BACDD9; font-weight:bold; color:#FFFFFF; font-size:.8em; height:1.9em}
+input.buttonblue:hover{color:#fbe249;}
+a:link,a.named:visited{color:#3E6B8A}
+a:hover{text-decoration:underline}
+a{text-decoration:none}
+a:visited,a:visited code{color:#917E9C}
+-->
+</style>
+</head>
+
+<body>
+<table width="813" border="0" cellpadding="3" cellspacing="0">
+  <tr>
+    <td width="7" height="78">&nbsp;</td>
+    <td width="794" align="left" valign="top">
+        <img src="@@JDK_HEADER_PNG@@" width="783" height="63"></td>
+  </tr>
+  <tr>
+    <td>&nbsp;</td>
+    <td><p class="style1">Thank you for installing the
+        <strong> Java Development Kit @@JDK_VERSION@@ </strong>
+        from Sun Microsystems. </p>
+        <p class="style1">Registering your product will give you the following benefits:</p>
+        <ul class="style1">
+          <li> Notification of new versions, patches, and updates</li>
+          <li> Special offers on Sun developer products, services and training </li>
+          <li> Access to early releases and documentation </li>
+        </ul>
+        <p class="style1">Product registration is FREE, quick and easy!</p>
+        <blockquote>
+          <p class="style1">All you need is a Sun Developer Network or other Sun Online account. If you don't already have one, you will be prompted to create one. </p>
+          <table width="708" border="0" cellspacing="0" cellpadding="3">
+            <tr valign="top">
+              <td width="126" height="35">
+              <form name="form1" method="post" action="@@REGISTRATION_URL@@" enctype="text/xml">
+                <input type="hidden" name="servicetag_payload" value="@@REGISTRATION_PAYLOAD@@">
+                <input type="submit" name="Submit"border="0" class="buttonblue" onmouseover="this.style.color='#fbe249';" onmouseout="this.style.color='#FFF';"  value="Register My JDK">
+              </form></td>
+              <td width="570"><span class="style3">You need to be connected to the Internet to register this Sun product. </span></td>
+            </tr>
+          </table>
+        </blockquote>
+        </td>
+        </tr>
+    <tr>
+       <td>&nbsp;</td>
+       <td bgcolor="#f1f7df">
+       <p class="style3">Sun Microsystems, Inc. respects your privacy.
+    We will use your personal information for communications
+    and management of your Sun Online Account, the services
+    and applications you access using your Sun Online Account,
+    and the products and systems you register with your Sun Online Account.</p>
+                <p class="style3">For more information on the data that will be collected as
+          part of the registration process and how it will be managed <br>
+          see <a href="http://java.sun.com/javase/registration/JDKRegistrationPrivacy.html">http://java.sun.com/javase/registration/JDKRegistrationPrivacy.html</a>. <br>
+          <br>
+          For more information on Sun's Privacy Policy see <a href="http://www.sun.com/privacy/">http://www.sun.com/privacy/</a> or contact <a class="moz-txt-link-rfc2396E" href="mailto:privacy@sun.com">privacy@sun.com.</a></p></td>
+  </tr>
+  <tr>
+    <td>&nbsp;</td>
+    <td>&nbsp;</td>
+  </tr>
+  <tr>
+    <td>&nbsp;</td>
+    <td>&nbsp;</td>
+  </tr>
+</table>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/resources/register_ja.html	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.or
+g/TR/html4/loose.dtd">
+<html><head>
+
+
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>JDK 製品登録</title>
+
+<!--
+Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+particular file as subject to the "Classpath" exception as provided
+by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+CA 95054 USA or visit www.sun.com if you need additional information or
+have any questions.
+-->
+
+<style type="text/css">
+<!--
+.style1 {font-family: Arial, Helvetica, sans-serif}
+.style3 {font-family: Arial, Helvetica, sans-serif; font-size: small; }
+input.buttonblue,input.defbutton{ background: #3F6580;border-right:1px solid #304C60;border-bottom:1px solid #304C60;border-left:1px solid #BACDD9;border-top:1px solid #BACDD9; font-weight:bold; color:#FFFFFF; font-size:.8em; height:1.9em}
+input.buttonblue:hover{color:#fbe249;}
+a:link,a.named:visited{color:#3E6B8A}
+a:hover{text-decoration:underline}
+a{text-decoration:none}
+a:visited,a:visited code{color:#917E9C}
+-->
+</style></head><body>
+<table border="0" cellpadding="3" cellspacing="0" width="813">
+  <tbody><tr>
+    <td height="78" width="7">&nbsp;</td>
+    <td align="left" valign="top" width="794"><img src="@@JDK_HEADER_PNG@@" height="63" width="783"></td>
+  </tr>
+  <tr>
+    <td>&nbsp;</td>
+
+    <td><p class="style1">Sun Microsystems の<strong> Java Development Kit @@JDK_VERSION@@ </strong>をインストールしていただき、ありがとうございます。 </p>
+        <p class="style1">製品登録をすると、次のような特典を受けることができます。</p>
+        <ul class="style1">
+          <li> 最新のバージョン、パッチ、および更新についての通知</li>
+          <li> Sun の開発者向け製品、サービス、およびトレーニングの特別販売 </li>
+          <li> アーリーリリースおよびドキュメントへのアクセス </li>
+        </ul>
+        <p class="style1">製品登録は無料であり、迅速で簡単です。</p>
+        <blockquote>
+          <p class="style1">必要になるのは、Sun 開発者向けネットワークアカウントまたはその他の Sun オンラインアカウントだけです。 まだアカウントがない場合は、アカウントの作成が求められます。 </p>
+          <table width="708" border="0" cellspacing="0" cellpadding="3">
+            <tr valign="top">
+              <td width="126" height="35"><form name="form1" method="post" action="@@REGISTRATION_URL@@" enctype="text/xml">
+			  <input type="hidden" name="servicetag_payload" value="@@REGISTRATION_PAYLOAD@@">
+                <input type="submit" name="Submit"border="0" class="buttonblue" onmouseover="this.style.color='#fbe249';" onmouseout="this.style.color='#FFF';"  value="JDK 製品登録">
+              </form></td>
+              <td width="570"><span class="style3">この Sun 製品を登録するには、インターネットに接続している必要があります。 </span></td>
+            </tr>
+	  </table>
+	</blockquote>
+	</td>
+	</tr>
+   <tr>
+       <td>&nbsp;</td>
+	<td bgcolor="#f1f7df">
+        <p class="style3">Sun Microsystems, Inc. は、お客様のプライバシーを尊重します。 お客様の個人情報は、お客様の Sun オンラインアカウント、お客様が Sun オンラインアカウントを使用してアクセスするサービスとアプリケーション、およびお客様が Sun オンラインアカウントで登録する製品とシステムの通信と管理に使用します。</p>
+                <p class="style3">登録の際に収集されるデータや、それらがどのように管理されるかについての詳細は、<br><a href="http://java.sun.com/javase/ja/registration/JDKRegistrationPrivacy.html">http://java.sun.com/javase/ja/registration/JDKRegistrationPrivacy.html</a> を参照してください。 <br> <br> Sun のプライバシーポリシーについての詳細は、<a href="http://jp.sun.com/privacy/">http://jp.sun.com/privacy/</a> を参照するか、<a class="moz-txt-link-rfc2396E" href="http://jp.sun.com/cgi-bin/contact/comment.cgi?url=http://jp.sun.com/privacy/">お問い合わせフォーム</a>からお問い合わせください。</p></td>
+  </tr>
+  <tr>
+    <td>&nbsp;</td>
+    <td>&nbsp;</td>
+  </tr>
+  <tr>
+    <td>&nbsp;</td>
+    <td>&nbsp;</td>
+  </tr>
+</table>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/servicetag/resources/register_zh_CN.html	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>注册您的 JDK</title>
+
+<!--
+Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+particular file as subject to the "Classpath" exception as provided
+by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+CA 95054 USA or visit www.sun.com if you need additional information or
+have any questions.
+-->
+
+<style type="text/css">
+<!--
+.style1 {font-family: Arial, Helvetica, sans-serif}
+.style3 {font-family: Arial, Helvetica, sans-serif; font-size: small; }
+input.buttonblue,input.defbutton{ background: #3F6580;border-right:1px solid #304C60;border-bottom:1px solid #304C60;border-left:1px solid #BACDD9;border-top:1px solid #BACDD9; font-weight:bold; color:#FFFFFF; font-size:.8em; height:1.9em}
+input.buttonblue:hover{color:#fbe249;}
+a:link,a.named:visited{color:#3E6B8A}
+a:hover{text-decoration:underline}
+a{text-decoration:none}
+a:visited,a:visited code{color:#917E9C}
+-->
+</style></head><body>
+<table border="0" cellpadding="3" cellspacing="0" width="813">
+  <tbody><tr>
+    <td height="78" width="7">&nbsp;</td>
+    <td align="left" valign="top" width="794"><img src="@@JDK_HEADER_PNG@@" height="63" width="783"></td>
+  </tr>
+
+  <tr>
+    <td>&nbsp;</td>
+
+<td><p class="style1">感谢您安装 Sun Microsystems 的 <strong>Java Development Kit @@JDK_VERSION@@</strong>。 </p>
+<p class="style1">注册产品后您将获得如下增值服务:</p>
+        <ul class="style1">
+<li> 获得新版本、修补程序和更新的通知服务</li>
+<li> 获得有关 Sun 开发者产品、服务和培训的优惠 </li>
+<li> 获得对早期版本和文档的访问权限 </li>
+        </ul>
+<p class="style1">产品注册是免费的,即快速又轻松!</p>
+        <blockquote>
+<p class="style1">您需要具有 Sun 开发者网络或其他 Sun 联机帐户。如果您没有,系统将提示您创建一个。 </p>
+          <table width="708" border="0" cellspacing="0" cellpadding="3">
+            <tr valign="top">
+              <td width="126" height="35"><form name="form1" method="post" action="@@REGISTRATION_URL@@" enctype="text/xml">
+			  <input type="hidden" name="servicetag_payload" value="@@REGISTRATION_PAYLOAD@@">
+<input type="submit" name="Submit"border="0" class="buttonblue" onmouseover="this.style.color='#fbe249';" onmouseout="this.style.color='#FFF';"  value="注册我的 JDK">
+              </form></td>
+<td width="570"><span class="style3">您需要连接到 Internet 来注册此 Sun 产品。 </span></td>
+            </tr>
+	  </table>
+	</blockquote>
+	</td>
+	</tr>
+    <tr>
+       <td>&nbsp;</td>
+	<td bgcolor="#f1f7df">
+        <p class="style3">Sun Microsystems, Inc. 尊重您的隐私。我们会将您的个人信息用于通信和 Sun 联机帐户的管理、Sun 联机帐户访问的服务和应用程序以及用于使用 Sun 联机帐户注册的产品和系统。</p>
+<p class="style3">有关注册过程中收集的数据以及这些数据的管理方式的更多信息,<br>请访问 <a href="http://java.sun.com/javase/registration/JDKRegistrationPrivacy.html">http://java.sun.com/javase/registration/JDKRegistrationPrivacy.html</a>。<br> <br>有关 Sun 隐私政策的更多信息,请访问 <a href="http://www.sun.com/privacy/">http://www.sun.com/privacy/</a> 或与 <a class="moz-txt-link-rfc2396E" href="mailto:privacy@sun.com">privacy@sun.com</a> 联系。</p></td>
+  </tr>
+  <tr>
+    <td>&nbsp;</td>
+    <td>&nbsp;</td>
+  </tr>
+  <tr>
+    <td>&nbsp;</td>
+    <td>&nbsp;</td>
+  </tr>
+</table>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/DeleteServiceTag.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug     6622366
+ * @summary Basic Test for deleting a service tag in a product registration
+ * @author  Mandy Chung
+ *
+ * @run build DeleteServiceTag Util
+ * @run main DeleteServiceTag
+ */
+
+import com.sun.servicetag.*;
+import java.io.*;
+import java.util.*;
+
+public class DeleteServiceTag {
+    private static RegistrationData registration;
+    private static File regFile;
+    private static Map<String, ServiceTag> stMap =
+        new LinkedHashMap<String, ServiceTag>();
+    private static String[] files = new String[] {
+                                        "servicetag1.properties",
+                                        "servicetag2.properties",
+                                        "servicetag3.properties"
+                                    };
+
+    public static void main(String[] argv) throws Exception {
+        String registrationDir = System.getProperty("test.classes");
+        String servicetagDir = System.getProperty("test.src");
+
+        File original = new File(servicetagDir, "registration.xml");
+        regFile = new File(registrationDir, "registration.xml");
+        copyRegistrationXML(original, regFile);
+
+        // loads all the service tags
+        for (String f : files) {
+            File stfile = new File(servicetagDir, f);
+            ServiceTag svcTag = Util.newServiceTag(stfile);
+            stMap.put(svcTag.getInstanceURN(), svcTag);
+        }
+
+        // load the registration data with all service tags
+        BufferedInputStream in = new BufferedInputStream(new FileInputStream(regFile));
+        registration = RegistrationData.loadFromXML(in);
+
+        if (stMap.size() != files.length) {
+            throw new RuntimeException("Invalid service tag count= " +
+                stMap.size() + " expected=" + files.length);
+        }
+        // check the service tags
+        Util.checkRegistrationData(regFile.getCanonicalPath(), stMap);
+
+        // delete a service tag
+        deleteServiceTag(servicetagDir, files[0]);
+
+        System.out.println("Test passed: service tags deleted.");
+    }
+
+    private static void copyRegistrationXML(File from, File to) throws IOException {
+
+        to.delete();
+        BufferedReader reader = new BufferedReader(new FileReader(from));
+        PrintWriter writer = new PrintWriter(to);
+        try {
+            String line = null;
+            while ((line = reader.readLine()) != null) {
+                writer.println(line);
+            }
+            writer.flush();
+        } finally {
+            writer.close();
+        }
+    }
+
+    private static void deleteServiceTag(String parent, String filename) throws Exception {
+        File f = new File(parent, filename);
+        ServiceTag svcTag = Util.newServiceTag(f);
+
+        ServiceTag st = registration.removeServiceTag(svcTag.getInstanceURN());
+        if (st == null) {
+            throw new RuntimeException("RegistrationData.remove method" +
+                " returns null");
+        }
+        if (!Util.matches(st, svcTag)) {
+            throw new RuntimeException("ServiceTag added in the registration " +
+                " doesn't match.");
+        }
+        // check the service tags before storing the updated data
+        Util.checkRegistrationData(regFile.getCanonicalPath(), stMap);
+
+        ServiceTag st1 = registration.getServiceTag(svcTag.getInstanceURN());
+        if (st1 != null) {
+            throw new RuntimeException("RegistrationData.get method returns " +
+                "non-null.");
+        }
+        // Now remove the service tag from the map and store to the XML file
+        stMap.remove(svcTag.getInstanceURN());
+        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(regFile));
+        try {
+            registration.storeToXML(out);
+        } finally {
+            out.close();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/DuplicateNotFound.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug     6622366
+ * @summary Basic Test for RegistrationData.removeServiceTag and
+ *          updateServiceTag.
+ * @author  Mandy Chung
+ *
+ * @run build DuplicateNotFound Util
+ * @run main DuplicateNotFound
+ */
+
+import com.sun.servicetag.*;
+import java.io.*;
+import java.util.*;
+
+public class DuplicateNotFound {
+    private static String servicetagDir = System.getProperty("test.src");
+    private static String[] files = new String[] {
+                                        "servicetag1.properties",
+                                        "servicetag2.properties",
+                                        "servicetag3.properties"
+                                    };
+
+    private static RegistrationData registration = new RegistrationData();
+
+    public static void main(String[] argv) throws Exception {
+        ServiceTag svcTag;
+        registration.addServiceTag(loadServiceTag(files[0]));
+        registration.addServiceTag(loadServiceTag(files[1]));
+        testDuplicate(files[0]);
+        testDuplicate(files[1]);
+        testNotFound(files[2]);
+    }
+
+    private static void testDuplicate(String filename) throws Exception {
+        boolean dup = false;
+        try {
+           registration.addServiceTag(loadServiceTag(filename));
+        } catch (IllegalArgumentException e) {
+           dup = true;
+        }
+        if (!dup) {
+           throw new RuntimeException(filename +
+               " added successfully but expected to be a duplicated.");
+        }
+    }
+    private static void testNotFound(String filename) throws Exception {
+        ServiceTag st = loadServiceTag(filename);
+        ServiceTag svctag = registration.getServiceTag(st.getInstanceURN());
+        if (svctag != null) {
+           throw new RuntimeException(st.getInstanceURN() +
+               " exists but expected not found");
+        }
+
+        svctag = registration.removeServiceTag(st.getInstanceURN());
+        if (svctag != null) {
+           throw new RuntimeException(st.getInstanceURN() +
+               " exists but expected not found");
+        }
+
+        svctag = registration.updateServiceTag(st.getInstanceURN(), "testing");
+        if (svctag != null) {
+           throw new RuntimeException(st.getInstanceURN() +
+               " updated successfully but expected not found.");
+        }
+    }
+
+    private static ServiceTag loadServiceTag(String filename) throws Exception {
+        File f = new File(servicetagDir, filename);
+        return Util.newServiceTag(f);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/FindServiceTags.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug     6622366
+ * @summary Basic Test for Registry.findServiceTags()
+ * @author  Mandy Chung
+ *
+ * @run build FindServiceTags SvcTagClient Util
+ * @run main FindServiceTags
+ */
+
+import com.sun.servicetag.*;
+import java.io.*;
+import java.util.*;
+
+// This test creates a few service tags in the Registry.
+// Check if the findServiceTags method returns the expected ones.
+public class FindServiceTags {
+    private static String registryDir = System.getProperty("test.classes");
+    private static String servicetagDir = System.getProperty("test.src");
+    private static String[] files = new String[] {
+                                        "servicetag1.properties",
+                                        "servicetag2.properties",
+                                        "servicetag3.properties",
+                                        "servicetag4.properties",
+                                        "servicetag5.properties"
+                                    };
+
+    private static Registry registry;
+    private static Set<ServiceTag> set = new HashSet<ServiceTag>();
+    private static Set<String> productUrns = new HashSet<String>();
+    private static int expectedUrnCount = 3;
+
+    public static void main(String[] argv) throws Exception {
+        registry = Util.getSvcTagClientRegistry();
+
+        for (String filename : files) {
+            File f = new File(servicetagDir, filename);
+            ServiceTag svcTag = Util.newServiceTag(f);
+            ServiceTag st = registry.addServiceTag(svcTag);
+
+            set.add(st);
+            productUrns.add(st.getProductURN());
+        }
+        if (productUrns.size() != expectedUrnCount) {
+            throw new RuntimeException("Unexpected number of product URNs = " +
+                productUrns.size() + " expected " + expectedUrnCount);
+        }
+        if (set.size() != files.length) {
+            throw new RuntimeException("Unexpected number of service tags = " +
+                set.size() + " expected " + files.length);
+        }
+        String purn = null;
+        for (String urn : productUrns) {
+            if (purn == null) {
+                // save the first product_urn for later use
+                purn = urn;
+            }
+            findServiceTags(urn);
+        }
+
+        // remove all service tags of purn
+        Set<ServiceTag> tags = registry.findServiceTags(purn);
+        for (ServiceTag st : tags) {
+            System.out.println("Removing service tag " + st.getInstanceURN());
+            registry.removeServiceTag(st.getInstanceURN());
+        }
+        tags = registry.findServiceTags(purn);
+        if (tags.size() != 0) {
+            throw new RuntimeException("Unexpected service tag count = " +
+                tags.size());
+        }
+
+        System.out.println("Test passed.");
+    }
+
+    private static void findServiceTags(String productUrn) throws Exception {
+        Set<ServiceTag> found = registry.findServiceTags(productUrn);
+        Set<ServiceTag> matched = new HashSet<ServiceTag>();
+        System.out.println("Finding service tags of product_urn=" +
+            productUrn);
+        for (ServiceTag st : set) {
+            if (st.getProductURN().equals(productUrn)) {
+                System.out.println(st.getInstanceURN());
+                matched.add(st);
+            }
+        }
+        if (found.size() != matched.size()) {
+            throw new RuntimeException("Unmatched service tag count = " +
+                found.size() + " expected " + matched.size());
+        }
+
+        for (ServiceTag st0 : found) {
+            ServiceTag st = null;
+            for (ServiceTag st1 : matched) {
+                if (Util.matches(st0, st1)) {
+                    st = st1;
+                    break;
+                }
+            }
+            if (st == null) {
+                System.out.println("product_urn=" + st0.getProductURN());
+                System.out.println("instance_urn=" + st0.getInstanceURN() );
+                throw new RuntimeException(st0.getInstanceURN() +
+                    " not expected in the returned list");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/InstanceUrnCheck.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug     6622366
+ * @summary Basic Test for checking instance_urn
+ * @author  Mandy Chung
+ *
+ * @run build InstanceUrnCheck Util
+ * @run main InstanceUrnCheck
+ */
+
+import com.sun.servicetag.*;
+import java.io.*;
+import java.util.*;
+
+public class InstanceUrnCheck {
+    private static String servicetagDir = System.getProperty("test.src");
+    private static String[] files = new String[] {
+                                        "servicetag1.properties",
+                                        "servicetag2.properties",
+                                        "servicetag3.properties"
+                                    };
+    private static RegistrationData registration = new RegistrationData();
+
+    public static void main(String[] argv) throws Exception {
+        for (String f : files) {
+            addServiceTag(f);
+        }
+    }
+
+   private static void addServiceTag(String filename) throws Exception {
+        File f = new File(servicetagDir, filename);
+        ServiceTag svcTag = Util.newServiceTag(f, true /* no instance_urn */);
+        ServiceTag st = registration.addServiceTag(svcTag);
+        if (!Util.matchesNoInstanceUrn(svcTag, st)) {
+            throw new RuntimeException("ServiceTag " +
+                " doesn't match.");
+        }
+        System.out.println("New service tag instance_urn=" + st.getInstanceURN());
+        if (!st.getInstanceURN().startsWith("urn:st:")) {
+            throw new RuntimeException("Invalid generated instance_urn " +
+                st.getInstanceURN());
+        }
+        if (st.getInstallerUID() != -1) {
+            throw new RuntimeException("Invalid installer_uid " +
+                st.getInstallerUID());
+        }
+        if (st.getTimestamp() == null) {
+            throw new RuntimeException("null timestamp ");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/InvalidRegistrationData.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug     6622366
+ * @summary Basic Test for invalid product registry
+ * @author  Mandy Chung
+ *
+ * @run build InvalidRegistrationData
+ * @run main InvalidRegistrationData
+ */
+
+import com.sun.servicetag.*;
+import java.io.*;
+import java.util.*;
+
+public class InvalidRegistrationData {
+    public static void main(String[] argv) throws Exception {
+        String servicetagDir = System.getProperty("test.src");
+
+        checkRegistrationData(servicetagDir, "missing-environ-field.xml");
+        checkRegistrationData(servicetagDir, "newer-registry-version.xml");
+    }
+
+    private static void checkRegistrationData(String parent, String filename)
+           throws Exception {
+        boolean thrown = false;
+        File f = new File(parent, filename);
+        BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));
+        try {
+            RegistrationData regData = RegistrationData.loadFromXML(in);
+        } catch (IllegalArgumentException e) {
+            System.out.println(e.getMessage() + " thrown expected");
+            thrown = true;
+        }
+
+        if (!thrown) {
+            throw new RuntimeException("ERROR: No IllegalArgumentException thrown");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/InvalidServiceTag.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug     6622366
+ * @summary Basic Test for ServiceTag.newServiceTag() to test invalid fields.
+ * @author  Mandy Chung
+ *
+ * @run build InvalidServiceTag
+ * @run main InvalidServiceTag
+ */
+
+import com.sun.servicetag.*;
+import java.io.*;
+import java.util.*;
+
+public class InvalidServiceTag {
+    private final static int MAX_CONTAINER_LEN = 64 - 1;
+    public static void main(String[] argv) throws Exception {
+        // all fields valid
+        ServiceTag st1 = ServiceTag.newInstance("product name",
+                                                "product version",
+                                                "product urn",
+                                                "product parent",
+                                                "product parent urn",
+                                                "product defined instance ID",
+                                                "product vendor",
+                                                "platform arch",
+                                                "container",
+                                                "source");
+        // empty optional field
+        ServiceTag st2 = ServiceTag.newInstance("product name",
+                                                "product version",
+                                                "product urn",
+                                                "product parent",
+                                                "",
+                                                "",
+                                                "product vendor",
+                                                "platform arch",
+                                                "container",
+                                                "source");
+        // Invalid - empty required field
+        setInvalidContainer("");
+        // Invalid - required field exceeds max length.
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i <= MAX_CONTAINER_LEN; i++) {
+            sb.append('x');
+        }
+        setInvalidContainer(sb.toString());
+        System.out.println("Test passed.");
+    }
+    private static void setInvalidContainer(String container) {
+        boolean exceptionThrown = false;
+        try {
+            ServiceTag st2 = ServiceTag.newInstance("product name",
+                                                    "product version",
+                                                    "product urn",
+                                                    "product parent",
+                                                    "product parent urn",
+                                                    "product defined instance ID",
+                                                    "product vendor",
+                                                    "platform arch",
+                                                    container,
+                                                    "source");
+        } catch (IllegalArgumentException iae) {
+            iae.printStackTrace();
+            exceptionThrown = true;
+        }
+        if (!exceptionThrown) {
+            throw new RuntimeException("IllegalArgumentException not thrown");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/JavaServiceTagTest.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug     6622366
+ * @summary Basic Test for ServiceTag.getJavaServiceTag()
+ *          Disable creating the service tag in the system registry.
+ *          Verify the existence of registration.xml file and the
+ *          content of the service tag.
+ * @author  Mandy Chung
+ *
+ * @run build JavaServiceTagTest
+ * @run main JavaServiceTagTest
+ */
+
+import com.sun.servicetag.*;
+import java.io.*;
+import java.util.*;
+
+public class JavaServiceTagTest {
+    public static void main(String[] argv) throws Exception {
+        String registrationDir = System.getProperty("test.classes");
+
+        // disable calling to stclient
+        System.setProperty("servicetag.sthelper.supported", "false");
+
+        if (Registry.isSupported()) {
+            throw new RuntimeException("Registry.isSupported() should " +
+                "return false");
+        }
+        // For debugging
+        // System.setProperty("servicetag.verbose", "");
+
+        // cleanup the registration.xml and servicetag file in the test directory
+        System.setProperty("servicetag.dir.path", registrationDir);
+        File regFile = new File(registrationDir, "registration.xml");
+        regFile.delete();
+        File svcTagFile = new File(registrationDir, "servicetag");
+        svcTagFile.delete();
+
+        ServiceTag svctag = ServiceTag.getJavaServiceTag("JavaServiceTagTest");
+        checkServiceTag(svctag);
+
+        if (svcTagFile.exists()) {
+            throw new RuntimeException(svcTagFile + " should not exist.");
+        }
+
+        // registration.xml should be created
+        if (!regFile.exists()) {
+            throw new RuntimeException(regFile + " not created.");
+        }
+        BufferedInputStream in = new BufferedInputStream(new FileInputStream(regFile));
+        RegistrationData registration = RegistrationData.loadFromXML(in);
+        Set<ServiceTag> c = registration.getServiceTags();
+        if (c.size() != 1) {
+            throw new RuntimeException(regFile + " has " + c.size() +
+                " service tags. Expected 1.");
+        }
+        ServiceTag st = registration.getServiceTag(svctag.getInstanceURN());
+        if (!Util.matches(st, svctag)) {
+            throw new RuntimeException("ServiceTag " +
+                " doesn't match.");
+        }
+    }
+
+    private static void checkServiceTag(ServiceTag st) throws IOException {
+        Properties props = loadSwordfishEntries();
+        if (st.getProductURN().
+                equals(props.getProperty("servicetag.jdk.urn"))) {
+            if (!st.getProductName().
+                    equals(props.getProperty("servicetag.jdk.name"))) {
+                throw new RuntimeException("Product URN and name don't match.");
+            }
+        } else if (st.getProductURN().
+                equals(props.getProperty("servicetag.jre.urn"))) {
+            if (!st.getProductName().
+                    equals(props.getProperty("servicetag.jre.name"))) {
+                throw new RuntimeException("Product URN and name don't match.");
+            }
+        } else {
+            throw new RuntimeException("Unexpected product_urn: " +
+                st.getProductURN());
+        }
+        if (!st.getProductVersion().
+                equals(System.getProperty("java.version"))) {
+            throw new RuntimeException("Unexpected product_version: " +
+                st.getProductVersion());
+        }
+        if (!st.getProductParent().
+                equals(props.getProperty("servicetag.parent.name"))) {
+            throw new RuntimeException("Unexpected product_parent: " +
+                st.getProductParent());
+        }
+        if (!st.getProductParentURN().
+                equals(props.getProperty("servicetag.parent.urn"))) {
+            throw new RuntimeException("Unexpected product_parent_urn: " +
+                st.getProductParentURN());
+        }
+        if (!st.getPlatformArch().
+                equals(System.getProperty("os.arch"))) {
+            throw new RuntimeException("Unexpected platform_arch: " +
+                st.getPlatformArch());
+        }
+        if (!st.getProductVendor().
+                equals("Sun Microsystems")) {
+            throw new RuntimeException("Unexpected product_vendor: " +
+                st.getProductVendor());
+        }
+        if (!st.getSource().
+                equals("JavaServiceTagTest")) {
+            throw new RuntimeException("Unexpected source: " +
+                st.getSource());
+        }
+        String[] ss = st.getProductDefinedInstanceID().split(",");
+        boolean id = false;
+        boolean dir = false;
+        for (String s : ss) {
+            String[] values = s.split("=");
+            if (values[0].equals("id")) {
+                id = true;
+                String[] sss = values[1].split(" ");
+                if (!sss[0].equals(System.getProperty("java.runtime.version"))) {
+                    throw new RuntimeException("Unexpected version in id: " +
+                        sss[0]);
+                }
+                if (sss.length < 2) {
+                    throw new RuntimeException("Unexpected id=" + values[1]);
+                }
+            } else if (values[0].equals("dir")) {
+                dir = true;
+            }
+        }
+        if (!id || !dir) {
+            throw new RuntimeException("Unexpected product_defined_instance_id: " +
+                st.getProductDefinedInstanceID());
+        }
+    }
+
+    private static Properties loadSwordfishEntries()
+           throws IOException {
+        int version = sun.misc.Version.jdkMinorVersion();
+        String filename = "/com/sun/servicetag/resources/javase_" +
+                version + "_swordfish.properties";
+        InputStream in = Installer.class.getClass().getResourceAsStream(filename);
+        Properties props = new Properties();
+        try {
+            props.load(in);
+        } finally {
+            in.close();
+        }
+        return props;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/JavaServiceTagTest1.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug     6622366
+ * @summary Basic Test for ServiceTag.getJavaServiceTag(String)
+ *          to verify that the registration.xml and servicetag files
+ *          are both created correctly.
+ * @author  Mandy Chung
+ *
+ * @run build JavaServiceTagTest1
+ * @run main JavaServiceTagTest1
+ */
+
+import com.sun.servicetag.*;
+import java.io.*;
+import java.util.*;
+
+public class JavaServiceTagTest1 {
+    private static String registrationDir = System.getProperty("test.classes");
+    private static String servicetagDir = System.getProperty("test.src");
+    private static File regFile;
+    private static File svcTagFile;
+    private static Registry registry;
+    public static void main(String[] argv) throws Exception {
+        // cleanup the registration.xml and servicetag file in the test directory
+        System.setProperty("servicetag.dir.path", registrationDir);
+        regFile = new File(registrationDir, "registration.xml");
+        regFile.delete();
+
+        svcTagFile = new File(registrationDir, "servicetag");
+        svcTagFile.delete();
+
+        registry = Util.getSvcTagClientRegistry();
+
+        // verify that only one service tag is created
+        ServiceTag st1 = testJavaServiceTag("Test1");
+
+        // getJavaServiceTag method should create a new service tag
+        // and delete the old one
+        ServiceTag st2 = testJavaServiceTag("Test2");
+        if (registry.getServiceTag(st1.getInstanceURN()) != null) {
+            throw new RuntimeException("instance_urn: " + st1.getInstanceURN() +
+                " exists but expected to be removed");
+        }
+
+        // expected to have different instance_urn
+        if (st1.getInstanceURN().equals(st2.getInstanceURN())) {
+            throw new RuntimeException("instance_urn: " + st1.getInstanceURN() +
+                " == " + st2.getInstanceURN());
+        }
+
+        // Delete the service tag from the Registry and the servicetag file
+        if (registry.removeServiceTag(st2.getInstanceURN()) == null) {
+            throw new RuntimeException("Failed to remove " +
+                st1.getInstanceURN() + " from the registry");
+        }
+        svcTagFile.delete();
+
+        // call the getJavaServiceTag(String) method again
+        // should create the servicetag file.
+        ServiceTag st3 = testJavaServiceTag("Test2");
+        if (!Util.matches(st2, st3)) {
+            System.out.println(st2);
+            System.out.println(st3);
+            throw new RuntimeException("Test Failed: Expected to be the same");
+        }
+
+    }
+
+    private static ServiceTag testJavaServiceTag(String source) throws Exception {
+        ServiceTag svctag = ServiceTag.getJavaServiceTag(source);
+        checkServiceTag(svctag, source);
+
+        // verify if registration.xml is created
+        if (!regFile.exists()) {
+            throw new RuntimeException(regFile + " not created.");
+        }
+
+        // verify the registration.xml content is the expected service tag
+        BufferedInputStream in = new BufferedInputStream(new FileInputStream(regFile));
+        RegistrationData registration = RegistrationData.loadFromXML(in);
+        Set<ServiceTag> c = registration.getServiceTags();
+        if (c.size() != 1) {
+            throw new RuntimeException(regFile + " has " + c.size() +
+                " service tags. Expected 1.");
+        }
+        ServiceTag st = registration.getServiceTag(svctag.getInstanceURN());
+        if (!Util.matches(st, svctag)) {
+            throw new RuntimeException("RegistrationData ServiceTag " +
+                " doesn't match.");
+        }
+
+        // verify the service tag added in the registry
+        st = registry.getServiceTag(svctag.getInstanceURN());
+        if (!Util.matches(st, svctag)) {
+            throw new RuntimeException("Registry ServiceTag " +
+                " doesn't match.");
+        }
+
+        // verify if servicetag file is created
+        if (!svcTagFile.exists()) {
+            throw new RuntimeException(svcTagFile + " not created.");
+        }
+
+        // verify that the servicetag file only contains one instance_urn
+        BufferedReader reader = new BufferedReader(new FileReader(svcTagFile));
+        int count = 0;
+        try {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                if (line.equals(svctag.getInstanceURN())) {
+                    count++;
+                } else {
+                    throw new RuntimeException("servicetag contains " +
+                        " unexpected instance_urn " + line);
+                }
+            }
+        } finally {
+            reader.close();
+        }
+        if (count != 1) {
+            throw new RuntimeException("servicetag contains unexpected " +
+                "number of instance_urn = " + count);
+        }
+        return svctag;
+    }
+
+    private static void checkServiceTag(ServiceTag st, String source)
+            throws IOException {
+        Properties props = loadSwordfishEntries();
+        if (st.getProductURN().
+                equals(props.getProperty("servicetag.jdk.urn"))) {
+            if (!st.getProductName().
+                    equals(props.getProperty("servicetag.jdk.name"))) {
+                throw new RuntimeException("Product URN and name don't match.");
+            }
+        } else if (st.getProductURN().
+                equals(props.getProperty("servicetag.jre.urn"))) {
+            if (!st.getProductName().
+                    equals(props.getProperty("servicetag.jre.name"))) {
+                throw new RuntimeException("Product URN and name don't match.");
+            }
+        } else {
+            throw new RuntimeException("Unexpected product_urn: " +
+                st.getProductURN());
+        }
+        if (!st.getProductVersion().
+                equals(System.getProperty("java.version"))) {
+            throw new RuntimeException("Unexpected product_version: " +
+                st.getProductVersion());
+        }
+        if (!st.getProductParent().
+                equals(props.getProperty("servicetag.parent.name"))) {
+            throw new RuntimeException("Unexpected product_parent: " +
+                st.getProductParent());
+        }
+        if (!st.getProductParentURN().
+                equals(props.getProperty("servicetag.parent.urn"))) {
+            throw new RuntimeException("Unexpected product_parent_urn: " +
+                st.getProductParentURN());
+        }
+        if (!st.getPlatformArch().
+                equals(System.getProperty("os.arch"))) {
+            throw new RuntimeException("Unexpected platform_arch: " +
+                st.getPlatformArch());
+        }
+        if (!st.getProductVendor().
+                equals("Sun Microsystems")) {
+            throw new RuntimeException("Unexpected product_vendor: " +
+                st.getProductVendor());
+        }
+        if (!st.getSource().
+                equals(source)) {
+            throw new RuntimeException("Unexpected source: " +
+                st.getSource() + " expected: " + source);
+        }
+        String[] ss = st.getProductDefinedInstanceID().split(",");
+        boolean id = false;
+        boolean dir = false;
+        for (String s : ss) {
+            String[] values = s.split("=");
+            if (values[0].equals("id")) {
+                id = true;
+                String[] sss = values[1].split(" ");
+                if (!sss[0].equals(System.getProperty("java.runtime.version"))) {
+                    throw new RuntimeException("Unexpected version in id: " +
+                        sss[0]);
+                }
+                if (sss.length < 2) {
+                    throw new RuntimeException("Unexpected id=" + values[1]);
+                }
+            } else if (values[0].equals("dir")) {
+                dir = true;
+            }
+        }
+        if (!id || !dir) {
+            throw new RuntimeException("Unexpected product_defined_instance_id: " +
+                st.getProductDefinedInstanceID());
+        }
+    }
+
+    private static Properties loadSwordfishEntries()
+           throws IOException {
+        int version = sun.misc.Version.jdkMinorVersion();
+        String filename = "/com/sun/servicetag/resources/javase_" +
+                version + "_swordfish.properties";
+        InputStream in = Installer.class.getClass().getResourceAsStream(filename);
+        Properties props = new Properties();
+        try {
+            props.load(in);
+        } finally {
+            in.close();
+        }
+        return props;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/NewRegistrationData.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug     6622366
+ * @summary Basic Test for Registration Data
+ * @author  Mandy Chung
+ *
+ * @run build NewRegistrationData Util
+ * @run main NewRegistrationData
+ */
+
+import com.sun.servicetag.*;
+import java.io.*;
+import java.util.*;
+
+public class NewRegistrationData {
+    private static RegistrationData regData;
+    private static Map<String, ServiceTag> stMap = new LinkedHashMap<String, ServiceTag>();
+    private static String[] files = new String[] {
+                                        "servicetag1.properties",
+                                        "servicetag2.properties",
+                                        "servicetag3.properties"
+                                    };
+
+    public static void main(String[] argv) throws Exception {
+        String regDataDir = System.getProperty("test.classes");
+        String servicetagDir = System.getProperty("test.src");
+
+        File reg = new File(regDataDir, "registration.xml");
+        // Make sure a brand new file is created
+        reg.delete();
+
+        regData = new RegistrationData();
+        if (regData.getRegistrationURN().isEmpty()) {
+            throw new RuntimeException("Empty registration urn");
+        }
+
+        int count = 0;
+        for (String f : files) {
+            addServiceTag(servicetagDir, f, ++count);
+        }
+
+        // check if the registration data contains all service tags
+        Set<ServiceTag> c = regData.getServiceTags();
+        for (ServiceTag st : c) {
+            if (!Util.matches(st, regData.getServiceTag(st.getInstanceURN()))) {
+                throw new RuntimeException("ServiceTag added in the regData " +
+                    " doesn't match.");
+            }
+        }
+
+        // store the service tag to a file
+        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(reg));
+        try {
+            regData.storeToXML(out);
+        } finally {
+            out.close();
+        }
+
+        Util.checkRegistrationData(reg.getCanonicalPath(), stMap);
+        System.out.println("Test passed: " + count + " service tags added");
+    }
+
+    private static void addServiceTag(String parent, String filename, int count) throws Exception {
+        File f = new File(parent, filename);
+        ServiceTag svcTag = Util.newServiceTag(f);
+        regData.addServiceTag(svcTag);
+        stMap.put(svcTag.getInstanceURN(), svcTag);
+
+        Set<ServiceTag> c = regData.getServiceTags();
+        if (c.size() != count) {
+            throw new RuntimeException("Invalid service tag count= " +
+                c.size() + " expected=" + count);
+        }
+        ServiceTag st = regData.getServiceTag(svcTag.getInstanceURN());
+        if (!Util.matches(st, svcTag)) {
+            throw new RuntimeException("ServiceTag added in the regData " +
+                " doesn't match.");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/SvcTagClient.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @bug     6622366
+ */
+
+import com.sun.servicetag.*;
+import java.io.*;
+import java.util.*;
+
+/**
+ * A utility class simulating stclient for testing purpose.
+ */
+public class SvcTagClient {
+    private static File xmlFile;
+    private static RegistrationData registration;
+    private static String instanceURN;
+    private static String productName;
+    private static String productVersion;
+    private static String productURN;
+    private static String productParent;
+    private static String productParentURN = ""; // optional
+    private static String productDefinedInstanceID = ""; //optional
+    private static String productVendor;
+    private static String platformArch;
+    private static String container;
+    private static String source;
+
+    // stclient exit value
+    private static final int ST_ERR_REC_NOT_FOUND = 225;
+
+    public static void main(String[] args) throws Exception {
+        String path = System.getProperty("stclient.registry.path");
+        if (path == null) {
+            System.err.println("stclient registry path missing");
+            System.exit(-1);
+        }
+        xmlFile = new File(path);
+        if (xmlFile.exists()) {
+            BufferedInputStream in = new BufferedInputStream(new FileInputStream(xmlFile));
+            registration = RegistrationData.loadFromXML(in);
+        } else {
+            registration = new RegistrationData();
+        }
+        boolean add = false;
+        boolean delete = false;
+        boolean update = false;
+        boolean get = false;
+        boolean find = false;
+
+        int count = 0;
+        while (count < args.length) {
+            String arg = args[count];
+            if (!arg.startsWith("-")) {
+                System.err.println("Invalid option:" + arg);
+                System.exit(-1);
+            }
+            if (arg.equals("-a")) {
+                add = true;
+            } else if (arg.equals("-d")) {
+                delete = true;
+            } else if (arg.equals("-u")) {
+                update = true;
+            } else if (arg.equals("-g")) {
+                get = true;
+            } else if (arg.equals("-f")) {
+                find = true;
+                productURN = "";
+            } else if (arg.equals("-t")) {
+                productURN = args[++count];
+            } else if (arg.equals("-i")) {
+                instanceURN = args[++count];
+            } else if (arg.equals("-p")) {
+                productName = args[++count];
+            } else if (arg.equals("-e")) {
+                productVersion = args[++count];
+            } else if (arg.equals("-t")) {
+                productURN = args[++count];
+            } else if (arg.equals("-F")) {
+                productParentURN = args[++count];
+            } else if (arg.equals("-P")) {
+                productParent = args[++count];
+            } else if (arg.equals("-I")) {
+                productDefinedInstanceID = args[++count];
+            } else if (arg.equals("-m")) {
+                productVendor = args[++count];
+            } else if (arg.equals("-A")) {
+                platformArch = args[++count];
+            } else if (arg.equals("-z")) {
+                container = args[++count];
+            } else if (arg.equals("-S")) {
+                source = args[++count];
+            } else {
+                System.err.println("Invalid option:" + arg);
+                System.exit(-1);
+            }
+            count++;
+        }
+
+        if (add) {
+            addServiceTag();
+        } else if (delete) {
+            deleteServiceTag();
+        } else if (update) {
+            updateServiceTag();
+        } else if (get) {
+            getServiceTag();
+        } else if (find) {
+            findServiceTags();
+        } else {
+            System.err.println("Error");
+            System.exit(-1);
+        }
+        updateXmlFile();
+    }
+    private static String OUTPUT = "Product instance URN=";
+
+    private static void addServiceTag() {
+        if (instanceURN == null) {
+            instanceURN = ServiceTag.generateInstanceURN();
+        }
+        ServiceTag st = ServiceTag.newInstance(instanceURN,
+                                               productName,
+                                               productVersion,
+                                               productURN,
+                                               productParent,
+                                               productParentURN,
+                                               productDefinedInstanceID,
+                                               productVendor,
+                                               platformArch,
+                                               container,
+                                               source);
+        registration.addServiceTag(st);
+        System.out.println(OUTPUT + st.getInstanceURN());
+    }
+
+    private static void deleteServiceTag() {
+        registration.removeServiceTag(instanceURN);
+        System.out.println("instance_urn=" + instanceURN + " deleted");
+    }
+
+    private static void updateServiceTag() {
+        registration.updateServiceTag(instanceURN, productDefinedInstanceID);
+        System.out.println("instance_urn=" + instanceURN + " updated");
+    }
+
+    private static void getServiceTag() {
+        ServiceTag st = registration.getServiceTag(instanceURN);
+        if (st == null) {
+            System.err.println("instance_urn=" + instanceURN + " not found");
+            System.exit(ST_ERR_REC_NOT_FOUND);
+        } else {
+            System.out.println(st);
+        }
+    }
+
+    private static void findServiceTags() {
+        Set<ServiceTag> set = registration.getServiceTags();
+        for (ServiceTag st : set) {
+            if (st.getProductURN().equals(productURN)) {
+                System.out.println(st.getInstanceURN());
+            }
+        }
+        if (set.size() == 0) {
+            System.out.println("No records found");
+            System.exit(ST_ERR_REC_NOT_FOUND);
+        }
+    }
+    private static void updateXmlFile() throws IOException {
+        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(xmlFile));
+        try {
+            registration.storeToXML(out);
+        } finally {
+            out.close();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/SystemRegistryTest.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug     6622366
+ * @summary Basic Test for registry class
+ *          by replacing stclient with SvcTagClient utility
+ * @author  Mandy Chung
+ *
+ * @run build SvcTagClient SystemRegistryTest Util
+ * @run main SystemRegistryTest
+ */
+
+import com.sun.servicetag.*;
+import java.io.*;
+import java.util.*;
+
+public class SystemRegistryTest {
+    private static String registryDir = System.getProperty("test.classes");
+    private static String servicetagDir = System.getProperty("test.src");
+    private static List<ServiceTag> list = new ArrayList<ServiceTag>();
+    private static String[] files = new String[] {
+                                        "servicetag1.properties",
+                                        "servicetag2.properties",
+                                        "servicetag3.properties"
+                                    };
+
+    private static Registry registry;
+    public static void main(String[] argv) throws Exception {
+        registry = Util.getSvcTagClientRegistry();
+
+        for (String filename : files) {
+            File f = new File(servicetagDir, filename);
+            ServiceTag svcTag = Util.newServiceTag(f);
+            ServiceTag st = registry.addServiceTag(svcTag);
+            list.add(st);
+            System.out.println(st);
+        }
+
+        testDuplicate(list.get(0));
+        testNotFound();
+
+        // remove a service tag
+        String urn = list.get(0).getInstanceURN();
+        ServiceTag svcTag = registry.removeServiceTag(urn);
+        if (!Util.matches(svcTag, list.get(0))) {
+           throw new RuntimeException(urn +
+               " deleted but does not match.");
+        }
+
+        // get a service tag
+        svcTag = list.get(1);
+        urn = svcTag.getInstanceURN();
+        ServiceTag st = registry.getServiceTag(urn);
+        if (!Util.matches(svcTag, st)) {
+           throw new RuntimeException(urn +
+               " returned from getServiceTag but does not match.");
+        }
+        // update the service tag
+        registry.updateServiceTag(urn, "My new defined ID");
+        st = registry.getServiceTag(urn);
+        if (Util.matches(svcTag, st)) {
+           throw new RuntimeException(urn +
+               " updated but expected to be different.");
+        }
+
+        if (!st.getProductDefinedInstanceID().equals("My new defined ID")) {
+            throw new RuntimeException("Invalid product_defined_instance_id " +
+                st.getProductDefinedInstanceID());
+        }
+        if (st.getInstallerUID() != -1) {
+            throw new RuntimeException("Invalid installer_uid " +
+                st.getInstallerUID());
+        }
+        if (st.getTimestamp().equals(svcTag.getTimestamp())) {
+            throw new RuntimeException("Timestamp " +
+                st.getTimestamp() + " == " + svcTag.getTimestamp());
+        }
+
+    }
+    private static void testDuplicate(ServiceTag st) throws IOException {
+        boolean dup = false;
+        try {
+           registry.addServiceTag(st);
+        } catch (IllegalArgumentException e) {
+           dup = true;
+        }
+        if (!dup) {
+           throw new RuntimeException(st.getInstanceURN() +
+               " added successfully but expected to be a duplicated.");
+        }
+    }
+
+    private static void testNotFound() throws Exception {
+        String instanceURN = "urn:st:721cf98a-f4d7-6231-bb1d-f2f5aa903ef7";
+        ServiceTag svctag = registry.removeServiceTag(instanceURN);
+        if (svctag != null) {
+           throw new RuntimeException(instanceURN +
+               " exists but expected not found");
+        }
+
+        svctag = registry.updateServiceTag(instanceURN, "testing");
+        if (svctag != null) {
+           throw new RuntimeException(instanceURN +
+               " exists but expected not found");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/TestLoadFromXML.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug     6622366
+ * @summary Basic Test for RegistrationData.loadFromXML
+ * @author  Mandy Chung
+ *
+ * @run build TestLoadFromXML
+ * @run main TestLoadFromXML
+ */
+
+import com.sun.servicetag.*;
+import java.io.*;
+import java.util.*;
+
+public class TestLoadFromXML {
+    public static void main(String[] argv) throws Exception {
+        String registrationDir = System.getProperty("test.classes");
+        String servicetagDir = System.getProperty("test.src");
+
+        File inFile = new File(servicetagDir, "registration.xml");
+        File outFile = new File(registrationDir, "out.xml");
+        BufferedInputStream in = new BufferedInputStream(new FileInputStream(inFile));
+        RegistrationData regData = RegistrationData.loadFromXML(in);
+        boolean closed = false;
+        try {
+           in.read();
+        } catch (IOException e) {
+           // expect the InputStream is closed
+           closed = true;
+           System.out.println("*** Expected IOException ***");
+           e.printStackTrace();
+        }
+        if (!closed) {
+           throw new RuntimeException("InputStream not closed after " +
+               "RegistrationData.loadFromXML() call");
+        }
+
+        BufferedOutputStream out =
+            new BufferedOutputStream(new FileOutputStream(outFile));
+        regData.storeToXML(out);
+        // should be able to write to the OutputStream
+        out.write(0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/UpdateServiceTagTest.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug     6622366
+ * @summary Basic Test for RegistrationData.updateServiceTag
+ * @author  Mandy Chung
+ *
+ * @run build UpdateServiceTagTest Util
+ * @run main UpdateServiceTagTest
+ */
+
+import com.sun.servicetag.*;
+import java.io.*;
+import java.util.*;
+
+public class UpdateServiceTagTest {
+    private static String servicetagDir = System.getProperty("test.src");
+    private static String[] files = new String[] {
+                                        "servicetag1.properties",
+                                        "servicetag2.properties",
+                                        "servicetag3.properties"
+                                    };
+    private static RegistrationData registration = new RegistrationData();
+    private static Set<ServiceTag> set = new HashSet<ServiceTag>();
+
+    public static void main(String[] argv) throws Exception {
+        for (String f : files) {
+            ServiceTag st = addServiceTag(f);
+            set.add(st);
+        }
+        Thread.sleep(1000);
+        for (ServiceTag st : set) {
+            updateServiceTag(st);
+        }
+    }
+
+    private static ServiceTag addServiceTag(String filename) throws Exception {
+        File f = new File(servicetagDir, filename);
+        ServiceTag svcTag = Util.newServiceTag(f, true /* no instance_urn */);
+        ServiceTag st = registration.addServiceTag(svcTag);
+        if (!Util.matchesNoInstanceUrn(svcTag, st)) {
+            throw new RuntimeException("ServiceTag " +
+                " doesn't match.");
+        }
+        String urn = st.getInstanceURN();
+        if (!urn.startsWith("urn:st:")) {
+            throw new RuntimeException("Invalid generated instance_urn " +
+                urn);
+        }
+        if (st.getInstallerUID() != -1) {
+            throw new RuntimeException("Invalid installer_uid " +
+                st.getInstallerUID());
+        }
+        if (st.getTimestamp() == null) {
+            throw new RuntimeException("null timestamp ");
+        }
+        return st;
+    }
+
+    private static String newID = "New product defined instance ID";
+    private static void updateServiceTag(ServiceTag svcTag) throws Exception {
+        // update the service tag
+        String urn = svcTag.getInstanceURN();
+        registration.updateServiceTag(urn, newID);
+
+        // get the updated service tag
+        ServiceTag st = registration.getServiceTag(urn);
+        if (Util.matches(svcTag, st)) {
+            throw new RuntimeException("ServiceTag " +
+                " should not match.");
+        }
+        if (!st.getProductDefinedInstanceID().equals(newID)) {
+            throw new RuntimeException("Invalid product_defined_instance_id " +
+                st.getProductDefinedInstanceID());
+        }
+        if (st.getInstallerUID() != -1) {
+            throw new RuntimeException("Invalid installer_uid " +
+                st.getInstallerUID());
+        }
+        if (st.getTimestamp().equals(svcTag.getTimestamp())) {
+            throw new RuntimeException("Timestamp " +
+                st.getTimestamp() + " == " + svcTag.getTimestamp());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/Util.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @bug     6622366
+ * @summary Utility class used by other jtreg tests
+ */
+
+import com.sun.servicetag.RegistrationData;
+import com.sun.servicetag.ServiceTag;
+import com.sun.servicetag.Registry;
+
+import java.util.Set;
+import java.util.Date;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TimeZone;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.io.*;
+
+public class Util {
+    public static ServiceTag newServiceTag(File f)
+            throws FileNotFoundException, IOException, NumberFormatException {
+        return newServiceTag(f, false /* with instance_urn */);
+    }
+
+    public static ServiceTag newServiceTag(File f, boolean noInstanceURN)
+            throws FileNotFoundException, IOException, NumberFormatException {
+        Properties props = new Properties();
+        FileReader reader = new FileReader(f);
+        try {
+            props.load(reader);
+        } finally {
+            reader.close();
+        }
+        if (noInstanceURN) {
+            return ServiceTag.newInstance(
+                            props.getProperty("product_name"),
+                            props.getProperty("product_version"),
+                            props.getProperty("product_urn"),
+                            props.getProperty("product_parent"),
+                            props.getProperty("product_parent_urn"),
+                            props.getProperty("product_defined_inst_id"),
+                            props.getProperty("product_vendor"),
+                            props.getProperty("platform_arch"),
+                            props.getProperty("container"),
+                            props.getProperty("source"));
+        } else {
+            return ServiceTag.newInstance(
+                            props.getProperty("instance_urn"),
+                            props.getProperty("product_name"),
+                            props.getProperty("product_version"),
+                            props.getProperty("product_urn"),
+                            props.getProperty("product_parent"),
+                            props.getProperty("product_parent_urn"),
+                            props.getProperty("product_defined_inst_id"),
+                            props.getProperty("product_vendor"),
+                            props.getProperty("platform_arch"),
+                            props.getProperty("container"),
+                            props.getProperty("source"));
+        }
+    }
+
+    public static boolean matches(ServiceTag st1, ServiceTag st2) {
+        if (!st1.getInstanceURN().equals(st2.getInstanceURN())) {
+            System.out.println("instance_urn: " + st1.getInstanceURN() +
+                " != " + st2.getInstanceURN());
+            return false;
+        }
+        return matchesNoInstanceUrn(st1, st2);
+    }
+
+    public static boolean matchesNoInstanceUrn(ServiceTag st1, ServiceTag st2) {
+        if (!st1.getProductName().equals(st2.getProductName())) {
+            System.out.println("product_name: " + st1.getProductName() +
+                " != " + st2.getProductName());
+            return false;
+        }
+
+        if (!st1.getProductVersion().equals(st2.getProductVersion())) {
+            System.out.println("product_version: " + st1.getProductVersion() +
+                " != " + st2.getProductVersion());
+            return false;
+        }
+        if (!st1.getProductURN().equals(st2.getProductURN())) {
+            System.out.println("product_urn: " + st1.getProductURN() +
+                " != " + st2.getProductURN());
+            return false;
+        }
+        if (!st1.getProductParentURN().equals(st2.getProductParentURN())) {
+            System.out.println("product_parent_urn: " + st1.getProductParentURN() +
+                " != " + st2.getProductParentURN());
+            return false;
+        }
+        if (!st1.getProductParent().equals(st2.getProductParent())) {
+            System.out.println("product_parent: " + st1.getProductParent() +
+                " != " + st2.getProductParent());
+            return false;
+        }
+        if (!st1.getProductDefinedInstanceID().equals(st2.getProductDefinedInstanceID())) {
+            System.out.println("product_defined_inst_id: " +
+                st1.getProductDefinedInstanceID() +
+                " != " + st2.getProductDefinedInstanceID());
+            return false;
+        }
+        if (!st1.getProductVendor().equals(st2.getProductVendor())) {
+            System.out.println("product_vendor: " + st1.getProductVendor() +
+                " != " + st2.getProductVendor());
+            return false;
+        }
+        if (!st1.getPlatformArch().equals(st2.getPlatformArch())) {
+            System.out.println("platform_arch: " + st1.getPlatformArch() +
+                " != " + st2.getPlatformArch());
+            return false;
+        }
+        if (!st1.getContainer().equals(st2.getContainer())) {
+            System.out.println("container: " + st1.getContainer() +
+                " != " + st2.getContainer());
+            return false;
+        }
+        if (!st1.getSource().equals(st2.getSource())) {
+            System.out.println("source: " + st1.getSource() +
+                " != " + st2.getSource());
+            return false;
+        }
+        return true;
+    }
+
+    public static void checkRegistrationData(String regFile,
+                                             Map<String, ServiceTag> stMap)
+            throws IOException {
+        BufferedInputStream in = new BufferedInputStream(new FileInputStream(regFile));
+        RegistrationData registration = RegistrationData.loadFromXML(in);
+        Set<ServiceTag> svcTags = registration.getServiceTags();
+        if (svcTags.size() != stMap.size()) {
+            throw new RuntimeException("Invalid service tag count= " +
+                svcTags.size() + " expected=" + stMap.size());
+        }
+        for (ServiceTag st : svcTags) {
+            ServiceTag st1 = stMap.get(st.getInstanceURN());
+            if (!matches(st, st1)) {
+                throw new RuntimeException("ServiceTag in the registry " +
+                    "does not match the one in the map");
+            }
+        }
+    }
+
+
+    /**
+     * 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) {
+        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();
+        }
+    }
+
+    /**
+     * Returns the command simulating stclient behavior.
+     */
+    static String getSvcClientCommand(String stclientRegistry) {
+        String regDir = System.getProperty("test.classes");
+
+        StringBuilder sb = new StringBuilder();
+        // wrap each argument to the command with double quotes
+        sb.append("\"");
+        sb.append(System.getProperty("java.home"));
+        sb.append(File.separator).append("bin");
+        sb.append(File.separator).append("java");
+        sb.append("\"");
+        sb.append(" -cp ");
+        sb.append("\"").append(regDir).append("\"");
+        sb.append(" \"-Dstclient.registry.path=");
+        sb.append(stclientRegistry).append("\"");
+        sb.append(" SvcTagClient");
+        return sb.toString();
+    }
+
+    private static Registry registry = null;
+    /**
+     * Returns the Registry processed by SvcTagClient that simulates
+     * stclient.
+     */
+    static synchronized Registry getSvcTagClientRegistry() throws IOException {
+        if (registry != null) {
+            return registry;
+        }
+
+        // System.setProperty("servicetag.verbose", "true");
+        // enable the helper class
+        System.setProperty("servicetag.sthelper.supported", "true");
+
+        // clean up registry.xml
+        String regDir = System.getProperty("test.classes");
+        File registryFile = new File(regDir, "registry.xml");
+        if (registryFile.exists()) {
+            registryFile.delete();
+        }
+
+        String stclientCmd = Util.getSvcClientCommand(registryFile.getCanonicalPath());
+        System.out.println("stclient cmd: " + stclientCmd);
+        System.setProperty("servicetag.stclient.cmd", stclientCmd);
+
+        // get the Registry object after the system properties are set
+        registry = Registry.getSystemRegistry();
+        return registry;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/ValidRegistrationData.java	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug     6622366
+ * @summary Basic Test for reading a valid registration
+ * @author  Mandy Chung
+ *
+ * @run build ValidRegistrationData
+ * @run main ValidRegistrationData
+ */
+
+import com.sun.servicetag.*;
+import java.io.*;
+import java.util.*;
+
+public class ValidRegistrationData {
+    private static String registrationDir = System.getProperty("test.classes");
+    private static String servicetagDir = System.getProperty("test.src");
+    private static RegistrationData registration;
+    private static Map<String, ServiceTag> stMap =
+        new LinkedHashMap<String, ServiceTag>();
+    private static String[] files = new String[] {
+                                        "servicetag1.properties",
+                                        "servicetag2.properties",
+                                        "servicetag3.properties"
+                                    };
+    private static String URN = "urn:st:9543ffaa-a4f1-4f77-b2d1-f561922d4e4a";
+
+    public static void main(String[] argv) throws Exception {
+        File f = new File(servicetagDir, "registration.xml");
+
+        // load the registration data with all service tags
+        BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));
+        registration = RegistrationData.loadFromXML(in);
+        if (!registration.getRegistrationURN().equals(URN)){
+            throw new RuntimeException("Invalid URN=" +
+                registration.getRegistrationURN());
+        }
+        Map<String,String> environMap = registration.getEnvironmentMap();
+        checkEnvironmentMap(environMap);
+
+        // set environment
+        setInvalidEnvironment("hostname", "");
+        setInvalidEnvironment("osName", "");
+        setInvalidEnvironment("invalid", "");
+    }
+
+    private static void checkEnvironmentMap(Map<String,String> envMap)
+            throws Exception {
+        Properties props = new Properties();
+        File f = new File(servicetagDir, "environ.properties");
+        FileReader reader = new FileReader(f);
+        try {
+            props.load(reader);
+        } finally {
+            reader.close();
+        }
+        for (Map.Entry<String,String> entry : envMap.entrySet()) {
+            String name = entry.getKey();
+            String value = entry.getValue();
+            String expected = props.getProperty(name);
+            if (expected == null || !value.equals(expected)) {
+                throw new RuntimeException("Invalid environment " +
+                    name + "=" + value);
+            }
+            props.remove(name);
+        }
+        if (!props.isEmpty()) {
+            System.out.println("Environment missing: ");
+            for (String s : props.stringPropertyNames()) {
+                System.out.println("   " + s + "=" + props.getProperty(s));
+            }
+            throw new RuntimeException("Invalid environment read");
+        }
+    }
+    private static void setInvalidEnvironment(String name, String value) {
+        boolean invalid = false;
+        try {
+            registration.setEnvironment(name, value);
+        } catch (IllegalArgumentException e) {
+            invalid = true;
+        }
+        if (!invalid) {
+           throw new RuntimeException(name + "=" + value +
+               " set but expected to fail.");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/environ.properties	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,9 @@
+hostname=ko
+hostId=83abc1ab
+osName=SunOS
+osVersion=5.10
+osArchitecture=sparc
+systemModel=Sun-Fire-V440
+systemManufacturer=Sun Microsystems
+cpuManufacturer=Sun Microsystems
+serialNumber=BEL078932
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/missing-environ-field.xml	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<registration_data version="1.0">
+<environment>
+<hostname>ko</hostname>
+<hostId/>
+<osName>SunOS</osName>
+<osVersion>5.10</osVersion>
+<osArchitecture>sparc</osArchitecture>
+<systemModel/>
+<systemManufacturer/>
+<cpuManufacturer/>
+</environment>
+<registry urn="urn:st:9b2c801f-89d5-431e-a930-1335a9049124" version="1.0">
+<service_tag>
+<instance_urn>urn:st:9efff93a-767c-4714-fcfa-c48988293110</instance_urn>
+<product_name>Java SE 6 Runtime Environment</product_name>
+<product_version>1.6.0-internal</product_version>
+<product_urn>urn:uuid:92d1de8c-1e59-42c6-a280-1c379526bcbc</product_urn>
+<product_parent_urn>urn:uuid:fdc90b21-018d-4cab-b866-612c7c119ed3</product_parent_urn>
+<product_parent>Java Platform Standard Edition 6 (Java SE 6)</product_parent>
+<product_defined_inst_id>id=1.6.0-internal-b00 sparc,dir=/myjdk/solaris-sparc</product_defined_inst_id>
+<product_vendor>Sun Microsystems</product_vendor>
+<platform_arch>sparc</platform_arch>
+<timestamp>2007-11-12 06:15:11 GMT</timestamp>
+<container>global</container>
+<source>servicetag1.properties</source>
+<installer_uid>121937</installer_uid>
+</service_tag>
+<service_tag>
+<instance_urn>urn:st:0e9712bf-4832-e315-8e40-c4b17ffac9a9</instance_urn>
+<product_name>Java SE 6 Development Kit</product_name>
+<product_version>1.6.0</product_version>
+<product_urn>urn:uuid:b58ef9a8-5ae8-11db-a023-080020a9ed93</product_urn>
+<product_parent_urn>urn:uuid:fdc90b21-018d-4cab-b866-612c7c119ed3</product_parent_urn>
+<product_parent>Java Platform Standard Edition 6 (Java SE 6)</product_parent>
+<product_defined_inst_id>id=1.6.0_05-b01 sparc,dir=/myjdk/solaris-i586</product_defined_inst_id>
+<product_vendor>Sun Microsystems</product_vendor>
+<platform_arch>i386</platform_arch>
+<timestamp>2007-11-12 06:15:11 GMT</timestamp>
+<container>global</container>
+<source>servicetag2.properties</source>
+<installer_uid>121937</installer_uid>
+</service_tag>
+</registry>
+</registration_data>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/newer-registry-version.xml	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<registration_data version="1.0">
+<environment>
+<hostname>ko</hostname>
+<hostId/>
+<osName>SunOS</osName>
+<osVersion>5.10</osVersion>
+<osArchitecture>sparc</osArchitecture>
+<systemModel/>
+<systemManufacturer/>
+<cpuManufacturer/>
+<serialNumber/>
+</environment>
+<registry urn="urn:st:9543ffaa-a4f1-4f77-b2d1-f561922d4e4a" version="100.0">
+<service_tag>
+<instance_urn>urn:st:9efff93a-767c-4714-fcfa-c48988293110</instance_urn>
+<product_name>Java SE 6 Runtime Environment</product_name>
+<product_version>1.6.0-internal</product_version>
+<product_urn>urn:uuid:92d1de8c-1e59-42c6-a280-1c379526bcbc</product_urn>
+<product_parent_urn>urn:uuid:fdc90b21-018d-4cab-b866-612c7c119ed3</product_parent_urn>
+<product_parent>Java Platform Standard Edition 6 (Java SE 6)</product_parent>
+<product_defined_inst_id>id=1.6.0-internal-b00 sparc,dir=/myjdk/solaris-sparc</product_defined_inst_id>
+<product_vendor>Sun Microsystems</product_vendor>
+<platform_arch>sparc</platform_arch>
+<timestamp>2007-11-13 00:49:01 GMT</timestamp>
+<container>global</container>
+<source>servicetag1.properties</source>
+<installer_uid>121937</installer_uid>
+<NEW-FIELD/>
+</service_tag>
+</registry>
+</registration_data>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/registration.xml	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<registration_data version="1.0">
+<environment>
+<hostname>ko</hostname>
+<hostId>83abc1ab</hostId>
+<osName>SunOS</osName>
+<osVersion>5.10</osVersion>
+<osArchitecture>sparc</osArchitecture>
+<systemModel>Sun-Fire-V440</systemModel>
+<systemManufacturer>Sun Microsystems</systemManufacturer>
+<cpuManufacturer>Sun Microsystems</cpuManufacturer>
+<serialNumber>BEL078932</serialNumber>
+</environment>
+<registry urn="urn:st:9543ffaa-a4f1-4f77-b2d1-f561922d4e4a" version="1.0">
+<service_tag>
+<instance_urn>urn:st:9efff93a-767c-4714-fcfa-c48988293110</instance_urn>
+<product_name>Java SE 6 Runtime Environment</product_name>
+<product_version>1.6.0-internal</product_version>
+<product_urn>urn:uuid:92d1de8c-1e59-42c6-a280-1c379526bcbc</product_urn>
+<product_parent_urn>urn:uuid:fdc90b21-018d-4cab-b866-612c7c119ed3</product_parent_urn>
+<product_parent>Java Platform Standard Edition 6 (Java SE 6)</product_parent>
+<product_defined_inst_id>id=1.6.0-internal-b00 sparc,dir=/myjdk/solaris-sparc</product_defined_inst_id>
+<product_vendor>Sun Microsystems</product_vendor>
+<platform_arch>sparc</platform_arch>
+<timestamp>2007-11-13 00:49:01 GMT</timestamp>
+<container>global</container>
+<source>servicetag1.properties</source>
+<installer_uid>121937</installer_uid>
+</service_tag>
+<service_tag>
+<instance_urn>urn:st:0e9712bf-4832-e315-8e40-c4b17ffac9a9</instance_urn>
+<product_name>Java SE 6 Development Kit</product_name>
+<product_version>1.6.0</product_version>
+<product_urn>urn:uuid:b58ef9a8-5ae8-11db-a023-080020a9ed93</product_urn>
+<product_parent_urn>urn:uuid:fdc90b21-018d-4cab-b866-612c7c119ed3</product_parent_urn>
+<product_parent>Java Platform Standard Edition 6 (Java SE 6)</product_parent>
+<product_defined_inst_id>id=1.6.0_05-b01 i386,dir=/myjdk/solaris-i586</product_defined_inst_id>
+<product_vendor>Sun Microsystems</product_vendor>
+<platform_arch>i386</platform_arch>
+<timestamp>2007-11-13 00:49:01 GMT</timestamp>
+<container>global</container>
+<source>servicetag2.properties</source>
+<installer_uid>121937</installer_uid>
+</service_tag>
+<service_tag>
+<instance_urn>urn:st:8a6ff75e-21a4-c8d7-bbda-de2c971bd67d</instance_urn>
+<product_name>Solaris 10 Operating System</product_name>
+<product_version>10</product_version>
+<product_urn>urn:uuid:5005588c-36f3-11d6-9cec-fc96f718e113</product_urn>
+<product_parent_urn>urn:uuid:596ffcfa-63d5-11d7-9886-ac816a682f92</product_parent_urn>
+<product_parent>Solaris Operating System</product_parent>
+<product_defined_inst_id/>
+<product_vendor>Sun Microsystems</product_vendor>
+<platform_arch>sparc</platform_arch>
+<timestamp>2007-11-13 00:49:01 GMT</timestamp>
+<container>global</container>
+<source>servicetag3.properties</source>
+<installer_uid>212883</installer_uid>
+</service_tag>
+</registry>
+</registration_data>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/servicetag1.properties	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,13 @@
+instance_urn=urn:st:9efff93a-767c-4714-fcfa-c48988293110
+product_name=Java SE 6 Runtime Environment
+product_version=1.6.0-internal
+product_urn=urn:uuid:92d1de8c-1e59-42c6-a280-1c379526bcbc
+product_parent_urn=urn:uuid:fdc90b21-018d-4cab-b866-612c7c119ed3
+product_parent=Java Platform Standard Edition 6 (Java SE 6)
+product_defined_inst_id=id=1.6.0-internal-b00 sparc,dir=/myjdk/solaris-sparc
+product_vendor=Sun Microsystems
+platform_arch=sparc
+timestamp=2007-11-12 05:19:40 GMT
+container=global
+source=servicetag1.properties
+installer_uid=121937
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/servicetag2.properties	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,13 @@
+instance_urn=urn:st:0e9712bf-4832-e315-8e40-c4b17ffac9a9
+product_name=Java SE 6 Development Kit
+product_version=1.6.0
+product_urn=urn:uuid:b58ef9a8-5ae8-11db-a023-080020a9ed93
+product_parent_urn=urn:uuid:fdc90b21-018d-4cab-b866-612c7c119ed3
+product_parent=Java Platform Standard Edition 6 (Java SE 6)
+product_defined_inst_id=id=1.6.0_05-b01 i386,dir=/myjdk/solaris-i586
+product_vendor=Sun Microsystems
+platform_arch=i386
+timestamp=2007-11-12 06:12:21 GMT
+container=global
+source=servicetag2.properties
+installer_uid=121937
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/servicetag3.properties	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,13 @@
+instance_urn=urn:st:8a6ff75e-21a4-c8d7-bbda-de2c971bd67d
+product_name=Solaris 10 Operating System
+product_version=10
+product_urn=urn:uuid:5005588c-36f3-11d6-9cec-fc96f718e113
+product_parent_urn=urn:uuid:596ffcfa-63d5-11d7-9886-ac816a682f92
+product_parent=Solaris Operating System
+product_defined_inst_id=
+product_vendor=Sun Microsystems
+platform_arch=sparc
+timestamp=2007-06-20 22:07:11 GMT
+container=global
+source=servicetag3.properties
+installer_uid=212883
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/servicetag4.properties	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,13 @@
+instance_urn=urn:st:b8171b45-a087-47b3-92c8-f2d9fb34e8c2
+product_name=Java SE 6 Runtime Environment
+product_version=1.6.0_05
+product_urn=urn:uuid:92d1de8c-1e59-42c6-a280-1c379526bcbc
+product_parent_urn=urn:uuid:fdc90b21-018d-4cab-b866-612c7c119ed3
+product_parent=Java Platform Standard Edition 6 (Java SE 6)
+product_defined_inst_id=id=1.6.0_05-b01 amd64,dir=/myjdk/linux-amd64
+product_vendor=Sun Microsystems
+platform_arch=x64
+timestamp=2007-12-12 05:19:40 GMT
+container=global
+source=servicetag4.properties
+installer_uid=121937
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/servicetag/servicetag5.properties	Thu Oct 02 16:50:41 2008 -0700
@@ -0,0 +1,13 @@
+instance_urn=urn:st:1d4269a1-71e3-4e44-bc8f-3793da7928ed
+product_name=Java SE 6 Runtime Environment
+product_version=1.6.0_06
+product_urn=urn:uuid:92d1de8c-1e59-42c6-a280-1c379526bcbc
+product_parent_urn=urn:uuid:fdc90b21-018d-4cab-b866-612c7c119ed3
+product_parent=Java Platform Standard Edition 6 (Java SE 6)
+product_defined_inst_id=id=1.6.0_06-b06 i386,dir=/w/mchung/bundles/jdk1.6.0_05/jre
+product_vendor=Sun Microsystems
+platform_arch=x86
+timestamp=2007-11-29 17:59:42 GMT
+container=global
+source=servicetag5.properties
+installer_uid=-1