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   * 1720707    2007-05-17  ebak         Conventional Node factory for CIM-XML SAX parser
19   * 2003590    2008-06-30  blaschke-oss Change licensing from CPL to EPL
20   * 2524131    2009-01-21  raman_arora  Upgrade client to JDK 1.5 (Phase 1)
21   * 2531371    2009-02-10  raman_arora  Upgrade client to JDK 1.5 (Phase 2)
22   * 2763216    2009-04-14  blaschke-oss Code cleanup: visible spelling/grammar errors
23   *    2713    2013-11-22  blaschke-oss Enforce loose validation of CIM-XML documents
24   */
25  
26  package org.metricshub.wbem.sblim.cimclient.internal.cimxml.sax;
27  
28  /*-
29   * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
30   * WBEM Java Client
31   * ჻჻჻჻჻჻
32   * Copyright 2023 - 2025 MetricsHub
33   * ჻჻჻჻჻჻
34   * Licensed under the Apache License, Version 2.0 (the "License");
35   * you may not use this file except in compliance with the License.
36   * You may obtain a copy of the License at
37   *
38   *      http://www.apache.org/licenses/LICENSE-2.0
39   *
40   * Unless required by applicable law or agreed to in writing, software
41   * distributed under the License is distributed on an "AS IS" BASIS,
42   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
43   * See the License for the specific language governing permissions and
44   * limitations under the License.
45   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
46   */
47  
48  import java.util.ArrayList;
49  import java.util.logging.Level;
50  import org.metricshub.wbem.javax.cim.CIMObjectPath;
51  import org.metricshub.wbem.sblim.cimclient.internal.cimxml.sax.node.CIMNode;
52  import org.metricshub.wbem.sblim.cimclient.internal.cimxml.sax.node.Node;
53  import org.metricshub.wbem.sblim.cimclient.internal.cimxml.sax.node.NonVolatileIf;
54  import org.metricshub.wbem.sblim.cimclient.internal.logging.LogAndTraceBroker;
55  import org.xml.sax.Attributes;
56  import org.xml.sax.SAXException;
57  import org.xml.sax.helpers.DefaultHandler;
58  
59  /**
60   * Class XMLDefaultHandlerImpl is DefaultHandler implementation which is used
61   * for SAX and PULL style XML parsing.
62   */
63  public class XMLDefaultHandlerImpl extends DefaultHandler {
64  	private Node iRootNode;
65  
66  	private NodeStack iNodeStack = new NodeStack();
67  
68  	private NodePool iNodePool = new NodePool();
69  
70  	private StringBuffer iStrBuf;
71  
72  	private SAXSession iSession;
73  
74  	private boolean iAnyRoot;
75  
76  	/**
77  	 * NodeStack
78  	 */
79  	static class NodeStack {
80  		private ArrayList<Node> iAL = new ArrayList<Node>();
81  
82  		/**
83  		 * push
84  		 *
85  		 * @param pNode
86  		 */
87  		public void push(Node pNode) {
88  			this.iAL.add(pNode);
89  		}
90  
91  		/**
92  		 * pop
93  		 *
94  		 * @return Node
95  		 */
96  		public Node pop() {
97  			if (this.iAL.size() == 0) return null;
98  			return this.iAL.remove(this.iAL.size() - 1);
99  		}
100 
101 		/**
102 		 * peek
103 		 *
104 		 * @return Node
105 		 */
106 		public Node peek() {
107 			if (this.iAL.size() == 0) return null;
108 			return this.iAL.get(this.iAL.size() - 1);
109 		}
110 	}
111 
112 	/**
113 	 * Ctor.
114 	 *
115 	 * @param pSession
116 	 *            - stores common variables for the whole parsing session
117 	 * @param pAnyRoot
118 	 *            - if true any CIM-XML element can be the root element of the
119 	 *            XML stream
120 	 */
121 	public XMLDefaultHandlerImpl(SAXSession pSession, boolean pAnyRoot) {
122 		this.iSession = pSession;
123 		this.iAnyRoot = pAnyRoot;
124 	}
125 
126 	/**
127 	 * Ctor.
128 	 *
129 	 * @param pLocalPath
130 	 *            - CIMObjectPathes without local paths will be extended by this
131 	 *            value
132 	 * @param pAnyRoot
133 	 *            - if true any CIM-XML element can be the root element of the
134 	 *            XML stream
135 	 */
136 	public XMLDefaultHandlerImpl(CIMObjectPath pLocalPath, boolean pAnyRoot) {
137 		this(new SAXSession(pLocalPath), pAnyRoot);
138 	}
139 
140 	/**
141 	 * Ctor.
142 	 *
143 	 * @param pLocalPath
144 	 *            - CIMObjectPathes without local paths will be extended by this
145 	 *            value
146 	 */
147 	public XMLDefaultHandlerImpl(CIMObjectPath pLocalPath) {
148 		this(pLocalPath, false);
149 	}
150 
151 	/**
152 	 * Ctor.
153 	 */
154 	public XMLDefaultHandlerImpl() {
155 		this((CIMObjectPath) null, false);
156 	}
157 
158 	/**
159 	 * @param uri
160 	 * @param localName
161 	 */
162 	@Override
163 	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
164 		this.iStrBuf = null;
165 		String nodeNameEnum = NodeFactory.getEnum(qName);
166 		if (nodeNameEnum == null) {
167 			LogAndTraceBroker
168 				.getBroker()
169 				.trace(Level.FINEST, "Ignoring unrecognized starting CIM-XML element found during parsing: " + qName);
170 			return;
171 		}
172 
173 		Node parentNode = getPeekNode();
174 		if (parentNode == null) {
175 			if (!this.iAnyRoot && nodeNameEnum != NodeConstIf.CIM) throw new SAXException(
176 				"First node of CIM-XML document must be CIM! " + nodeNameEnum + " is invalid!"
177 			);
178 		}
179 		if (parentNode != null) parentNode.testChild(nodeNameEnum);
180 		// let's look for a Node instance in the pool
181 		Node node = this.iNodePool.getNode(nodeNameEnum);
182 		// create an instance if pool didn't give us one
183 		if (node == null) {
184 			node = NodeFactory.getNodeInstance(nodeNameEnum);
185 		}
186 		if (parentNode != null) {
187 			if (parentNode instanceof NonVolatileIf) ((NonVolatileIf) parentNode).addChild(node);
188 		} else {
189 			this.iRootNode = node;
190 		}
191 		this.iNodeStack.push(node);
192 		node.init(attributes, this.iSession);
193 	}
194 
195 	@Override
196 	public void characters(char ch[], int start, int length) {
197 		String str = new String(ch, start, length);
198 		// System.out.println("str("+str.length()+")="+str);
199 		if (this.iStrBuf == null) {
200 			this.iStrBuf = new StringBuffer(str);
201 		} else {
202 			this.iStrBuf.append(str);
203 		}
204 	}
205 
206 	/**
207 	 * @param uri
208 	 * @param localName
209 	 */
210 	@Override
211 	public void endElement(String uri, String localName, String qName) throws SAXException {
212 		String nodeNameEnum = NodeFactory.getEnum(qName);
213 		if (nodeNameEnum == null) {
214 			LogAndTraceBroker
215 				.getBroker()
216 				.trace(Level.FINEST, "Ignoring unrecognized ending CIM-XML element found during parsing: " + qName);
217 			return;
218 		}
219 		Node peekNode = this.iNodeStack.pop();
220 		try {
221 			// pass character data
222 			if (this.iStrBuf != null) {
223 				peekNode.parseData(this.iStrBuf.toString());
224 				this.iStrBuf = null;
225 			}
226 			// completeness check
227 			peekNode.testCompletness();
228 
229 			// call parent's childParsed()
230 			Node parentNode = this.iNodeStack.peek();
231 			if (parentNode != null) {
232 				parentNode.childParsed(peekNode);
233 			}
234 		} finally {
235 			peekNode.setCompleted();
236 			// if peekNode is reusable place it into the NodePool
237 			if (!(peekNode instanceof NonVolatileIf)) {
238 				this.iNodePool.addNode(peekNode);
239 			}
240 		}
241 	}
242 
243 	@Override
244 	public void endDocument() {
245 		String msg = "hits   : " + getNodePoolHits() + "\nmisses : " + getNodePoolMisses();
246 		LogAndTraceBroker.getBroker().trace(Level.FINE, msg);
247 	}
248 
249 	/**
250 	 * getCIMNode
251 	 *
252 	 * @return CIMNode, the root Element of the parsed CIM-XML document
253 	 */
254 	public CIMNode getCIMNode() {
255 		return this.iRootNode instanceof CIMNode ? (CIMNode) this.iRootNode : null;
256 	}
257 
258 	/**
259 	 * getRootNode
260 	 *
261 	 * @return Node, the root element of the parsed CIM-XML stream
262 	 */
263 	public Node getRootNode() {
264 		return this.iRootNode;
265 	}
266 
267 	/**
268 	 * getNodePoolHits
269 	 *
270 	 * @return int
271 	 */
272 	public int getNodePoolHits() {
273 		return this.iNodePool.getHitCnt();
274 	}
275 
276 	/**
277 	 * getNodePoolMisses
278 	 *
279 	 * @return int
280 	 */
281 	public int getNodePoolMisses() {
282 		return this.iNodePool.getMissCnt();
283 	}
284 
285 	private Node getPeekNode() {
286 		return this.iNodeStack.peek();
287 	}
288 }