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.sentrysoftware.wbem.sblim.cimclient.internal.cimxml.sax;
27  
28  /*-
29   * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
30   * WBEM Java Client
31   * ჻჻჻჻჻჻
32   * Copyright (C) 2023 Sentry Software
33   * ჻჻჻჻჻჻
34   * This program is free software: you can redistribute it and/or modify
35   * it under the terms of the GNU Lesser General Public License as
36   * published by the Free Software Foundation, either version 3 of the
37   * License, or (at your option) any later version.
38   *
39   * This program is distributed in the hope that it will be useful,
40   * but WITHOUT ANY WARRANTY; without even the implied warranty of
41   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
42   * GNU General Lesser Public License for more details.
43   *
44   * You should have received a copy of the GNU General Lesser Public
45   * License along with this program.  If not, see
46   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
47   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
48   */
49  
50  import java.util.ArrayList;
51  import java.util.logging.Level;
52  
53  import org.sentrysoftware.wbem.javax.cim.CIMObjectPath;
54  
55  import org.sentrysoftware.wbem.sblim.cimclient.internal.cimxml.sax.node.CIMNode;
56  import org.sentrysoftware.wbem.sblim.cimclient.internal.cimxml.sax.node.Node;
57  import org.sentrysoftware.wbem.sblim.cimclient.internal.cimxml.sax.node.NonVolatileIf;
58  import org.sentrysoftware.wbem.sblim.cimclient.internal.logging.LogAndTraceBroker;
59  import org.xml.sax.Attributes;
60  import org.xml.sax.SAXException;
61  import org.xml.sax.helpers.DefaultHandler;
62  
63  /**
64   * Class XMLDefaultHandlerImpl is DefaultHandler implementation which is used
65   * for SAX and PULL style XML parsing.
66   */
67  public class XMLDefaultHandlerImpl extends DefaultHandler {
68  
69  	private Node iRootNode;
70  
71  	private NodeStack iNodeStack = new NodeStack();
72  
73  	private NodePool iNodePool = new NodePool();
74  
75  	private StringBuffer iStrBuf;
76  
77  	private SAXSession iSession;
78  
79  	private boolean iAnyRoot;
80  
81  	/**
82  	 * NodeStack
83  	 */
84  	static class NodeStack {
85  
86  		private ArrayList<Node> iAL = new ArrayList<Node>();
87  
88  		/**
89  		 * push
90  		 * 
91  		 * @param pNode
92  		 */
93  		public void push(Node pNode) {
94  			this.iAL.add(pNode);
95  		}
96  
97  		/**
98  		 * pop
99  		 * 
100 		 * @return Node
101 		 */
102 		public Node pop() {
103 			if (this.iAL.size() == 0) return null;
104 			return this.iAL.remove(this.iAL.size() - 1);
105 		}
106 
107 		/**
108 		 * peek
109 		 * 
110 		 * @return Node
111 		 */
112 		public Node peek() {
113 			if (this.iAL.size() == 0) return null;
114 			return this.iAL.get(this.iAL.size() - 1);
115 		}
116 
117 	}
118 
119 	/**
120 	 * Ctor.
121 	 * 
122 	 * @param pSession
123 	 *            - stores common variables for the whole parsing session
124 	 * @param pAnyRoot
125 	 *            - if true any CIM-XML element can be the root element of the
126 	 *            XML stream
127 	 */
128 	public XMLDefaultHandlerImpl(SAXSession pSession, boolean pAnyRoot) {
129 		this.iSession = pSession;
130 		this.iAnyRoot = pAnyRoot;
131 	}
132 
133 	/**
134 	 * Ctor.
135 	 * 
136 	 * @param pLocalPath
137 	 *            - CIMObjectPathes without local paths will be extended by this
138 	 *            value
139 	 * @param pAnyRoot
140 	 *            - if true any CIM-XML element can be the root element of the
141 	 *            XML stream
142 	 */
143 	public XMLDefaultHandlerImpl(CIMObjectPath pLocalPath, boolean pAnyRoot) {
144 		this(new SAXSession(pLocalPath), pAnyRoot);
145 	}
146 
147 	/**
148 	 * Ctor.
149 	 * 
150 	 * @param pLocalPath
151 	 *            - CIMObjectPathes without local paths will be extended by this
152 	 *            value
153 	 */
154 	public XMLDefaultHandlerImpl(CIMObjectPath pLocalPath) {
155 		this(pLocalPath, false);
156 	}
157 
158 	/**
159 	 * Ctor.
160 	 */
161 	public XMLDefaultHandlerImpl() {
162 		this((CIMObjectPath) null, false);
163 	}
164 
165 	/**
166 	 * @param uri
167 	 * @param localName
168 	 */
169 	@Override
170 	public void startElement(String uri, String localName, String qName, Attributes attributes)
171 			throws SAXException {
172 		this.iStrBuf = null;
173 		String nodeNameEnum = NodeFactory.getEnum(qName);
174 		if (nodeNameEnum == null) {
175 			LogAndTraceBroker.getBroker()
176 					.trace(
177 							Level.FINEST,
178 							"Ignoring unrecognized starting CIM-XML element found during parsing: "
179 									+ qName);
180 			return;
181 		}
182 
183 		Node parentNode = getPeekNode();
184 		if (parentNode == null) {
185 			if (!this.iAnyRoot && nodeNameEnum != NodeConstIf.CIM) throw new SAXException(
186 					"First node of CIM-XML document must be CIM! " + nodeNameEnum + " is invalid!");
187 		}
188 		if (parentNode != null) parentNode.testChild(nodeNameEnum);
189 		// let's look for a Node instance in the pool
190 		Node node = this.iNodePool.getNode(nodeNameEnum);
191 		// create an instance if pool didn't give us one
192 		if (node == null) {
193 			node = NodeFactory.getNodeInstance(nodeNameEnum);
194 		}
195 		if (parentNode != null) {
196 			if (parentNode instanceof NonVolatileIf) ((NonVolatileIf) parentNode).addChild(node);
197 		} else {
198 			this.iRootNode = node;
199 		}
200 		this.iNodeStack.push(node);
201 		node.init(attributes, this.iSession);
202 	}
203 
204 	@Override
205 	public void characters(char ch[], int start, int length) {
206 		String str = new String(ch, start, length);
207 		// System.out.println("str("+str.length()+")="+str);
208 		if (this.iStrBuf == null) {
209 			this.iStrBuf = new StringBuffer(str);
210 		} else {
211 			this.iStrBuf.append(str);
212 		}
213 	}
214 
215 	/**
216 	 * @param uri
217 	 * @param localName
218 	 */
219 	@Override
220 	public void endElement(String uri, String localName, String qName) throws SAXException {
221 		String nodeNameEnum = NodeFactory.getEnum(qName);
222 		if (nodeNameEnum == null) {
223 			LogAndTraceBroker.getBroker().trace(Level.FINEST,
224 					"Ignoring unrecognized ending CIM-XML element found during parsing: " + qName);
225 			return;
226 		}
227 		Node peekNode = this.iNodeStack.pop();
228 		try {
229 			// pass character data
230 			if (this.iStrBuf != null) {
231 				peekNode.parseData(this.iStrBuf.toString());
232 				this.iStrBuf = null;
233 			}
234 			// completeness check
235 			peekNode.testCompletness();
236 
237 			// call parent's childParsed()
238 			Node parentNode = this.iNodeStack.peek();
239 			if (parentNode != null) {
240 				parentNode.childParsed(peekNode);
241 			}
242 		} finally {
243 			peekNode.setCompleted();
244 			// if peekNode is reusable place it into the NodePool
245 			if (!(peekNode instanceof NonVolatileIf)) {
246 				this.iNodePool.addNode(peekNode);
247 			}
248 		}
249 	}
250 
251 	@Override
252 	public void endDocument() {
253 		String msg = "hits   : " + getNodePoolHits() + "\nmisses : " + getNodePoolMisses();
254 		LogAndTraceBroker.getBroker().trace(Level.FINE, msg);
255 	}
256 
257 	/**
258 	 * getCIMNode
259 	 * 
260 	 * @return CIMNode, the root Element of the parsed CIM-XML document
261 	 */
262 	public CIMNode getCIMNode() {
263 		return this.iRootNode instanceof CIMNode ? (CIMNode) this.iRootNode : null;
264 	}
265 
266 	/**
267 	 * getRootNode
268 	 * 
269 	 * @return Node, the root element of the parsed CIM-XML stream
270 	 */
271 	public Node getRootNode() {
272 		return this.iRootNode;
273 	}
274 
275 	/**
276 	 * getNodePoolHits
277 	 * 
278 	 * @return int
279 	 */
280 	public int getNodePoolHits() {
281 		return this.iNodePool.getHitCnt();
282 	}
283 
284 	/**
285 	 * getNodePoolMisses
286 	 * 
287 	 * @return int
288 	 */
289 	public int getNodePoolMisses() {
290 		return this.iNodePool.getMissCnt();
291 	}
292 
293 	private Node getPeekNode() {
294 		return this.iNodeStack.peek();
295 	}
296 }