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-10-06  ebak         Make SBLIM client JSR48 compliant
16   * 1669961    2006-04-16  lupusalex    CIMTypedElement.getType() =>getDataType()
17   * 1716991    2006-05-11  lupusalex    FVT: CIMObjectPath.equals() should ignore host name
18   * 1737141    2007-06-18  ebak         Sync up with JSR48 evolution
19   * 1917321    2008-05-29  rgummada     javadoc update to constructors with 2 and more parms
20   * 2003590    2008-06-30  blaschke-oss Change licensing from CPL to EPL
21   * 2524131    2009-01-21  raman_arora  Upgrade client to JDK 1.5 (Phase 1)
22   * 2763216    2009-04-14  blaschke-oss Code cleanup: visible spelling/grammar errors
23   * 2797550    2009-06-01  raman_arora  JSR48 compliance - add Java Generics
24   * 2845128    2009-09-24  blaschke-oss CIMObjectPath.toString() misses host
25   * 2935258    2010-01-22  blaschke-oss Sync up javax.cim.* javadoc with JSR48 1.0.0
26   * 2944824    2010-02-08  blaschke-oss Missing getXmlSchemaName() in CIMObjectPath
27   * 2975975    2010-03-24  blaschke-oss TCK: CIMObjectPath(String) does not handle null
28   * 3023141    2010-07-01  blaschke-oss CIMObjectPath uses # constructor instead of valueOf
29   * 3496349    2012-03-02  blaschke-oss JSR48 1.0.0: add CIMObjectPath getKeyValue
30   * 3510090    2012-03-23  blaschke-oss Fix CIMObjectPath.toString() inconsistencies
31   * 3513343    2012-03-31  blaschke-oss TCK: CIMObjectPath must validate XML schema name
32   * 3513347    2012-03-31  blaschke-oss TCK: CIMObjectPath allows empty string
33   * 3521131    2012-04-24  blaschke-oss Sync up javax.* javadoc with JSR48 1.0.0 Final II
34   * 3521119    2012-04-24  blaschke-oss JSR48 1.0.0: remove CIMObjectPath 2/3/4-parm ctors
35   * 3529151    2012-08-22  blaschke-oss TCK: CIMInstance property APIs include keys from COP
36   *    2660    2013-09-04  blaschke-oss CIMObjectPath.equalsModelPath same as equals
37   *    2716    2013-12-11  blaschke-oss Sync up javax.* javadoc with JSR48 1.0.0 Final V
38   */
39  
40  package org.metricshub.wbem.javax.cim;
41  
42  /*-
43   * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
44   * WBEM Java Client
45   * ჻჻჻჻჻჻
46   * Copyright 2023 - 2025 MetricsHub
47   * ჻჻჻჻჻჻
48   * Licensed under the Apache License, Version 2.0 (the "License");
49   * you may not use this file except in compliance with the License.
50   * You may obtain a copy of the License at
51   *
52   *      http://www.apache.org/licenses/LICENSE-2.0
53   *
54   * Unless required by applicable law or agreed to in writing, software
55   * distributed under the License is distributed on an "AS IS" BASIS,
56   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
57   * See the License for the specific language governing permissions and
58   * limitations under the License.
59   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
60   */
61  
62  import java.io.Serializable;
63  import java.net.MalformedURLException;
64  import java.net.URL;
65  import java.util.Arrays;
66  import org.metricshub.wbem.sblim.cimclient.internal.cim.CIMElementSorter;
67  import org.metricshub.wbem.sblim.cimclient.internal.uri.BooleanValue;
68  import org.metricshub.wbem.sblim.cimclient.internal.uri.CharValue;
69  import org.metricshub.wbem.sblim.cimclient.internal.uri.DateTimeValue;
70  import org.metricshub.wbem.sblim.cimclient.internal.uri.IntegerValue;
71  import org.metricshub.wbem.sblim.cimclient.internal.uri.KeyValuePair;
72  import org.metricshub.wbem.sblim.cimclient.internal.uri.KeyValuePairs;
73  import org.metricshub.wbem.sblim.cimclient.internal.uri.RealValue;
74  import org.metricshub.wbem.sblim.cimclient.internal.uri.ReferenceValue;
75  import org.metricshub.wbem.sblim.cimclient.internal.uri.StringValue;
76  import org.metricshub.wbem.sblim.cimclient.internal.uri.URI;
77  import org.metricshub.wbem.sblim.cimclient.internal.uri.URIString;
78  import org.metricshub.wbem.sblim.cimclient.internal.uri.Value;
79  import org.metricshub.wbem.sblim.cimclient.internal.util.MOF;
80  
81  //Sync'd against JSR48 1.0.0 javadoc (version 1.7.0_03) on Tue Dec 10 07:02:50 EST 2013
82  /**
83   * This class represents the CIM Object Path as defined by the Distributed
84   * Management Task Force (<a href=http://www.dmtf.org>DMTF</a>) CIM
85   * Infrastructure Specification (<a href=
86   * "http://dmtf.org/sites/default/files/standards/documents/DSP0004_2.7.0.pdf"
87   * >DSP004</a>). In order to uniquely identify a given object, a CIM object path
88   * includes the host, namespace, object name and keys (if the object is an
89   * instance).<br>
90   * <br>
91   * For example, the object path:<br>
92   * <br>
93   * <code>
94   * http://myserver/root/cimv2:My_ComputerSystem.Name=mycomputer,
95   * CreationClassName=My_ComputerSystem
96   * </code><br>
97   * <br>
98   * has two parts:<br>
99   * <br>
100  * <ul><li>Namespace Path</li>
101  * <li style="list-style-type: none">
102  * http://myserver/root/cimv2
103  * JSR48 defines the namespace path to include the scheme, host, port (optional)
104  * and namespace
105  * The example specifies the <code>"root/cimv2"</code> namespace on the host
106  * <code>myserver</code>.</li> <li>Model Path</li>
107  * <li style="list-style-type: none"><code>My_ComputerSystem.Name=mycomputer,CreationClassName=My_ComputerSystem
108  * 		</code><br>
109  * DSP0004 defines the model path for a class or qualifier type as the name of
110  * the class/qualifier type<br>
111  * DSP0004 defines the model path for an instance as the class
112  * name.(key=value),*<br>
113  * The example specifies an instance for the class
114  * <code>My_ComputerSystem</code> which is uniquely identified by two key
115  * properties and values: </li><li><code>Name=mycomputer</code></li>
116  * <li>
117  * <code>CreationClassName=My_ComputerSystem</code></li> </ul>
118  */
119 public class CIMObjectPath implements Serializable {
120 	private static final long serialVersionUID = 4593259690658425064L;
121 
122 	private String iScheme, iHost, iPort, iNamespace, iObjectName, iXmlSchemaName;
123 
124 	private CIMProperty<?>[] iKeys;
125 
126 	/**
127 	 * Class TypeValuePair represents a type-value pair with special
128 	 * identification functionality for integer and real numbers.
129 	 *
130 	 */
131 	private static class TypeValuePair {
132 		private CIMDataType iType;
133 
134 		private Object iValue;
135 
136 		/**
137 		 * Constructs a type-value pair with the specified type and value.
138 		 *
139 		 * @param pType
140 		 *            Type.
141 		 * @param pValue
142 		 *            Value.
143 		 */
144 		public TypeValuePair(CIMDataType pType, Object pValue) {
145 			this.iType = pType;
146 			this.iValue = pValue;
147 		}
148 
149 		/**
150 		 * Constructs a type-value pair with the specified integer value.
151 		 *
152 		 * @param intVal
153 		 *            Integer value.
154 		 */
155 		public TypeValuePair(IntegerValue intVal) {
156 			if (intVal.isSigned()) {
157 				switch (intVal.getBitWidth()) {
158 					case 8:
159 						this.iType = CIMDataType.SINT8_T;
160 						this.iValue = Byte.valueOf(intVal.byteValue());
161 						break;
162 					case 16:
163 						this.iType = CIMDataType.SINT16_T;
164 						this.iValue = Short.valueOf(intVal.shortValue());
165 						break;
166 					case 32:
167 						this.iType = CIMDataType.SINT32_T;
168 						this.iValue = Integer.valueOf(intVal.intValue());
169 						break;
170 					default:
171 						this.iType = CIMDataType.SINT64_T;
172 						this.iValue = Long.valueOf(intVal.longValue());
173 				}
174 			} else { // unsigned integers
175 				switch (intVal.getBitWidth()) {
176 					case 8:
177 						this.iType = CIMDataType.UINT8_T;
178 						this.iValue = new UnsignedInteger8(intVal.shortValue());
179 						break;
180 					case 16:
181 						this.iType = CIMDataType.UINT16_T;
182 						this.iValue = new UnsignedInteger16(intVal.intValue());
183 						break;
184 					case 32:
185 						this.iType = CIMDataType.UINT32_T;
186 						this.iValue = new UnsignedInteger32(intVal.longValue());
187 						break;
188 					default:
189 						this.iType = CIMDataType.UINT64_T;
190 						this.iValue = new UnsignedInteger64(intVal.bigIntValue());
191 				}
192 			}
193 		}
194 
195 		/**
196 		 * Constructs a type-value pair with the specified real value.
197 		 *
198 		 * @param pRealVal
199 		 *            Real value.
200 		 */
201 		public TypeValuePair(RealValue pRealVal) {
202 			// TODO: handle precision
203 			if (pRealVal.isDouble()) {
204 				this.iType = CIMDataType.REAL64_T;
205 				this.iValue = new Double(pRealVal.doubleValue());
206 			} else {
207 				this.iType = CIMDataType.REAL32_T;
208 				this.iValue = new Float(pRealVal.floatValue());
209 			}
210 		}
211 
212 		/**
213 		 * Returns the type of the type-value pair.
214 		 *
215 		 * @return Type of type-value pair.
216 		 */
217 		public CIMDataType getType() {
218 			return this.iType;
219 		}
220 
221 		/**
222 		 * Returns the value of the type-value pair.
223 		 *
224 		 * @return Value of type-value pair.
225 		 */
226 		public Object getValue() {
227 			return this.iValue;
228 		}
229 	}
230 
231 	/**
232 	 * Extracts and returns sorted list of key-value pairs from the URI.
233 	 *
234 	 * @param pURI
235 	 *            The Uniform Resource Identifier.
236 	 * @return Sorted array of keys in URI.
237 	 */
238 	private CIMProperty<?>[] getKeysFromURI(URI pURI) {
239 		KeyValuePairs pairs = pURI.getKeyValuePairs();
240 		if (pairs == null) return null;
241 		CIMProperty<?>[] keys = new CIMProperty[pairs.size()];
242 		for (int i = 0; i < pairs.size(); i++) {
243 			KeyValuePair pair = (KeyValuePair) pairs.elementAt(i);
244 			String name = pair.getKey();
245 			Value uriVal = pair.getValue();
246 			TypeValuePair typeValue;
247 			if (uriVal instanceof StringValue) {
248 				typeValue = new TypeValuePair(CIMDataType.STRING_T, uriVal.toString());
249 			} else if (uriVal instanceof ReferenceValue) {
250 				ReferenceValue refVal = (ReferenceValue) uriVal;
251 				CIMObjectPath op = new CIMObjectPath(refVal.getRef());
252 				typeValue = new TypeValuePair(new CIMDataType(op.getObjectName()), op);
253 			} else if (uriVal instanceof BooleanValue) {
254 				typeValue = new TypeValuePair(CIMDataType.BOOLEAN_T, ((BooleanValue) uriVal).getBoolean());
255 			} else if (uriVal instanceof CharValue) {
256 				typeValue = new TypeValuePair(CIMDataType.CHAR16_T, ((CharValue) uriVal).getCharacter());
257 			} else if (uriVal instanceof IntegerValue) {
258 				typeValue = new TypeValuePair((IntegerValue) uriVal);
259 			} else if (uriVal instanceof RealValue) {
260 				typeValue = new TypeValuePair((RealValue) uriVal);
261 			} else if (uriVal instanceof DateTimeValue) {
262 				typeValue = new TypeValuePair(CIMDataType.DATETIME_T, ((DateTimeValue) uriVal).getDateTime());
263 			} else {
264 				// TODO: error or warning tracing
265 				typeValue = new TypeValuePair(CIMDataType.INVALID_T, null);
266 			}
267 			keys[i] = new CIMProperty<Object>(name, typeValue.getType(), typeValue.getValue(), true, false, null);
268 		}
269 		return (CIMProperty[]) CIMElementSorter.sort(keys);
270 	}
271 
272 	/**
273 	 * Initializes the elements of the <code>CIMObjectPath</code> from the given
274 	 * URI.
275 	 *
276 	 * @param pURI
277 	 *            The Uniform Resource Identifier.
278 	 */
279 	private void setURI(URI pURI) {
280 		this.iNamespace = pURI.getNamespaceName();
281 		this.iScheme = pURI.getNamespaceType();
282 		this.iHost = pURI.getHost();
283 		this.iPort = pURI.getPort();
284 		this.iObjectName = pURI.getClassName();
285 		this.iKeys = getKeysFromURI(pURI);
286 	}
287 
288 	/**
289 	 * Constructs a CIM Object Path referencing an instance of the specified CIM
290 	 * element in the given URI.
291 	 *
292 	 * @param pURI
293 	 *            The Uniform Resource Identifier.
294 	 */
295 	private CIMObjectPath(URI pURI) {
296 		setURI(pURI);
297 	}
298 
299 	/**
300 	 * Constructs a CIM Object Path referencing a CIM element. The name can
301 	 * refer to a class name or a qualifier type name, depending on the
302 	 * particular CIM element identified. In order to refer to an instance, the
303 	 * key properties and their corresponding values must be set.<br>
304 	 * <br>
305 	 * Should be able to handle strings, like:<br>
306 	 * <code>
307 	 * http://myserver.org:5066/root/cimv2:My_ComputerSystem.Name="mycmp",CreationClassName="My_ComputerSystem"
308 	 * <br>
309 	 * http://myserver.org/root/cimv2:My_ComputerSystem.Name="mycmp",CreationClassName="My_ComputerSystem"
310 	 * <br>
311 	 * //myserver.org/root/cimv2:My_ComputerSystem<br>
312 	 * /root/cimv2:My_ComputerSystem
313 	 * </code>
314 	 *
315 	 * @param pObjectPath
316 	 *            The string representation of an object path for a CIM element
317 	 *            that will be parsed and used to initialize the object.
318 	 * @throws IllegalArgumentException
319 	 *             If the <code>pObjectPath</code> is <code>null</code> or an
320 	 *             empty string.
321 	 */
322 	public CIMObjectPath(String pObjectPath) {
323 		URI uri;
324 
325 		if (pObjectPath == null) throw new IllegalArgumentException("ObjectPath is null!");
326 		if (pObjectPath.trim().length() == 0) throw new IllegalArgumentException("ObjectPath is empty!");
327 
328 		try {
329 			uri = URI.parse(pObjectPath);
330 		} catch (IllegalArgumentException asURI) {
331 			try {
332 				uri = URI.parseRef(new URIString(pObjectPath), false);
333 			} catch (IllegalArgumentException asUntypedRef) {
334 				try {
335 					uri = URI.parseRef(new URIString(pObjectPath), true);
336 				} catch (IllegalArgumentException asTypedRef) {
337 					String msg =
338 						"Parsing of ObjectPath string has failed!\n" +
339 						"Nested error messages:\n" +
340 						"When parsing as normal URI string:\n" +
341 						asURI.getMessage() +
342 						"When parsing as untyped reference:\n" +
343 						asUntypedRef.getMessage() +
344 						"When parsing as typed reference:\n" +
345 						asTypedRef.getMessage();
346 					// TODO: tracing
347 					throw new IllegalArgumentException(msg);
348 				}
349 			}
350 		}
351 		setURI(uri);
352 	}
353 
354 	/**
355 	 * Constructs a CIM Object Path referencing an instance of the specified CIM
356 	 * element as defined in the specified namespace on the specified host and
357 	 * identified by the given key properties and their corresponding values.
358 	 * Note that the connection mechanism and the port number to which a client
359 	 * connection is established are also specified.<br>
360 	 * <br>
361 	 * NOTE: When using this API against OpenPegasus CIMOM, do not provide the
362 	 * preceding '/' in the namespace parameter. For example, OpenPegasus will
363 	 * accept <code>"root/cimv2"</code> as a namespace but will not accept
364 	 * <code>"/root/cimv2"</code>.
365 	 *
366 	 * @param pScheme
367 	 *            The connection scheme to the host (e.g. http, https, ...)
368 	 * @param pHost
369 	 *            The host name or IP Address.
370 	 * @param pPort
371 	 *            The port on the host to which the connection was established.
372 	 * @param pNamespace
373 	 *            The namepace in which the CIM element is defined.
374 	 * @param pObjectName
375 	 *            The name of the CIM element referenced.
376 	 * @param pKeys
377 	 *            The keys and their corresponding values that identify an
378 	 *            instance of the CIM element.
379 	 */
380 	public CIMObjectPath(
381 		String pScheme,
382 		String pHost,
383 		String pPort,
384 		String pNamespace,
385 		String pObjectName,
386 		CIMProperty<?>[] pKeys
387 	) {
388 		this.iScheme = pScheme;
389 		this.iHost = pHost;
390 		this.iPort = pPort;
391 		this.iNamespace = pNamespace;
392 		this.iObjectName = pObjectName;
393 		if (pKeys != null) {
394 			for (int i = 0; i < pKeys.length; i++) if (!pKeys[i].isKey()) throw new IllegalArgumentException(
395 				"All CIMObjectPath properties must be keys!"
396 			);
397 		}
398 		this.iKeys = (CIMProperty[]) CIMElementSorter.sort(pKeys);
399 	}
400 
401 	/**
402 	 * Constructs a CIM Object Path referencing an instance of the specified CIM
403 	 * element as defined in the specified namespace on the specified host and
404 	 * identified by the given key properties and their corresponding values.
405 	 * Note that the connection mechanism and the port number to which a client
406 	 * connection is established are also specified.<br>
407 	 * <br>
408 	 * NOTE: When using this API against OpenPegasus CIMOM, do not provide the
409 	 * preceding '/' in the namespace parameter. For example, OpenPegasus will
410 	 * accept <code>"root/cimv2"</code> as a namespace but will not accept
411 	 * <code>"/root/cimv2"</code>.
412 	 *
413 	 * @param pScheme
414 	 *            The connection scheme to the host (e.g. http, https, ...)
415 	 * @param pHost
416 	 *            The host name or IP Address.
417 	 * @param pPort
418 	 *            The port on the host to which the connection was established.
419 	 * @param pNamespace
420 	 *            The namepace in which the CIM element is defined.
421 	 * @param pObjectName
422 	 *            The name of the CIM element referenced.
423 	 * @param pKeys
424 	 *            The keys and their corresponding values that identify an
425 	 *            instance of the CIM element.
426 	 * @param pXmlSchemaName
427 	 *            The name of the XML Schema for this object. This is only
428 	 *            needed for protocols that require this information.
429 	 */
430 	public CIMObjectPath(
431 		String pScheme,
432 		String pHost,
433 		String pPort,
434 		String pNamespace,
435 		String pObjectName,
436 		CIMProperty<?>[] pKeys,
437 		String pXmlSchemaName
438 	) {
439 		this(pScheme, pHost, pPort, pNamespace, pObjectName, pKeys);
440 		if (pXmlSchemaName != null) {
441 			try {
442 				new URL(pXmlSchemaName);
443 			} catch (MalformedURLException e) {
444 				throw new IllegalArgumentException(e);
445 			}
446 		}
447 		this.iXmlSchemaName = pXmlSchemaName;
448 	}
449 
450 	/**
451 	 * Compares this CIM object path with the specified CIM object path for
452 	 * equality.
453 	 *
454 	 * @param pObj
455 	 *            The object to compare to this CIM object path. Only the model
456 	 *            paths are compared.
457 	 * @return <code>true</code> if the specified path references the same
458 	 *         object, otherwise <code>false</code> is returned.
459 	 */
460 	@Override
461 	public boolean equals(Object pObj) {
462 		return equalsWorker(pObj, true);
463 	}
464 
465 	private boolean equalsWorker(Object pObj, boolean pIncludeNamespacePath) {
466 		if (!(pObj instanceof CIMObjectPath)) return false;
467 		CIMObjectPath that = (CIMObjectPath) pObj;
468 		// hostname information is not any longer part of the comparison, since
469 		// there is no reliable way to attach hostnames
470 		if (pIncludeNamespacePath) {
471 			boolean namespaceEqual =
472 				(this.iNamespace == null ? that.iNamespace == null : this.iNamespace.equalsIgnoreCase(that.iNamespace));
473 			if (!namespaceEqual) return false;
474 		}
475 		return (
476 			(this.iObjectName == null ? that.iObjectName == null : this.iObjectName.equalsIgnoreCase(that.iObjectName)) &&
477 			keysEqual(that)
478 		);
479 	}
480 
481 	/**
482 	 * Compares this CIM object path's keys with the specified CIM object path's
483 	 * keys for equality.<br>
484 	 * <br>
485 	 * NOTE: <code>CIMProperty.equals()</code> shouldn't be used for keys,
486 	 * because the XML doesn't contain originClass and propagated information.
487 	 *
488 	 * @param pThat
489 	 *            The object path whose keys are to be compared to this CIM
490 	 *            object path's keys.
491 	 * @return <code>true</code> if the keys are the same, otherwise
492 	 *         <code>false</code> is returned.
493 	 */
494 	private boolean keysEqual(CIMObjectPath pThat) {
495 		if (pThat == this) return true;
496 		if (this.iKeys == null) return pThat.iKeys == null;
497 		if (pThat.iKeys == null) return false;
498 		if (this.iKeys.length != pThat.iKeys.length) return false;
499 		for (int i = 0; i < this.iKeys.length; i++) {
500 			CIMProperty<?> thisKey = this.iKeys[i], thatKey = pThat.iKeys[i];
501 			if (!equals(thisKey, thatKey)) {
502 				return false;
503 			}
504 		}
505 		return true;
506 	}
507 
508 	/**
509 	 * Compares two properties for equality.
510 	 *
511 	 * @param pThis
512 	 *            First property.
513 	 * @param pThat
514 	 *            Second property.
515 	 * @return <code>true</code> if the properties are equal, <code>false</code>
516 	 *         otherwise.
517 	 */
518 	private boolean equals(CIMProperty<?> pThis, CIMProperty<?> pThat) {
519 		if (pThis.getDataType() != null && pThis.getDataType().isArray()) {
520 			return (
521 				ncEqualsIC(pThis.getName(), pThat.getName()) &&
522 				ncEquals(pThis.getDataType(), pThat.getDataType()) &&
523 				Arrays.equals((Object[]) pThis.getValue(), (Object[]) pThat.getValue())
524 			);
525 		}
526 		return (
527 			ncEqualsIC(pThis.getName(), pThat.getName()) &&
528 			ncEquals(pThis.getDataType(), pThat.getDataType()) &&
529 			ncEquals(pThis.getValue(), pThat.getValue())
530 		);
531 	}
532 
533 	/**
534 	 * Compares two objects for equality.
535 	 *
536 	 * @param pThis
537 	 *            First object.
538 	 * @param pThat
539 	 *            Second object.
540 	 * @return <code>true</code> if the objects are equal, <code>false</code>
541 	 *         otherwise.
542 	 */
543 	private boolean ncEquals(Object pThis, Object pThat) {
544 		return pThis == null ? pThat == null : pThis.equals(pThat);
545 	}
546 
547 	/**
548 	 * Compares two strings for equality, ignoring case.
549 	 *
550 	 * @param pThis
551 	 *            First string.
552 	 * @param pThat
553 	 *            Second string.
554 	 * @return <code>true</code> if the strings are equal, <code>false</code>
555 	 *         otherwise.
556 	 */
557 	private boolean ncEqualsIC(String pThis, String pThat) {
558 		return pThis == null ? pThat == null : pThis.equalsIgnoreCase(pThat);
559 	}
560 
561 	/**
562 	 * Compares this model path with the specified model path for equality. If
563 	 * the model path includes references, then the references will also be
564 	 * compared for the model path (i.e. the namespace part of the object path
565 	 * will be ignored).
566 	 *
567 	 * @param pModelPath
568 	 *            The object to compare.
569 	 * @return <code>true</code> if the specified path references the same
570 	 *         object, otherwise <code>false</code>.
571 	 */
572 	public boolean equalsModelPath(CIMObjectPath pModelPath) {
573 		return equalsWorker(pModelPath, false);
574 	}
575 
576 	/**
577 	 * Gets the host.
578 	 *
579 	 * @return The name of the host.
580 	 */
581 	public String getHost() {
582 		return this.iHost;
583 	}
584 
585 	/**
586 	 * Gets a key property by name.
587 	 *
588 	 * @param pName
589 	 *            The name of the key property to retrieve.
590 	 * @return The <code>CIMProperty</code> with the given name, or
591 	 *         <code>null</code> if it is not found.
592 	 */
593 	public CIMProperty<?> getKey(String pName) {
594 		return (CIMProperty<?>) CIMElementSorter.find(this.iKeys, pName);
595 	}
596 
597 	/**
598 	 * Gets all key properties.
599 	 *
600 	 * @return The container of key properties.
601 	 */
602 	public CIMProperty<?>[] getKeys() {
603 		return this.iKeys == null ? new CIMProperty[0] : this.iKeys;
604 	}
605 
606 	/**
607 	 * @param pName
608 	 *            The name of the key property to retrieve.
609 	 * @return The value of the key property.
610 	 */
611 	public Object getKeyValue(String pName) {
612 		CIMProperty<?> prop = getKey(pName);
613 		return prop == null ? prop : prop.getValue();
614 	}
615 
616 	/**
617 	 * Gets the namespace.
618 	 *
619 	 * @return The name of the namespace.
620 	 */
621 	public String getNamespace() {
622 		return this.iNamespace;
623 	}
624 
625 	/**
626 	 * Gets the object name. Depending on the type of CIM element referenced,
627 	 * this may be either a class name or a qualifier type name.
628 	 *
629 	 * @return The name of this CIM element.
630 	 */
631 	public String getObjectName() {
632 		return this.iObjectName;
633 	}
634 
635 	/**
636 	 * Gets the the port on the host to which the connection was established.
637 	 *
638 	 * @return The port on the host.
639 	 */
640 	public String getPort() {
641 		return this.iPort;
642 	}
643 
644 	/**
645 	 * Get the connection scheme.
646 	 *
647 	 * @return The connection scheme (e.g. http, https,...)
648 	 */
649 	public String getScheme() {
650 		return this.iScheme;
651 	}
652 
653 	/**
654 	 * Get the XML Schema for this object (optional).
655 	 *
656 	 * @return The XML Schema name.
657 	 */
658 	public String getXmlSchemaName() {
659 		return this.iXmlSchemaName;
660 	}
661 
662 	/**
663 	 * Computes the hash code for this object path.
664 	 *
665 	 * @return The integer representing the hash code for this object path.
666 	 */
667 	@Override
668 	public int hashCode() {
669 		return toString().hashCode();
670 	}
671 
672 	/**
673 	 * Returns a <code>String</code> representation of the CIM object path. This
674 	 * method is intended to be used only for debugging purposes. The format of
675 	 * the value returned may vary between implementations. The string returned
676 	 * may be empty but may not be <code>null</code>.
677 	 *
678 	 * @return A string representation of this CIM object path.
679 	 */
680 	@Override
681 	public String toString() {
682 		return MOF.objectHandle(this, false, false);
683 	}
684 }