001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package com.sun.servicetag;
043:
044: import java.io.*;
045: import java.net.UnknownHostException;
046: import java.util.Collection;
047: import java.util.Collections;
048: import java.util.HashSet;
049: import java.util.LinkedHashMap;
050: import java.util.Map;
051: import java.util.Set;
052:
053: import static com.sun.servicetag.RegistrationDocument.*;
054:
055: /**
056: * A {@code RegistrationData} object is a container of one or more
057: * {@link #getServiceTags service tags} that identify the
058: * components for product registration.
059: * Each {@code RegistrationData} object has a {@link #getRegistrationURN
060: * uniform resource name} (URN) as its identifier.
061: * <a name="EnvMap"></a>
062: * It also has an <i>environment map</i> with
063: * the following elements:
064: * <blockquote>
065: * <table border=0>
066: * <tr>
067: * <td><tt>hostname</tt></td>
068: * <td>Hostname of the system</td>
069: * <td>e.g. woody</td>
070: * </tr>
071: * <tr>
072: * <td><tt>hostId</tt></td>
073: * <td>Host ID of the system</td>
074: * <td>e.g. 83abc1ab</td>
075: * </tr>
076: * <tr>
077: * <td><tt>osName</tt></td>
078: * <td>Operating system name</td>
079: * <td> e.g. SunOS</td>
080: * </tr>
081: * <tr>
082: * <td><tt>osVersion</tt></td>
083: * <td>Operating system version</td>
084: * <td> e.g. 5.10</td>
085: * </tr>
086: * <tr>
087: * <td><tt>osArchitecture</tt></td>
088: * <td>Operating system architecture</td>
089: * <td> e.g. sparc</td>
090: * </tr>
091: * <tr>
092: * <td><tt>systemModel</tt></td>
093: * <td>System model</td>
094: * <td> e.g. SUNW,Sun-Fire-V440</td>
095: * </tr>
096: * <tr>
097: * <td><tt>systemManufacturer</tt></td>
098: * <td>System manufacturer</td>
099: * <td> e.g. Sun Microsystems</td>
100: * </tr>
101: * <tr>
102: * <td><tt>cpuManufacturer</tt></td>
103: * <td>CPU manufacturer</td>
104: * <td> e.g. Sun Microsystems</td>
105: * </tr>
106: * <tr>
107: * <td><tt>serialNumber</tt></td>
108: * <td>System serial number</td>
109: * <td> e.g. BEL078932</td>
110: * </tr>
111: * </table>
112: * </blockquote>
113: * The <tt>hostname</tt> and <tt>osName</tt> element must have a non-empty value.
114: * If an element is not available on a system and their value will be
115: * empty.
116: * <p>
117: * <a name="XMLSchema">
118: * <b>Registration XML Schema</b></a>
119: * <p>
120: * A {@code RegistrationData} object can be {@link #loadFromXML loaded} from
121: * and {@link #storeToXML stored} into an XML file in the format described
122: * by the
123: * <a href="https://sn-tools.central.sun.com/twiki/pub/ServiceTags/RegistrationRelayService/product_registration.xsd">
124: * registration data schema</a>. The registration data schema is defined by the
125: * Service Tags Technology.
126: * <p>
127: * Typically the registration data is constructed at installation time
128: * and stored in an XML file for later service tag lookup or registration.
129: *
130: * <p>
131: * <b>Example Usage</b>
132: * <p>
133: * The examples below show how the {@code RegistrationData} can be
134: * used for product registration.
135: * Exception handling is not shown in these examples for clarity.
136: * <ol>
137: * <li>This example shows how the JDK creates a JDK service tag, installs it
138: * in the system service tag registry and adds it to the registration data.
139: * <br>
140: * <blockquote><pre>
141: * // create a service tag object with an instance_urn
142: * ServiceTag st = ServiceTag.newInstance(ServiceTag.generateInstanceURN(),
143: * ....);
144: * // Adds to the system service tag registry if supported
145: * if (Registry.isSupported()) {
146: * Registry.getSystemRegistry().addServiceTag(st);
147: * }
148: *
149: * // add to the registration data
150: * RegistrationData registration = new RegistrationData();
151: * registration.addServiceTag(st);
152: * </pre></blockquote>
153: * </li>
154: * <li>At this point, the registration data is ready to
155: * send to Sun Connection for registration. This example shows how to register
156: * the JDK via the <i>Registration Relay Service</i>.
157: * <p>
158: * There are several registration services for Sun Connection. For example,
159: * the <a href="https://sn-tools.central.sun.com/twiki/bin/view/ServiceTags/RegistrationRelayService">
160: * Registration Relay Service</a> is a web application interface that
161: * processes the registration data payload sent via HTTP post
162: * and hosts the registration user interface for a specified
163: * registration URL. Refer to the
164: * Registration Relay Service Specification for details.
165: * <p>
166: * <blockquote><pre>
167: * // Open the connection to the URL of the registration service
168: * HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
169: * con.setDoInput(true);
170: * con.setDoOutput(true);
171: * con.setUseCaches(false);
172: * con.setAllowUserInteraction(false);
173: * con.setRequestMethod("POST");
174: * con.setRequestProperty("Content-Type", "text/xml;charset=\"utf-8\"");
175: * con.connect();
176: *
177: * // send the registration data to the registration service
178: * OutputStream out = con.getOutputStream();
179: * registration.storeToXML(out);
180: * out.close();
181: * </pre></blockquote>
182: * </li>
183: * <li>This example shows how to store the registration data in an XML file.
184: * for later service tag lookup or registration.
185: * <br>
186: * <blockquote><pre>
187: * BufferedOutputStream out = new BufferedOutputStream(
188: * new FileOutputStream(""<JAVA_HOME>/lib/servicetag/registration.xml"));
189: * registration.storeToXML(out);
190: * out.close();
191: * </pre></blockquote>
192: * </li>
193: * <li>This example shows how to install service tags that are in the
194: * registration data in the system service tag registry when determined
195: * to be available. The system service tag registry might not have existed
196: * when the registration data was constructed.
197: * <br>
198: * <blockquote><pre>
199: * if (Registry.isSupported()) {
200: * Set<ServiceTag> svctags = registration.getServiceTags();
201: * for (ServiceTag st : svctags) {
202: * Registry.getSystemRegistry().addServiceTag(st);
203: * }
204: * }
205: * </pre></blockquote>
206: * </li>
207: * </ol>
208: *
209: * @see <a href="https://sunconnection.sun.com/inventory">Sun Connection Inventory Channel</a>
210: */
211: public class RegistrationData {
212: private final Map<String, String> environment;
213: private final Map<String, ServiceTag> svcTagMap;
214: private final String urn;
215:
216: /**
217: * Creates a {@code RegistrationData} object with a generated
218: * {@link #getRegistrationURN registration URN}.
219: * The following keys in the {@link #getEnvironmentMap environment map}
220: * will be initialized for the configuration of the
221: * running system:
222: * <blockquote>
223: * <tt>hostname</tt>, <tt>osName</tt>, <tt>osVersion</tt> and
224: * <tt>osArchitecture</tt>
225: * </blockquote>
226: * and the value of other keys may be empty.
227: */
228: public RegistrationData() {
229: this (Util.generateURN());
230: }
231:
232: // package private
233: RegistrationData(String urn) {
234: this .urn = urn;
235: this .environment = initEnvironment();
236: this .svcTagMap = new LinkedHashMap<String, ServiceTag>();
237: }
238:
239: private Map<String, String> initEnvironment() {
240: Map<String, String> map = new LinkedHashMap<String, String>();
241: SystemEnvironment sysEnv = SystemEnvironment
242: .getSystemEnvironment();
243: map.put(ST_NODE_HOSTNAME, sysEnv.getHostname());
244: map.put(ST_NODE_HOST_ID, sysEnv.getHostId());
245: map.put(ST_NODE_OS_NAME, sysEnv.getOsName());
246: map.put(ST_NODE_OS_VERSION, sysEnv.getOsVersion());
247: map.put(ST_NODE_OS_ARCH, sysEnv.getOsArchitecture());
248: map.put(ST_NODE_SYSTEM_MODEL, sysEnv.getSystemModel());
249: map.put(ST_NODE_SYSTEM_MANUFACTURER, sysEnv
250: .getSystemManufacturer());
251: map.put(ST_NODE_CPU_MANUFACTURER, sysEnv.getCpuManufacturer());
252: map.put(ST_NODE_SERIAL_NUMBER, sysEnv.getSerialNumber());
253: return map;
254: }
255:
256: /**
257: * Returns the uniform resource name of this registration data
258: * in this format:
259: * <tt>urn:st:<32-char {@link java.util.UUID uuid}></tt>
260: *
261: * @return the URN of this registration data.
262: */
263: public String getRegistrationURN() {
264: return urn;
265: }
266:
267: /**
268: * Returns a map containing the environment information for this
269: * registration data. See the set of <a href="#EnvMap">keys</a>
270: * in the environment map. Subsequent update to the environment
271: * map via the {@link #setEnvironment setEnvironment} method will not be reflected
272: * in the returned map.
273: *
274: * @return an environment map for this registration data.
275: */
276: public Map<String, String> getEnvironmentMap() {
277: return new LinkedHashMap<String, String>(environment);
278: }
279:
280: /**
281: * Sets an element of the specified {@code name} in the environment map
282: * with the given {@code value}.
283: *
284: * @throws IllegalArgumentException if {@code name} is not a valid key
285: * in the environment map, or {@code value} is not valid.
286: */
287: public void setEnvironment(String name, String value) {
288: if (name == null) {
289: throw new NullPointerException("name is null");
290: }
291: if (value == null) {
292: throw new NullPointerException("value is null");
293: }
294: if (environment.containsKey(name)) {
295: if (name.equals(ST_NODE_HOSTNAME)
296: || name.equals(ST_NODE_OS_NAME)) {
297: if (value.length() == 0) {
298: throw new IllegalArgumentException("\"" + name
299: + "\" requires non-empty value.");
300: }
301: }
302: environment.put(name, value);
303: } else {
304: throw new IllegalArgumentException("\"" + name
305: + "\" is not an environment element.");
306: }
307: }
308:
309: /**
310: * Returns all service tags in this registration data.
311: *
312: * @return a {@link Set Set} of the service tags
313: * in this registration data.
314: */
315: public Set<ServiceTag> getServiceTags() {
316: return new HashSet<ServiceTag>(svcTagMap.values());
317: }
318:
319: /**
320: * Adds a service tag to this registration data.
321: * If the given service tag has an empty <tt>instance_urn</tt>,
322: * this method will generate a URN and place it in the copy
323: * of the service tag in this registration data.
324: * This method will return the {@code ServiceTag} object
325: * added to this registration data.
326: *
327: * @param st {@code ServiceTag} object to be added.
328: * @return a {@code ServiceTag} object added to this registration data.
329: *
330: * @throws IllegalArgumentException if
331: * a service tag of the same {@link ServiceTag#getInstanceURN
332: * <tt>instance_urn</tt>} already exists in the registry.
333: */
334: public synchronized ServiceTag addServiceTag(ServiceTag st) {
335: ServiceTag svcTag = ServiceTag.newInstanceWithUrnTimestamp(st);
336:
337: String instanceURN = svcTag.getInstanceURN();
338: if (svcTagMap.containsKey(instanceURN)) {
339: throw new IllegalArgumentException("Instance_urn = "
340: + instanceURN
341: + " already exists in the registration data.");
342: } else {
343: svcTagMap.put(instanceURN, svcTag);
344: }
345: return svcTag;
346: }
347:
348: /**
349: * Returns a service tag of the given <tt>instance_urn</tt> in this registration
350: * data.
351: *
352: * @param instanceURN the <tt>instance_urn</tt> of the service tag
353: * @return the {@code ServiceTag} object of the given <tt>instance_urn</tt>
354: * if exists; otherwise return {@code null}.
355: */
356: public synchronized ServiceTag getServiceTag(String instanceURN) {
357: if (instanceURN == null) {
358: throw new NullPointerException("instanceURN is null");
359: }
360: return svcTagMap.get(instanceURN);
361: }
362:
363: /**
364: * Removes a service tag of the given <tt>instance_urn</tt> from this
365: * registration data.
366: *
367: * @param instanceURN the <tt>instance_urn</tt> of
368: * the service tag to be removed.
369: *
370: * @return the removed {@code ServiceTag} object;
371: * or {@code null} if the service tag does not exist in this
372: * registration data.
373: */
374: public synchronized ServiceTag removeServiceTag(String instanceURN) {
375: if (instanceURN == null) {
376: throw new NullPointerException("instanceURN is null");
377: }
378:
379: ServiceTag svcTag = null;
380: if (svcTagMap.containsKey(instanceURN)) {
381: svcTag = svcTagMap.remove(instanceURN);
382: }
383: return svcTag;
384: }
385:
386: /**
387: * Updates the <tt>product_defined_instance_id</tt> in the service tag
388: * of the given <tt>instance_urn</tt> in this registration data.
389: *
390: * @param instanceURN the <tt>instance_urn</tt> of the service tag to be updated.
391: * @param productDefinedInstanceID the value of the
392: * <tt>product_defined_instance_id</tt> to be set.
393: *
394: * @return the updated {@code ServiceTag} object;
395: * or {@code null} if the service tag does not exist in this
396: * registration data.
397: */
398: public synchronized ServiceTag updateServiceTag(String instanceURN,
399: String productDefinedInstanceID) {
400: ServiceTag svcTag = getServiceTag(instanceURN);
401: if (svcTag == null) {
402: return null;
403: }
404:
405: svcTag = ServiceTag.newInstanceWithUrnTimestamp(svcTag);
406: // update the product defined instance ID field
407: svcTag.setProductDefinedInstanceID(productDefinedInstanceID);
408: svcTagMap.put(instanceURN, svcTag);
409: return svcTag;
410: }
411:
412: /**
413: * Reads the registration data from the XML document on the
414: * specified input stream. The XML document must be
415: * in the format described by the <a href="#XMLSchema">
416: * registration data schema</a>.
417: * The specified stream is closed after this method returns.
418: *
419: * @param in the input stream from which to read the XML document.
420: * @return a {@code RegistrationData} object read from the input
421: * stream.
422: *
423: * @throws IllegalArgumentException if the input stream
424: * contains an invalid registration data.
425: *
426: * @throws IOException if an error occurred when reading from the input stream.
427: */
428: public static RegistrationData loadFromXML(InputStream in)
429: throws IOException {
430: try {
431: return RegistrationDocument.load(in);
432: } finally {
433: in.close();
434: }
435: }
436:
437: /**
438: * Writes the registration data to the specified output stream
439: * in the format described by the <a href="#XMLSchema">
440: * registration data schema</a> with "UTF-8" encoding.
441: * The specified stream remains open after this method returns.
442: *
443: * @param os the output stream on which to write the XML document.
444: *
445: * @throws IOException if an error occurred when writing to the output stream.
446: */
447: public void storeToXML(OutputStream os) throws IOException {
448: RegistrationDocument.store(os, this );
449: os.flush();
450: }
451:
452: /**
453: * Returns a newly allocated byte array containing the registration
454: * data in XML format.
455: *
456: * @return a newly allocated byte array containing the registration
457: * data in XML format.
458: */
459: public byte[] toXML() {
460: try {
461: ByteArrayOutputStream out = new ByteArrayOutputStream();
462: storeToXML(out);
463: return out.toByteArray();
464: } catch (IOException e) {
465: // should not reach here
466: return new byte[0];
467: }
468: }
469:
470: /**
471: * Returns a string representation of this registration data in XML
472: * format.
473: *
474: * @return a string representation of this registration data in XML
475: * format.
476: */
477: @Override
478: public String toString() {
479: try {
480: ByteArrayOutputStream out = new ByteArrayOutputStream();
481: storeToXML(out);
482: return out.toString("UTF-8");
483: } catch (IOException e) {
484: // should not reach here
485: return "Error creating the return string.";
486: }
487: }
488: }
|