1 /*
2 (C) Copyright IBM Corp. 2006, 2013
3
4 THIS FILE IS PROVIDED UNDER THE TERMS OF THE ECLIPSE PUBLIC LICENSE
5 ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE
6 CONSTITUTES RECIPIENTS ACCEPTANCE OF THE AGREEMENT.
7
8 You can obtain a current copy of the Eclipse Public License from
9 http://www.opensource.org/licenses/eclipse-1.0.php
10
11 @author : Endre Bak, ebak@de.ibm.com
12 *
13 * Flag Date Prog Description
14 * -------------------------------------------------------------------------------
15 * 1565892 2006-12-04 ebak Make SBLIM client JSR48 compliant
16 * 1663270 2007-02-19 ebak Minor performance problems
17 * 1660756 2007-02-22 ebak Embedded object support
18 * 1689085 2007-04-10 ebak Embedded object enhancements for Pegasus
19 * 1720707 2007-05-17 ebak Conventional Node factory for CIM-XML SAX parser
20 * 1735614 2007-06-12 ebak Wrong ARRAYSIZE attribute handling in SAX/PULL
21 * 2003590 2008-06-30 blaschke-oss Change licensing from CPL to EPL
22 * 2038305 2008-08-14 blaschke-oss SAXException SBLIM Java Client V2.0.7
23 * 2524131 2009-01-21 raman_arora Upgrade client to JDK 1.5 (Phase 1)
24 * 2531371 2009-02-10 raman_arora Upgrade client to JDK 1.5 (Phase 2)
25 * 3513353 2012-03-30 blaschke-oss TCK: CIMDataType arrays must have length >= 1
26 * 3602604 2013-01-29 blaschke-oss Clean up SAXException messages
27 * 2605 2013-03-20 buccella SAX parser throws wrong exception
28 * 2693 2013-10-21 blaschke-oss ReturnValueNode allows invalid PARAMTYPE attribute
29 * 2702 2013-11-07 blaschke-oss Bad PROPERTY.ARRAY ARRAYSIZE generates NumberFormatException
30 * 2706 2013-11-11 blaschke-oss Bad PARAMETER.REFARRAY ARRAYSIZE generates NumberFormatException
31 */
32
33 package org.metricshub.wbem.sblim.cimclient.internal.cimxml.sax.node;
34
35 /*-
36 * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
37 * WBEM Java Client
38 * ჻჻჻჻჻჻
39 * Copyright 2023 - 2025 MetricsHub
40 * ჻჻჻჻჻჻
41 * Licensed under the Apache License, Version 2.0 (the "License");
42 * you may not use this file except in compliance with the License.
43 * You may obtain a copy of the License at
44 *
45 * http://www.apache.org/licenses/LICENSE-2.0
46 *
47 * Unless required by applicable law or agreed to in writing, software
48 * distributed under the License is distributed on an "AS IS" BASIS,
49 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
50 * See the License for the specific language governing permissions and
51 * limitations under the License.
52 * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
53 */
54
55 import org.metricshub.wbem.javax.cim.CIMDataType;
56 import org.metricshub.wbem.javax.cim.CIMFlavor;
57 import org.metricshub.wbem.sblim.cimclient.internal.cim.CIMHelper;
58 import org.metricshub.wbem.sblim.cimclient.internal.cimxml.sax.CIMObjectFactory;
59 import org.metricshub.wbem.sblim.cimclient.internal.cimxml.sax.NodeConstIf;
60 import org.metricshub.wbem.sblim.cimclient.internal.cimxml.sax.SAXSession;
61 import org.metricshub.wbem.sblim.cimclient.internal.util.MOF;
62 import org.xml.sax.Attributes;
63 import org.xml.sax.SAXException;
64
65 /**
66 * Class Node is the abstract base class of all parseable XML elements. It
67 * contains helper functions for the implementations.
68 */
69 public abstract class Node implements NodeConstIf {
70 private String iNameEnum;
71
72 private boolean iCompleted;
73
74 /**
75 * Ctor.
76 *
77 * @param pNameEnum
78 * The name of the node which must be a String constant which is
79 * defined inside this class (because the implementation compares
80 * by reference).
81 */
82 public Node(String pNameEnum) {
83 this.iNameEnum = pNameEnum;
84 }
85
86 /**
87 * getNodeName
88 *
89 * @return The name of the node. This name have to be one of the String
90 * constant defined in the class.
91 */
92 public String getNodeName() {
93 return this.iNameEnum;
94 }
95
96 /**
97 * The SAX ContentHandler implementation calls this method after testChild()
98 * and addChild() calls. The implementation must reset it's instance unless
99 * it implements NonVolatileIf
100 *
101 * @param pAttribs
102 * @param pSession
103 * - stores variables which are common for the whole SAX parsing
104 * session
105 * @throws SAXException
106 */
107 public abstract void init(Attributes pAttribs, SAXSession pSession) throws SAXException;
108
109 /**
110 * XML element's data have to be passed
111 *
112 * @param pData
113 * - String which is concatenated in SAX's
114 * DefaultHandler.characters() implementation.
115 * @throws SAXException
116 */
117 public abstract void parseData(String pData) throws SAXException;
118
119 /**
120 * It have to be called by SAX's DefaultHandler implementation when it
121 * detects a new child element (startElement()).
122 *
123 * @param pNodeNameEnum
124 * - the name of the child element, it must be one of the String
125 * constant defined in class Node, because the implementer
126 * subclasses uses reference based equals comparisons (==)
127 * @throws SAXException
128 * - It have to be thrown when the Node cannot have
129 * pNodeNameEnum named child Node.
130 */
131 public abstract void testChild(String pNodeNameEnum) throws SAXException;
132
133 /**
134 * It have to be called by SAX's DefaultHandler.endElement(). It's task is
135 * to check that the Element is built up correctly. The implementer function
136 * can do some post processing here. testCompletness
137 *
138 * @throws SAXException
139 * It must be thrown when the Node is not valid.
140 */
141 public abstract void testCompletness() throws SAXException;
142
143 /**
144 * Have to be called by SAX's DefaultHandler.endElement()
145 *
146 * @param pChild
147 * @throws SAXException
148 * - parent Nodes can make conversions here (e.g. type string
149 * into CIMDataType), failed operation should throw
150 * SAXException)
151 */
152 public abstract void childParsed(Node pChild) throws SAXException;
153
154 /**
155 * completed
156 *
157 * @return true if the parsing of the node is completed
158 */
159 public boolean isCompleted() {
160 return this.iCompleted;
161 }
162
163 /**
164 * Have to be called by SAX's DefaultHandler at endElement(), after calling
165 * testCompletness().
166 */
167 public void setCompleted() {
168 this.iCompleted = true;
169 }
170
171 /**
172 * When a Node instance is going to be reused, this function must be called
173 * before.
174 */
175 public void clearCompleted() {
176 this.iCompleted = false;
177 }
178
179 /**
180 * ENTITY % CIMName "NAME CDATA #REQUIRED"
181 *
182 * @param pAttribs
183 * @return String
184 * @throws SAXException
185 */
186 public static String getCIMName(Attributes pAttribs) throws SAXException {
187 String name = pAttribs.getValue("NAME");
188 if (name == null) throw new SAXException("NAME attribute not found!");
189 return name;
190 }
191
192 /**
193 * ENTITY % ClassName "CLASSNAME CDATA #REQUIRED"
194 *
195 * @param pAttribs
196 * @return String
197 * @throws SAXException
198 */
199 public static String getClassName(Attributes pAttribs) throws SAXException {
200 String name = pAttribs.getValue("CLASSNAME");
201 if (name == null) throw new SAXException("CLASSNAME attribute not found!");
202 return name;
203 }
204
205 /**
206 * ENTITY % ReferenceClass "REFERENCECLASS CDATA #IMPLIED"
207 *
208 * @param pAttribs
209 * @return String
210 */
211 public static String getReferenceClass(Attributes pAttribs) {
212 return pAttribs.getValue("REFERENCECLASS");
213 }
214
215 /**
216 * ENTITY % ClassOrigin "CLASSORIGIN CDATA #IMPLIED
217 *
218 * @param pAttribs
219 * @return String
220 */
221 public static String getClassOrigin(Attributes pAttribs) {
222 return pAttribs.getValue("CLASSORIGIN");
223 }
224
225 /**
226 * ENTITY % Propagated "PROPAGATED (true|false) 'false'" getPropagated
227 *
228 * @param pAttribs
229 * @return boolean
230 */
231 public static boolean getPropagated(Attributes pAttribs) {
232 String str = pAttribs.getValue("PROPAGATED");
233 return MOF.TRUE.equalsIgnoreCase(str);
234 }
235
236 /**
237 * ENTITY % ArraySize "ARRAYSIZE CDATA #IMPLIED"
238 *
239 * @param pAttribs
240 * @return int
241 * @throws SAXException
242 */
243 public static int getArraySize(Attributes pAttribs) throws SAXException {
244 String arraySizeStr = pAttribs.getValue("ARRAYSIZE");
245 // 0 - unbounded size
246 int size = 0;
247 try {
248 size = arraySizeStr == null || arraySizeStr.length() == 0 ? 0 : Integer.parseInt(arraySizeStr);
249 } catch (NumberFormatException e) {
250 throw new SAXException(arraySizeStr + " is not a valid ARRAYSIZE attribute!");
251 }
252 if (size < 0) throw new SAXException("ARRAYSIZE cannot be " + size + "!");
253 return size;
254 }
255
256 /**
257 * ENTITY % CIMType "TYPE
258 * (boolean|string|char16|uint8|sint8|uint16|sint16|uint32
259 * |sint32|uint64|sint64|datetime|real32|real64)" getCIMType
260 *
261 * @param pAttribs
262 * @param pOptional
263 * @return CIMDataType
264 * @throws SAXException
265 */
266 public static CIMDataType getCIMType(Attributes pAttribs, boolean pOptional) throws SAXException {
267 String typeStr = pAttribs.getValue("TYPE");
268 if (typeStr == null) {
269 if (pOptional) return null;
270 throw new SAXException("TYPE attribute not found!");
271 }
272 CIMDataType type = CIMObjectFactory.getType(typeStr);
273 if (type == null) throw new SAXException(typeStr + " is not a valid TYPE attribute!");
274 if (type.getType() == CIMDataType.REFERENCE) throw new SAXException("TYPE attribute cannot be \"reference\"!");
275 // Is it array?
276 // Yes if ISARRAY is true or ARRAYSIZE>-1.
277 boolean isArray = hasTrueAttribute(pAttribs, "ISARRAY");
278 String arraySizeStr = pAttribs.getValue("ARRAYSIZE");
279 int arraySize;
280 try {
281 arraySize =
282 (arraySizeStr == null || arraySizeStr.length() == 0 ? (isArray ? 0 : -1) : Integer.parseInt(arraySizeStr));
283 } catch (NumberFormatException e) {
284 throw new SAXException(arraySizeStr + " is not a valid ARRAYSIZE attribute!");
285 }
286 if (isArray || arraySize >= 0) {
287 if (arraySize > 0) return new CIMDataType(type.getType(), arraySize);
288 return CIMHelper.UnboundedArrayDataType(type.getType());
289 }
290 return type;
291 }
292
293 /**
294 * getCIMType(pAttribs, pOptional=false);
295 *
296 * @param pAttribs
297 * @return CIMDataType
298 * @throws SAXException
299 */
300 public static CIMDataType getCIMType(Attributes pAttribs) throws SAXException {
301 return getCIMType(pAttribs, false);
302 }
303
304 /**
305 * ENTITY % ParamType "PARAMTYPE (
306 * boolean|string|char16|uint8|sint8|uint16|sint16
307 * |uint32|sint32|uint64|sint64|datetime| real32|real64|reference)
308 *
309 * @param pAttribs
310 * @return CIMDataType
311 * @throws SAXException
312 */
313 public static CIMDataType getParamType(Attributes pAttribs) throws SAXException {
314 String typeStr = pAttribs.getValue("PARAMTYPE");
315 return CIMObjectFactory.getType(typeStr);
316 }
317
318 /**
319 * <pre>
320 * ENTITY % QualifierFlavor "
321 * OVERRIDABLE (true|false) 'true'
322 * TOSUBCLASS (true|false) 'true'
323 * TOINSTANCE (true|false) 'false'
324 * TRANSLATABLE (true|false) 'false'"
325 * </pre>
326 *
327 * @param pAttribs
328 * @return int - CIMFlavor bit mixture
329 */
330 public int getQualifierFlavor(Attributes pAttribs) {
331 int flavors = 0;
332 if (!getBoolAttribute(pAttribs, "OVERRIDABLE", true)) flavors |= CIMFlavor.DISABLEOVERRIDE;
333 if (!getBoolAttribute(pAttribs, "TOSUBCLASS", true)) flavors |= CIMFlavor.RESTRICTED;
334 if (getBoolAttribute(pAttribs, "TRANSLATABLE", false)) flavors |= CIMFlavor.TRANSLATE;
335 return flavors;
336 }
337
338 /**
339 * hasTrueAttribute
340 *
341 * @param pAttribs
342 * @param pName
343 * @return boolean
344 */
345 public static boolean hasTrueAttribute(Attributes pAttribs, String pName) {
346 return MOF.TRUE.equalsIgnoreCase(pAttribs.getValue(pName));
347 }
348
349 /**
350 * getBoolAttribute
351 *
352 * @param pAttribs
353 * @param pName
354 * @param pDefVal
355 * @return boolean
356 */
357 public static boolean getBoolAttribute(Attributes pAttribs, String pName, boolean pDefVal) {
358 String val = pAttribs.getValue(pName);
359 if (MOF.TRUE.equalsIgnoreCase(val)) return true;
360 if (MOF.FALSE.equalsIgnoreCase(val)) return false;
361 return pDefVal;
362 }
363
364 /**
365 * duplicatedNode
366 *
367 * @param pParsedNodeName
368 * @param pNewNodeName
369 * @throws SAXException
370 */
371 public void duplicatedNode(String pParsedNodeName, String pNewNodeName) throws SAXException {
372 throw new SAXException(
373 getNodeName() +
374 " has a " +
375 pParsedNodeName +
376 " child node which disallows an additional " +
377 pNewNodeName +
378 " child node!"
379 );
380 }
381
382 /**
383 * illegalChildNodePair
384 *
385 * @param pNodeName0
386 * @param pNodeName1
387 * @throws SAXException
388 */
389 public void illegalChildNodePair(String pNodeName0, String pNodeName1) throws SAXException {
390 throw new SAXException(
391 pNodeName0 + ", " + pNodeName1 + " child node pair is illegal for " + getNodeName() + " node!"
392 );
393 }
394 }