1 /* |
|
2 * Copyright (c) 2008, 2011, 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.URL; |
|
30 import java.util.Collection; |
|
31 import java.util.Map; |
|
32 import java.util.Set; |
|
33 |
|
34 import org.w3c.dom.Document; |
|
35 import org.w3c.dom.Element; |
|
36 import org.w3c.dom.Node; |
|
37 import org.w3c.dom.NodeList; |
|
38 import org.xml.sax.SAXException; |
|
39 import org.xml.sax.InputSource; |
|
40 |
|
41 import javax.xml.XMLConstants; |
|
42 import javax.xml.parsers.DocumentBuilder; |
|
43 import javax.xml.parsers.DocumentBuilderFactory; |
|
44 |
|
45 import javax.xml.parsers.ParserConfigurationException; |
|
46 import javax.xml.validation.Schema; |
|
47 import javax.xml.validation.SchemaFactory; |
|
48 import javax.xml.validation.Validator; |
|
49 |
|
50 // For write operation |
|
51 import javax.xml.transform.OutputKeys; |
|
52 import javax.xml.transform.Transformer; |
|
53 import javax.xml.transform.TransformerException; |
|
54 import javax.xml.transform.TransformerFactory; |
|
55 import javax.xml.transform.TransformerConfigurationException; |
|
56 import javax.xml.transform.dom.DOMSource; |
|
57 import javax.xml.transform.stream.StreamResult; |
|
58 |
|
59 /** |
|
60 * XML Support Class for Product Registration. |
|
61 */ |
|
62 class RegistrationDocument { |
|
63 |
|
64 private static final String REGISTRATION_DATA_SCHEMA = |
|
65 "/com/sun/servicetag/resources/product_registration.xsd"; |
|
66 private static final String REGISTRATION_DATA_VERSION = "1.0"; |
|
67 private static final String SERVICE_TAG_VERSION = "1.0"; |
|
68 final static String ST_NODE_REGISTRATION_DATA = "registration_data"; |
|
69 final static String ST_ATTR_REGISTRATION_VERSION = "version"; |
|
70 final static String ST_NODE_ENVIRONMENT = "environment"; |
|
71 final static String ST_NODE_HOSTNAME = "hostname"; |
|
72 final static String ST_NODE_HOST_ID = "hostId"; |
|
73 final static String ST_NODE_OS_NAME = "osName"; |
|
74 final static String ST_NODE_OS_VERSION = "osVersion"; |
|
75 final static String ST_NODE_OS_ARCH = "osArchitecture"; |
|
76 final static String ST_NODE_SYSTEM_MODEL = "systemModel"; |
|
77 final static String ST_NODE_SYSTEM_MANUFACTURER = "systemManufacturer"; |
|
78 final static String ST_NODE_CPU_MANUFACTURER = "cpuManufacturer"; |
|
79 final static String ST_NODE_SERIAL_NUMBER = "serialNumber"; |
|
80 final static String ST_NODE_REGISTRY = "registry"; |
|
81 final static String ST_ATTR_REGISTRY_URN = "urn"; |
|
82 final static String ST_ATTR_REGISTRY_VERSION = "version"; |
|
83 final static String ST_NODE_SERVICE_TAG = "service_tag"; |
|
84 final static String ST_NODE_INSTANCE_URN = "instance_urn"; |
|
85 final static String ST_NODE_PRODUCT_NAME = "product_name"; |
|
86 final static String ST_NODE_PRODUCT_VERSION = "product_version"; |
|
87 final static String ST_NODE_PRODUCT_URN = "product_urn"; |
|
88 final static String ST_NODE_PRODUCT_PARENT_URN = "product_parent_urn"; |
|
89 final static String ST_NODE_PRODUCT_PARENT = "product_parent"; |
|
90 final static String ST_NODE_PRODUCT_DEFINED_INST_ID = "product_defined_inst_id"; |
|
91 final static String ST_NODE_PRODUCT_VENDOR = "product_vendor"; |
|
92 final static String ST_NODE_PLATFORM_ARCH = "platform_arch"; |
|
93 final static String ST_NODE_TIMESTAMP = "timestamp"; |
|
94 final static String ST_NODE_CONTAINER = "container"; |
|
95 final static String ST_NODE_SOURCE = "source"; |
|
96 final static String ST_NODE_INSTALLER_UID = "installer_uid"; |
|
97 |
|
98 static RegistrationData load(InputStream in) throws IOException { |
|
99 Document document = initializeDocument(in); |
|
100 |
|
101 // Gets the registration URN |
|
102 Element root = getRegistrationDataRoot(document); |
|
103 Element registryRoot = |
|
104 getSingletonElementFromRoot(root, ST_NODE_REGISTRY); |
|
105 String urn = registryRoot.getAttribute(ST_ATTR_REGISTRY_URN); |
|
106 |
|
107 // Construct a new RegistrationData object from the DOM tree |
|
108 // Initialize the environment map and service tags |
|
109 RegistrationData regData = new RegistrationData(urn); |
|
110 addServiceTags(registryRoot, regData); |
|
111 |
|
112 Element envRoot = getSingletonElementFromRoot(root, ST_NODE_ENVIRONMENT); |
|
113 buildEnvironmentMap(envRoot, regData); |
|
114 return regData; |
|
115 } |
|
116 |
|
117 static void store(OutputStream os, RegistrationData registration) |
|
118 throws IOException { |
|
119 // create a new document with the root node |
|
120 Document document = initializeDocument(); |
|
121 |
|
122 // create the nodes for the environment map and the service tags |
|
123 // in the registration data |
|
124 addEnvironmentNodes(document, |
|
125 registration.getEnvironmentMap()); |
|
126 addServiceTagRegistry(document, |
|
127 registration.getRegistrationURN(), |
|
128 registration.getServiceTags()); |
|
129 transform(document, os); |
|
130 } |
|
131 |
|
132 // initialize a document from an input stream |
|
133 private static Document initializeDocument(InputStream in) throws IOException { |
|
134 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); |
|
135 try { |
|
136 // XML schema for validation |
|
137 SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); |
|
138 URL xsdUrl = RegistrationDocument.class.getResource(REGISTRATION_DATA_SCHEMA); |
|
139 Schema schema = sf.newSchema(xsdUrl); |
|
140 Validator validator = schema.newValidator(); |
|
141 |
|
142 DocumentBuilder builder = factory.newDocumentBuilder(); |
|
143 Document doc = builder.parse(new InputSource(in)); |
|
144 validator.validate(new DOMSource(doc)); |
|
145 return doc; |
|
146 } catch (SAXException sxe) { |
|
147 IllegalArgumentException e = new IllegalArgumentException("Error generated in parsing"); |
|
148 e.initCause(sxe); |
|
149 throw e; |
|
150 } catch (ParserConfigurationException pce) { |
|
151 // Parser with specific options can't be built |
|
152 // should not reach here |
|
153 throw new InternalError("Error in creating the new document", pce); |
|
154 } |
|
155 } |
|
156 |
|
157 // initialize a new document for the registration data |
|
158 private static Document initializeDocument() throws IOException { |
|
159 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); |
|
160 try { |
|
161 DocumentBuilder builder = factory.newDocumentBuilder(); |
|
162 Document doc = builder.newDocument(); |
|
163 |
|
164 // initialize the document with the registration_data root |
|
165 Element root = doc.createElement(ST_NODE_REGISTRATION_DATA); |
|
166 doc.appendChild(root); |
|
167 root.setAttribute(ST_ATTR_REGISTRATION_VERSION, REGISTRATION_DATA_VERSION); |
|
168 |
|
169 return doc; |
|
170 } catch (ParserConfigurationException pce) { |
|
171 // Parser with specified options can't be built |
|
172 // should not reach here |
|
173 throw new InternalError("Error in creating the new document", pce); |
|
174 } |
|
175 } |
|
176 |
|
177 // Transform the current DOM tree with the given output stream. |
|
178 private static void transform(Document document, OutputStream os) { |
|
179 try { |
|
180 // Use a Transformer for output |
|
181 TransformerFactory tFactory = TransformerFactory.newInstance(); |
|
182 tFactory.setAttribute("indent-number", new Integer(3)); |
|
183 |
|
184 Transformer transformer = tFactory.newTransformer(); |
|
185 |
|
186 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); |
|
187 transformer.setOutputProperty(OutputKeys.METHOD, "xml"); |
|
188 transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); |
|
189 transformer.setOutputProperty(OutputKeys.STANDALONE, "yes"); |
|
190 transformer.transform(new DOMSource(document), |
|
191 new StreamResult(new BufferedWriter(new OutputStreamWriter(os, "UTF-8")))); |
|
192 } catch (UnsupportedEncodingException ue) { |
|
193 // Should not reach here |
|
194 throw new InternalError("Error generated during transformation", ue); |
|
195 } catch (TransformerConfigurationException tce) { |
|
196 // Error generated by the parser |
|
197 // Should not reach here |
|
198 throw new InternalError("Error in creating the new document", tce); |
|
199 } catch (TransformerException te) { |
|
200 // Error generated by the transformer |
|
201 throw new InternalError("Error generated during transformation", te); |
|
202 } |
|
203 } |
|
204 |
|
205 private static void addServiceTagRegistry(Document document, |
|
206 String registryURN, |
|
207 Set<ServiceTag> svcTags) { |
|
208 // add service tag registry node and its attributes |
|
209 Element reg = document.createElement(ST_NODE_REGISTRY); |
|
210 reg.setAttribute(ST_ATTR_REGISTRY_URN, registryURN); |
|
211 reg.setAttribute(ST_ATTR_REGISTRY_VERSION, SERVICE_TAG_VERSION); |
|
212 |
|
213 Element root = getRegistrationDataRoot(document); |
|
214 root.appendChild(reg); |
|
215 |
|
216 // adds the elements for the service tags |
|
217 for (ServiceTag st : svcTags) { |
|
218 addServiceTagElement(document, reg, st); |
|
219 } |
|
220 } |
|
221 |
|
222 private static void addServiceTagElement(Document document, |
|
223 Element registryRoot, |
|
224 ServiceTag st) { |
|
225 Element svcTag = document.createElement(ST_NODE_SERVICE_TAG); |
|
226 registryRoot.appendChild(svcTag); |
|
227 addChildElement(document, svcTag, |
|
228 ST_NODE_INSTANCE_URN, st.getInstanceURN()); |
|
229 addChildElement(document, svcTag, |
|
230 ST_NODE_PRODUCT_NAME, st.getProductName()); |
|
231 addChildElement(document, svcTag, |
|
232 ST_NODE_PRODUCT_VERSION, st.getProductVersion()); |
|
233 addChildElement(document, svcTag, |
|
234 ST_NODE_PRODUCT_URN, st.getProductURN()); |
|
235 addChildElement(document, svcTag, |
|
236 ST_NODE_PRODUCT_PARENT_URN, st.getProductParentURN()); |
|
237 addChildElement(document, svcTag, |
|
238 ST_NODE_PRODUCT_PARENT, st.getProductParent()); |
|
239 addChildElement(document, svcTag, |
|
240 ST_NODE_PRODUCT_DEFINED_INST_ID, |
|
241 st.getProductDefinedInstanceID()); |
|
242 addChildElement(document, svcTag, |
|
243 ST_NODE_PRODUCT_VENDOR, st.getProductVendor()); |
|
244 addChildElement(document, svcTag, |
|
245 ST_NODE_PLATFORM_ARCH, st.getPlatformArch()); |
|
246 addChildElement(document, svcTag, |
|
247 ST_NODE_TIMESTAMP, Util.formatTimestamp(st.getTimestamp())); |
|
248 addChildElement(document, svcTag, |
|
249 ST_NODE_CONTAINER, st.getContainer()); |
|
250 addChildElement(document, svcTag, |
|
251 ST_NODE_SOURCE, st.getSource()); |
|
252 addChildElement(document, svcTag, |
|
253 ST_NODE_INSTALLER_UID, |
|
254 String.valueOf(st.getInstallerUID())); |
|
255 } |
|
256 |
|
257 private static void addChildElement(Document document, Element root, |
|
258 String element, String text) { |
|
259 Element node = document.createElement(element); |
|
260 node.appendChild(document.createTextNode(text)); |
|
261 root.appendChild(node); |
|
262 } |
|
263 |
|
264 // Constructs service tags from the document |
|
265 private static void addServiceTags(Element registryRoot, |
|
266 RegistrationData registration) { |
|
267 NodeList children = registryRoot.getElementsByTagName(ST_NODE_SERVICE_TAG); |
|
268 int length = (children == null ? 0 : children.getLength()); |
|
269 for (int i = 0; i < length; i++) { |
|
270 Element svcTagElement = (Element) children.item(i); |
|
271 ServiceTag st = getServiceTag(svcTagElement); |
|
272 registration.addServiceTag(st); |
|
273 } |
|
274 } |
|
275 |
|
276 // build environment map from the document |
|
277 private static void buildEnvironmentMap(Element envRoot, |
|
278 RegistrationData registration) { |
|
279 registration.setEnvironment(ST_NODE_HOSTNAME, getTextValue(envRoot, ST_NODE_HOSTNAME)); |
|
280 registration.setEnvironment(ST_NODE_HOST_ID, getTextValue(envRoot, ST_NODE_HOST_ID)); |
|
281 registration.setEnvironment(ST_NODE_OS_NAME, getTextValue(envRoot, ST_NODE_OS_NAME)); |
|
282 registration.setEnvironment(ST_NODE_OS_VERSION, getTextValue(envRoot, ST_NODE_OS_VERSION)); |
|
283 registration.setEnvironment(ST_NODE_OS_ARCH, getTextValue(envRoot, ST_NODE_OS_ARCH)); |
|
284 registration.setEnvironment(ST_NODE_SYSTEM_MODEL, getTextValue(envRoot, ST_NODE_SYSTEM_MODEL)); |
|
285 registration.setEnvironment(ST_NODE_SYSTEM_MANUFACTURER, getTextValue(envRoot, ST_NODE_SYSTEM_MANUFACTURER)); |
|
286 registration.setEnvironment(ST_NODE_CPU_MANUFACTURER, getTextValue(envRoot, ST_NODE_CPU_MANUFACTURER)); |
|
287 registration.setEnvironment(ST_NODE_SERIAL_NUMBER, getTextValue(envRoot, ST_NODE_SERIAL_NUMBER)); |
|
288 } |
|
289 |
|
290 // add the nodes representing the environment map in the document |
|
291 private static void addEnvironmentNodes(Document document, |
|
292 Map<String, String> envMap) { |
|
293 Element root = getRegistrationDataRoot(document); |
|
294 Element env = document.createElement(ST_NODE_ENVIRONMENT); |
|
295 root.appendChild(env); |
|
296 Set<Map.Entry<String, String>> keys = envMap.entrySet(); |
|
297 for (Map.Entry<String, String> entry : keys) { |
|
298 addChildElement(document, env, entry.getKey(), entry.getValue()); |
|
299 } |
|
300 } |
|
301 |
|
302 private static Element getRegistrationDataRoot(Document doc) { |
|
303 Element root = doc.getDocumentElement(); |
|
304 if (!root.getNodeName().equals(ST_NODE_REGISTRATION_DATA)) { |
|
305 throw new IllegalArgumentException("Not a " + |
|
306 ST_NODE_REGISTRATION_DATA + |
|
307 " node \"" + root.getNodeName() + "\""); |
|
308 } |
|
309 return root; |
|
310 } |
|
311 |
|
312 private static Element getSingletonElementFromRoot(Element root, String name) { |
|
313 NodeList children = root.getElementsByTagName(name); |
|
314 int length = (children == null ? 0 : children.getLength()); |
|
315 if (length != 1) { |
|
316 throw new IllegalArgumentException("Invalid number of " + name + |
|
317 " nodes = " + length); |
|
318 } |
|
319 Element e = (Element) children.item(0); |
|
320 if (!e.getNodeName().equals(name)) { |
|
321 throw new IllegalArgumentException("Not a " + name + |
|
322 " node \"" + e.getNodeName() + "\""); |
|
323 } |
|
324 return e; |
|
325 } |
|
326 |
|
327 // Constructs one ServiceTag instance from a service tag element root |
|
328 private static ServiceTag getServiceTag(Element svcTagElement) { |
|
329 return new ServiceTag( |
|
330 getTextValue(svcTagElement, ST_NODE_INSTANCE_URN), |
|
331 getTextValue(svcTagElement, ST_NODE_PRODUCT_NAME), |
|
332 getTextValue(svcTagElement, ST_NODE_PRODUCT_VERSION), |
|
333 getTextValue(svcTagElement, ST_NODE_PRODUCT_URN), |
|
334 getTextValue(svcTagElement, ST_NODE_PRODUCT_PARENT), |
|
335 getTextValue(svcTagElement, ST_NODE_PRODUCT_PARENT_URN), |
|
336 getTextValue(svcTagElement, ST_NODE_PRODUCT_DEFINED_INST_ID), |
|
337 getTextValue(svcTagElement, ST_NODE_PRODUCT_VENDOR), |
|
338 getTextValue(svcTagElement, ST_NODE_PLATFORM_ARCH), |
|
339 getTextValue(svcTagElement, ST_NODE_CONTAINER), |
|
340 getTextValue(svcTagElement, ST_NODE_SOURCE), |
|
341 Util.getIntValue(getTextValue(svcTagElement, ST_NODE_INSTALLER_UID)), |
|
342 Util.parseTimestamp(getTextValue(svcTagElement, ST_NODE_TIMESTAMP)) |
|
343 ); |
|
344 } |
|
345 |
|
346 private static String getTextValue(Element e, String tagName) { |
|
347 String value = ""; |
|
348 NodeList nl = e.getElementsByTagName(tagName); |
|
349 if (nl != null && nl.getLength() > 0) { |
|
350 Element el = (Element) nl.item(0); |
|
351 Node node = el.getFirstChild(); |
|
352 if (node != null) { |
|
353 value = node.getNodeValue(); |
|
354 } |
|
355 } |
|
356 return value; |
|
357 } |
|
358 } |
|