View Javadoc
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 &quot;
321 	 * OVERRIDABLE    (true|false)  'true'
322 	 * TOSUBCLASS     (true|false)  'true'
323 	 * TOINSTANCE     (true|false)  'false'
324 	 * TRANSLATABLE   (true|false)  'false'&quot;
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 }