1 /* |
|
2 * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 package com.sun.servicetag; |
|
27 |
|
28 import java.io.*; |
|
29 import java.net.UnknownHostException; |
|
30 import java.util.Collection; |
|
31 import java.util.Collections; |
|
32 import java.util.HashSet; |
|
33 import java.util.LinkedHashMap; |
|
34 import java.util.Map; |
|
35 import java.util.Set; |
|
36 |
|
37 import static com.sun.servicetag.RegistrationDocument.*; |
|
38 |
|
39 /** |
|
40 * A {@code RegistrationData} object is a container of one or more |
|
41 * {@link #getServiceTags service tags} that identify the |
|
42 * components for product registration. |
|
43 * Each {@code RegistrationData} object has a {@link #getRegistrationURN |
|
44 * uniform resource name} (URN) as its identifier. |
|
45 * <a name="EnvMap"></a> |
|
46 * It also has an <i>environment map</i> with |
|
47 * the following elements: |
|
48 * <blockquote> |
|
49 * <table border=0> |
|
50 * <tr> |
|
51 * <td><tt>hostname</tt></td> |
|
52 * <td>Hostname of the system</td> |
|
53 * <td>e.g. woody</td> |
|
54 * </tr> |
|
55 * <tr> |
|
56 * <td><tt>hostId</tt></td> |
|
57 * <td>Host ID of the system</td> |
|
58 * <td>e.g. 83abc1ab</td> |
|
59 * </tr> |
|
60 * <tr> |
|
61 * <td><tt>osName</tt></td> |
|
62 * <td>Operating system name</td> |
|
63 * <td> e.g. SunOS</td> |
|
64 * </tr> |
|
65 * <tr> |
|
66 * <td><tt>osVersion</tt></td> |
|
67 * <td>Operating system version</td> |
|
68 * <td> e.g. 5.10</td> |
|
69 * </tr> |
|
70 * <tr> |
|
71 * <td><tt>osArchitecture</tt></td> |
|
72 * <td>Operating system architecture</td> |
|
73 * <td> e.g. sparc</td> |
|
74 * </tr> |
|
75 * <tr> |
|
76 * <td><tt>systemModel</tt></td> |
|
77 * <td>System model</td> |
|
78 * <td> e.g. SUNW,Sun-Fire-V440</td> |
|
79 * </tr> |
|
80 * <tr> |
|
81 * <td><tt>systemManufacturer</tt></td> |
|
82 * <td>System manufacturer</td> |
|
83 * <td> e.g. Oracle Corporation</td> |
|
84 * </tr> |
|
85 * <tr> |
|
86 * <td><tt>cpuManufacturer</tt></td> |
|
87 * <td>CPU manufacturer</td> |
|
88 * <td> e.g. Oracle Corporation</td> |
|
89 * </tr> |
|
90 * <tr> |
|
91 * <td><tt>serialNumber</tt></td> |
|
92 * <td>System serial number</td> |
|
93 * <td> e.g. BEL078932</td> |
|
94 * </tr> |
|
95 * </table> |
|
96 * </blockquote> |
|
97 * The <tt>hostname</tt> and <tt>osName</tt> element must have a non-empty value. |
|
98 * If an element is not available on a system and their value will be |
|
99 * empty. |
|
100 * <p> |
|
101 * <a name="XMLSchema"> |
|
102 * <b>Registration XML Schema</b></a> |
|
103 * <p> |
|
104 * A {@code RegistrationData} object can be {@link #loadFromXML loaded} from |
|
105 * and {@link #storeToXML stored} into an XML file in the format described |
|
106 * by the |
|
107 * <a href="https://sn-tools.central.sun.com/twiki/pub/ServiceTags/RegistrationRelayService/product_registration.xsd"> |
|
108 * registration data schema</a>. The registration data schema is defined by the |
|
109 * Service Tags Technology. |
|
110 * <p> |
|
111 * Typically the registration data is constructed at installation time |
|
112 * and stored in an XML file for later service tag lookup or registration. |
|
113 * |
|
114 * <p> |
|
115 * <b>Example Usage</b> |
|
116 * <p> |
|
117 * The examples below show how the {@code RegistrationData} can be |
|
118 * used for product registration. |
|
119 * Exception handling is not shown in these examples for clarity. |
|
120 * <ol> |
|
121 * <li>This example shows how the JDK creates a JDK service tag, installs it |
|
122 * in the system service tag registry and adds it to the registration data. |
|
123 * <br> |
|
124 * <blockquote><pre> |
|
125 * // create a service tag object with an instance_urn |
|
126 * ServiceTag st = ServiceTag.newInstance(ServiceTag.generateInstanceURN(), |
|
127 * ....); |
|
128 * // Adds to the system service tag registry if supported |
|
129 * if (Registry.isSupported()) { |
|
130 * Registry.getSystemRegistry().addServiceTag(st); |
|
131 * } |
|
132 * |
|
133 * // add to the registration data |
|
134 * RegistrationData registration = new RegistrationData(); |
|
135 * registration.addServiceTag(st); |
|
136 * </pre></blockquote> |
|
137 * </li> |
|
138 * <li>At this point, the registration data is ready to |
|
139 * send to Sun Connection for registration. This example shows how to register |
|
140 * the JDK via the <i>Registration Relay Service</i>. |
|
141 * <p> |
|
142 * There are several registration services for Sun Connection. For example, |
|
143 * the <a href="https://sn-tools.central.sun.com/twiki/bin/view/ServiceTags/RegistrationRelayService"> |
|
144 * Registration Relay Service</a> is a web application interface that |
|
145 * processes the registration data payload sent via HTTP post |
|
146 * and hosts the registration user interface for a specified |
|
147 * registration URL. Refer to the |
|
148 * Registration Relay Service Specification for details. |
|
149 * <p> |
|
150 * <blockquote><pre> |
|
151 * // Open the connection to the URL of the registration service |
|
152 * HttpsURLConnection con = (HttpsURLConnection) url.openConnection(); |
|
153 * con.setDoInput(true); |
|
154 * con.setDoOutput(true); |
|
155 * con.setUseCaches(false); |
|
156 * con.setAllowUserInteraction(false); |
|
157 * con.setRequestMethod("POST"); |
|
158 * con.setRequestProperty("Content-Type", "text/xml;charset=\"utf-8\""); |
|
159 * con.connect(); |
|
160 * |
|
161 * // send the registration data to the registration service |
|
162 * OutputStream out = con.getOutputStream(); |
|
163 * registration.storeToXML(out); |
|
164 * out.close(); |
|
165 * </pre></blockquote> |
|
166 * </li> |
|
167 * <li>This example shows how to store the registration data in an XML file. |
|
168 * for later service tag lookup or registration. |
|
169 * <br> |
|
170 * <blockquote><pre> |
|
171 * BufferedOutputStream out = new BufferedOutputStream( |
|
172 * new FileOutputStream(""<JAVA_HOME>/lib/servicetag/registration.xml")); |
|
173 * registration.storeToXML(out); |
|
174 * out.close(); |
|
175 * </pre></blockquote> |
|
176 * </li> |
|
177 * <li>This example shows how to install service tags that are in the |
|
178 * registration data in the system service tag registry when determined |
|
179 * to be available. The system service tag registry might not have existed |
|
180 * when the registration data was constructed. |
|
181 * <br> |
|
182 * <blockquote><pre> |
|
183 * if (Registry.isSupported()) { |
|
184 * Set<ServiceTag> svctags = registration.getServiceTags(); |
|
185 * for (ServiceTag st : svctags) { |
|
186 * Registry.getSystemRegistry().addServiceTag(st); |
|
187 * } |
|
188 * } |
|
189 * </pre></blockquote> |
|
190 * </li> |
|
191 * </ol> |
|
192 * |
|
193 * @see <a href="https://sunconnection.sun.com/inventory">Sun Connection Inventory Channel</a> |
|
194 */ |
|
195 public class RegistrationData { |
|
196 private final Map<String, String> environment = initEnvironment(); |
|
197 private final Map<String, ServiceTag> svcTagMap = |
|
198 new LinkedHashMap<String, ServiceTag>(); |
|
199 private final String urn; |
|
200 |
|
201 /** |
|
202 * Creates a {@code RegistrationData} object with a generated |
|
203 * {@link #getRegistrationURN registration URN}. |
|
204 * The following keys in the {@link #getEnvironmentMap environment map} |
|
205 * will be initialized for the configuration of the |
|
206 * running system: |
|
207 * <blockquote> |
|
208 * <tt>hostname</tt>, <tt>osName</tt>, <tt>osVersion</tt> and |
|
209 * <tt>osArchitecture</tt> |
|
210 * </blockquote> |
|
211 * and the value of other keys may be empty. |
|
212 */ |
|
213 public RegistrationData() { |
|
214 this(Util.generateURN()); |
|
215 SystemEnvironment sysEnv = SystemEnvironment.getSystemEnvironment(); |
|
216 setEnvironment(ST_NODE_HOSTNAME, sysEnv.getHostname()); |
|
217 setEnvironment(ST_NODE_HOST_ID, sysEnv.getHostId()); |
|
218 setEnvironment(ST_NODE_OS_NAME, sysEnv.getOsName()); |
|
219 setEnvironment(ST_NODE_OS_VERSION, sysEnv.getOsVersion()); |
|
220 setEnvironment(ST_NODE_OS_ARCH, sysEnv.getOsArchitecture()); |
|
221 setEnvironment(ST_NODE_SYSTEM_MODEL, sysEnv.getSystemModel()); |
|
222 setEnvironment(ST_NODE_SYSTEM_MANUFACTURER, sysEnv.getSystemManufacturer()); |
|
223 setEnvironment(ST_NODE_CPU_MANUFACTURER, sysEnv.getCpuManufacturer()); |
|
224 setEnvironment(ST_NODE_SERIAL_NUMBER, sysEnv.getSerialNumber()); |
|
225 } |
|
226 |
|
227 // package private |
|
228 RegistrationData(String urn) { |
|
229 this.urn = urn; |
|
230 } |
|
231 |
|
232 private Map<String, String> initEnvironment() { |
|
233 Map<String, String> map = new LinkedHashMap<String, String>(); |
|
234 map.put(ST_NODE_HOSTNAME, ""); |
|
235 map.put(ST_NODE_HOST_ID, ""); |
|
236 map.put(ST_NODE_OS_NAME, ""); |
|
237 map.put(ST_NODE_OS_VERSION, ""); |
|
238 map.put(ST_NODE_OS_ARCH, ""); |
|
239 map.put(ST_NODE_SYSTEM_MODEL, ""); |
|
240 map.put(ST_NODE_SYSTEM_MANUFACTURER, ""); |
|
241 map.put(ST_NODE_CPU_MANUFACTURER, ""); |
|
242 map.put(ST_NODE_SERIAL_NUMBER, ""); |
|
243 return map; |
|
244 } |
|
245 |
|
246 /** |
|
247 * Returns the uniform resource name of this registration data |
|
248 * in this format: |
|
249 * <tt>urn:st:<32-char {@link java.util.UUID uuid}></tt> |
|
250 * |
|
251 * @return the URN of this registration data. |
|
252 */ |
|
253 public String getRegistrationURN() { |
|
254 return urn; |
|
255 } |
|
256 |
|
257 /** |
|
258 * Returns a map containing the environment information for this |
|
259 * registration data. See the set of <a href="#EnvMap">keys</a> |
|
260 * in the environment map. Subsequent update to the environment |
|
261 * map via the {@link #setEnvironment setEnvironment} method will not be reflected |
|
262 * in the returned map. |
|
263 * |
|
264 * @return an environment map for this registration data. |
|
265 */ |
|
266 public Map<String, String> getEnvironmentMap() { |
|
267 return new LinkedHashMap<String,String>(environment); |
|
268 } |
|
269 |
|
270 /** |
|
271 * Sets an element of the specified {@code name} in the environment map |
|
272 * with the given {@code value}. |
|
273 * |
|
274 * @throws IllegalArgumentException if {@code name} is not a valid key |
|
275 * in the environment map, or {@code value} is not valid. |
|
276 */ |
|
277 public void setEnvironment(String name, String value) { |
|
278 if (name == null) { |
|
279 throw new NullPointerException("name is null"); |
|
280 } |
|
281 if (value == null) { |
|
282 throw new NullPointerException("value is null"); |
|
283 } |
|
284 if (environment.containsKey(name)) { |
|
285 if (name.equals(ST_NODE_HOSTNAME) || name.equals(ST_NODE_OS_NAME)) { |
|
286 if (value.length() == 0) { |
|
287 throw new IllegalArgumentException("\"" + |
|
288 name + "\" requires non-empty value."); |
|
289 } |
|
290 } |
|
291 environment.put(name, value); |
|
292 } else { |
|
293 throw new IllegalArgumentException("\"" + |
|
294 name + "\" is not an environment element."); |
|
295 } |
|
296 } |
|
297 |
|
298 /** |
|
299 * Returns all service tags in this registration data. |
|
300 * |
|
301 * @return a {@link Set Set} of the service tags |
|
302 * in this registration data. |
|
303 */ |
|
304 public Set<ServiceTag> getServiceTags() { |
|
305 return new HashSet<ServiceTag>(svcTagMap.values()); |
|
306 } |
|
307 |
|
308 /** |
|
309 * Adds a service tag to this registration data. |
|
310 * If the given service tag has an empty <tt>instance_urn</tt>, |
|
311 * this method will generate a URN and place it in the copy |
|
312 * of the service tag in this registration data. |
|
313 * This method will return the {@code ServiceTag} object |
|
314 * added to this registration data. |
|
315 * |
|
316 * @param st {@code ServiceTag} object to be added. |
|
317 * @return a {@code ServiceTag} object added to this registration data. |
|
318 * |
|
319 * @throws IllegalArgumentException if |
|
320 * a service tag of the same {@link ServiceTag#getInstanceURN |
|
321 * <tt>instance_urn</tt>} already exists in the registry. |
|
322 */ |
|
323 public synchronized ServiceTag addServiceTag(ServiceTag st) { |
|
324 ServiceTag svcTag = ServiceTag.newInstanceWithUrnTimestamp(st); |
|
325 |
|
326 String instanceURN = svcTag.getInstanceURN(); |
|
327 if (svcTagMap.containsKey(instanceURN)) { |
|
328 throw new IllegalArgumentException("Instance_urn = " + instanceURN + |
|
329 " already exists in the registration data."); |
|
330 } else { |
|
331 svcTagMap.put(instanceURN, svcTag); |
|
332 } |
|
333 return svcTag; |
|
334 } |
|
335 |
|
336 /** |
|
337 * Returns a service tag of the given <tt>instance_urn</tt> in this registration |
|
338 * data. |
|
339 * |
|
340 * @param instanceURN the <tt>instance_urn</tt> of the service tag |
|
341 * @return the {@code ServiceTag} object of the given <tt>instance_urn</tt> |
|
342 * if exists; otherwise return {@code null}. |
|
343 */ |
|
344 public synchronized ServiceTag getServiceTag(String instanceURN) { |
|
345 if (instanceURN == null) { |
|
346 throw new NullPointerException("instanceURN is null"); |
|
347 } |
|
348 return svcTagMap.get(instanceURN); |
|
349 } |
|
350 |
|
351 /** |
|
352 * Removes a service tag of the given <tt>instance_urn</tt> from this |
|
353 * registration data. |
|
354 * |
|
355 * @param instanceURN the <tt>instance_urn</tt> of |
|
356 * the service tag to be removed. |
|
357 * |
|
358 * @return the removed {@code ServiceTag} object; |
|
359 * or {@code null} if the service tag does not exist in this |
|
360 * registration data. |
|
361 */ |
|
362 public synchronized ServiceTag removeServiceTag(String instanceURN) { |
|
363 if (instanceURN == null) { |
|
364 throw new NullPointerException("instanceURN is null"); |
|
365 } |
|
366 |
|
367 ServiceTag svcTag = null; |
|
368 if (svcTagMap.containsKey(instanceURN)) { |
|
369 svcTag = svcTagMap.remove(instanceURN); |
|
370 } |
|
371 return svcTag; |
|
372 } |
|
373 |
|
374 /** |
|
375 * Updates the <tt>product_defined_instance_id</tt> in the service tag |
|
376 * of the given <tt>instance_urn</tt> in this registration data. |
|
377 * |
|
378 * @param instanceURN the <tt>instance_urn</tt> of the service tag to be updated. |
|
379 * @param productDefinedInstanceID the value of the |
|
380 * <tt>product_defined_instance_id</tt> to be set. |
|
381 * |
|
382 * @return the updated {@code ServiceTag} object; |
|
383 * or {@code null} if the service tag does not exist in this |
|
384 * registration data. |
|
385 */ |
|
386 public synchronized ServiceTag updateServiceTag(String instanceURN, |
|
387 String productDefinedInstanceID) { |
|
388 ServiceTag svcTag = getServiceTag(instanceURN); |
|
389 if (svcTag == null) { |
|
390 return null; |
|
391 } |
|
392 |
|
393 svcTag = ServiceTag.newInstanceWithUrnTimestamp(svcTag); |
|
394 // update the product defined instance ID field |
|
395 svcTag.setProductDefinedInstanceID(productDefinedInstanceID); |
|
396 svcTagMap.put(instanceURN, svcTag); |
|
397 return svcTag; |
|
398 } |
|
399 |
|
400 /** |
|
401 * Reads the registration data from the XML document on the |
|
402 * specified input stream. The XML document must be |
|
403 * in the format described by the <a href="#XMLSchema"> |
|
404 * registration data schema</a>. |
|
405 * The specified stream is closed after this method returns. |
|
406 * |
|
407 * @param in the input stream from which to read the XML document. |
|
408 * @return a {@code RegistrationData} object read from the input |
|
409 * stream. |
|
410 * |
|
411 * @throws IllegalArgumentException if the input stream |
|
412 * contains an invalid registration data. |
|
413 * |
|
414 * @throws IOException if an error occurred when reading from the input stream. |
|
415 */ |
|
416 public static RegistrationData loadFromXML(InputStream in) throws IOException { |
|
417 try { |
|
418 return RegistrationDocument.load(in); |
|
419 } finally { |
|
420 in.close(); |
|
421 } |
|
422 } |
|
423 |
|
424 /** |
|
425 * Writes the registration data to the specified output stream |
|
426 * in the format described by the <a href="#XMLSchema"> |
|
427 * registration data schema</a> with "UTF-8" encoding. |
|
428 * The specified stream remains open after this method returns. |
|
429 * |
|
430 * @param os the output stream on which to write the XML document. |
|
431 * |
|
432 * @throws IOException if an error occurred when writing to the output stream. |
|
433 */ |
|
434 public void storeToXML(OutputStream os) throws IOException { |
|
435 RegistrationDocument.store(os, this); |
|
436 os.flush(); |
|
437 } |
|
438 |
|
439 /** |
|
440 * Returns a newly allocated byte array containing the registration |
|
441 * data in XML format. |
|
442 * |
|
443 * @return a newly allocated byte array containing the registration |
|
444 * data in XML format. |
|
445 */ |
|
446 public byte[] toXML() { |
|
447 try { |
|
448 ByteArrayOutputStream out = new ByteArrayOutputStream(); |
|
449 storeToXML(out); |
|
450 return out.toByteArray(); |
|
451 } catch (IOException e) { |
|
452 // should not reach here |
|
453 return new byte[0]; |
|
454 } |
|
455 } |
|
456 |
|
457 /** |
|
458 * Returns a string representation of this registration data in XML |
|
459 * format. |
|
460 * |
|
461 * @return a string representation of this registration data in XML |
|
462 * format. |
|
463 */ |
|
464 @Override |
|
465 public String toString() { |
|
466 try { |
|
467 ByteArrayOutputStream out = new ByteArrayOutputStream(); |
|
468 storeToXML(out); |
|
469 return out.toString("UTF-8"); |
|
470 } catch (IOException e) { |
|
471 // should not reach here |
|
472 return "Error creating the return string."; |
|
473 } |
|
474 } |
|
475 } |
|