View Javadoc
1   /*
2     (C) Copyright IBM Corp. 2006, 2012
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   * 1776114    2007-08-21  ebak         Cannot derive instance of class CIM_IndicationSubscription
18   * 1855726    2008-02-11  blaschke-oss CIMInstance.deriveInstance is setting wrong CIMObjectPath
19   * 2003590    2008-06-30  blaschke-oss Change licensing from CPL to EPL
20   * 2204488 	  2008-10-28  raman_arora  Fix code to remove compiler warnings
21   * 2524131    2009-01-21  raman_arora  Upgrade client to JDK 1.5 (Phase 1)
22   * 2531371    2009-02-10  raman_arora  Upgrade client to JDK 1.5 (Phase 2)
23   * 2797550    2009-06-01  raman_arora  JSR48 compliance - add Java Generics
24   * 2935258    2010-01-22  blaschke-oss Sync up javax.cim.* javadoc with JSR48 1.0.0
25   * 2944842    2010-02-08  blaschke-oss Missing thrown ArrayIndexOutOfBoundsException
26   * 3529151    2012-08-22  blaschke-oss TCK: CIMInstance property APIs include keys from COP
27   */
28  
29  package org.metricshub.wbem.javax.cim;
30  
31  /*-
32   * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
33   * WBEM Java Client
34   * ჻჻჻჻჻჻
35   * Copyright 2023 - 2025 MetricsHub
36   * ჻჻჻჻჻჻
37   * Licensed under the Apache License, Version 2.0 (the "License");
38   * you may not use this file except in compliance with the License.
39   * You may obtain a copy of the License at
40   *
41   *      http://www.apache.org/licenses/LICENSE-2.0
42   *
43   * Unless required by applicable law or agreed to in writing, software
44   * distributed under the License is distributed on an "AS IS" BASIS,
45   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
46   * See the License for the specific language governing permissions and
47   * limitations under the License.
48   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
49   */
50  
51  import java.io.Serializable;
52  import java.util.ArrayList;
53  import java.util.logging.Level;
54  import org.metricshub.wbem.sblim.cimclient.internal.cim.CIMElementSorter;
55  import org.metricshub.wbem.sblim.cimclient.internal.logging.LogAndTraceBroker;
56  import org.metricshub.wbem.sblim.cimclient.internal.util.MOF;
57  import org.metricshub.wbem.sblim.cimclient.internal.util.StringSorter;
58  
59  //Sync'd against JSR48 1.0.0 javadoc (build 1.5.0_10) on Wed Jan 20 02:20:58 EST 2010
60  /**
61   * This class represents a CIM instance as defined by the Distributed Management
62   * Task Force (<a href=http://www.dmtf.org>DMTF</a>) CIM Infrastructure
63   * Specification (<a
64   * href=http://www.dmtf.org/standards/published_documents/DSP0004V2.3_final.pdf
65   * >DSP004</a>).
66   */
67  public class CIMInstance implements CIMNamedElementInterface, Serializable {
68  	private static final long serialVersionUID = -249160087013230559L;
69  
70  	private static final CIMProperty<?>[] EMPTY_PROP_A = new CIMProperty[0];
71  
72  	private CIMObjectPath iObjPath;
73  
74  	private CIMProperty<?>[] iProps;
75  
76  	/**
77  	 * Constructs a <code>CIMInstance</code> object using the name and
78  	 * properties specified.
79  	 *
80  	 * @param pName
81  	 *            The <code>CIMObjectPath</code> for this
82  	 *            <code>CIMInstance</code>.
83  	 * @param pProps
84  	 *            The properties for this <code>CIMInstance</code>.
85  	 * @throws IllegalArgumentException
86  	 *             If <code>pName</code> is <code>null</code> or
87  	 *             <code>pName.getObjectName()</code> is <code>null</code>.<br>
88  	 *             [OPTIONAL] - If the key property values do not match the
89  	 *             values in the property array. This is optional due to the
90  	 *             cost of the verification. Some implementations may leave it
91  	 *             up to the developer to ensure that the values match.
92  	 */
93  	public CIMInstance(CIMObjectPath pName, CIMProperty<?>[] pProps) throws IllegalArgumentException {
94  		if (pName == null) {
95  			String msg = "CIMObjectPath parameter cannot be null!";
96  			// TODO: tracing
97  			throw new IllegalArgumentException(msg);
98  		}
99  		if (pName.getObjectName() == null) {
100 			String msg = "ObjectName cannot be null!";
101 			// TODO: tracing
102 			throw new IllegalArgumentException(msg);
103 		}
104 
105 		this.iObjPath = pName;
106 		if (pProps != null) {
107 			this.iProps = pProps;
108 			CIMElementSorter.sort(this.iProps);
109 		} else {
110 			this.iProps = new CIMProperty[0];
111 		}
112 	}
113 
114 	/**
115 	 * Returns a <code>CIMInstance</code> with the updated
116 	 * <code>CIMObjectPath</code>.
117 	 *
118 	 * @param pPath
119 	 *            The complete <code>CIMObjectPath</code> for this instance.
120 	 * @return A new <code>CIMInstance</code> with the updated
121 	 *         <code>CIMObjectPath</code>.
122 	 */
123 	public CIMInstance deriveInstance(CIMObjectPath pPath) {
124 		return new CIMInstance(pPath, this.iProps);
125 	}
126 
127 	/**
128 	 * Returns a <code>CIMInstance</code> with the updated values for the
129 	 * properties in <code>pPropA</code>. Any new properties are ignored.
130 	 *
131 	 * @param pPropA
132 	 *            The array of properties to update.
133 	 * @return A new instance with the updated properties.
134 	 */
135 	public CIMInstance deriveInstance(CIMProperty<?>[] pPropA) {
136 		if (pPropA == null || pPropA.length == 0) return this;
137 		CIMProperty<?>[] newPropA = new CIMProperty[getPropertyCount()];
138 		for (int i = 0; i < newPropA.length; i++) newPropA[i] = this.iProps[i];
139 		for (int i = 0; i < pPropA.length; i++) {
140 			CIMProperty<?> newProp = pPropA[i];
141 			int idx = CIMElementSorter.findIdx(newPropA, newProp.getName());
142 			if (idx < 0) continue;
143 			CIMProperty<?> oldProp = newPropA[idx];
144 			/*
145 			 * 1776114 -> reference type comparison shouldn't be sensitive to
146 			 * the referenced class name due to derivation
147 			 */
148 			if (!typesEqual(oldProp, newProp)) {
149 				LogAndTraceBroker
150 					.getBroker()
151 					.trace(
152 						Level.FINE,
153 						"CIMInstance.deriveInstance() can update only property " +
154 						"values but not property types!\n" +
155 						"original property: " +
156 						oldProp +
157 						"\nnew property: " +
158 						newProp
159 					);
160 				continue;
161 			}
162 			newPropA[idx] =
163 				new CIMProperty<Object>(
164 					oldProp.getName(),
165 					newProp.getDataType(),
166 					newProp.getValue(),
167 					oldProp.isKey(),
168 					oldProp.isPropagated(),
169 					oldProp.getOriginClass()
170 				);
171 		}
172 		return new CIMInstance(this.iObjPath, newPropA);
173 	}
174 
175 	/**
176 	 * Indicates whether some other instance is equal to this one. Two
177 	 * <code>CIMInstances</code> are considered equal if the names are the same.
178 	 * This method does NOT compare each property value.
179 	 *
180 	 * @param pObj
181 	 *            The object to compare.
182 	 * @return <code>true</code> if the specified path references the same
183 	 *         instance, otherwise <code>false</code>.
184 	 */
185 	@Override
186 	public boolean equals(Object pObj) {
187 		if (!(pObj instanceof CIMInstance)) return false;
188 		CIMInstance that = (CIMInstance) pObj;
189 		return this.iObjPath.equals(that.iObjPath);
190 	}
191 
192 	/**
193 	 * This method returns a new <code>CIMInstance</code> with properties
194 	 * filtered according to the input parameters. Inclusion of class origin and
195 	 * qualifiers can also be controlled.
196 	 *
197 	 * @param pLocalOnly
198 	 *            Include only the properties values that were instantiated in
199 	 *            this instance.
200 	 * @param pIncludeClassOrigin
201 	 *            classOrigins are only included if <code>true</code>.
202 	 * @param pPropertyList
203 	 *            If the <code>pPropertyList</code> input parameter is not
204 	 *            <code>null</code>, the members of the array define one or more
205 	 *            Property names. The returned Instance does not include
206 	 *            elements for any Properties missing from this list. If the
207 	 *            <code>pPropertyList</code> input parameter is an empty array
208 	 *            this signifies that no Properties are included in each
209 	 *            returned class. If the <code>pPropertyList</code> input
210 	 *            parameter is <code>null</code> this specifies that all
211 	 *            Properties are included in each returned class. If the
212 	 *            <code>pPropertyList</code> contains duplicate elements or
213 	 *            invalid property names, they are ignored.
214 	 * @return <code>CIMInstance</code> matching the input filter.
215 	 */
216 	public CIMInstance filterProperties(boolean pLocalOnly, boolean pIncludeClassOrigin, String[] pPropertyList) {
217 		StringSorter.sort(pPropertyList);
218 		ArrayList<CIMProperty<?>> propAList = new ArrayList<CIMProperty<?>>();
219 		for (int i = 0; i < getPropertyCount(); i++) {
220 			CIMProperty<?> prop = getProperty(i);
221 			if (pLocalOnly && prop.isPropagated()) continue;
222 			if (pPropertyList != null && !StringSorter.find(pPropertyList, prop.getName())) continue;
223 			propAList.add(
224 				new CIMProperty<Object>(
225 					prop.getName(),
226 					prop.getDataType(),
227 					prop.getValue(),
228 					prop.isKey(),
229 					prop.isPropagated(),
230 					pIncludeClassOrigin ? prop.getOriginClass() : null
231 				)
232 			);
233 		}
234 		return new CIMInstance(this.iObjPath, propAList.toArray(EMPTY_PROP_A));
235 	}
236 
237 	/**
238 	 * Get the name of the class that instantiates this CIM instance.
239 	 *
240 	 * @return Name of class that instantiates this CIM instance.
241 	 */
242 	public String getClassName() {
243 		return this.iObjPath.getObjectName();
244 	}
245 
246 	/**
247 	 * Get the key properties for this instance.
248 	 *
249 	 * @return An array of key properties.
250 	 */
251 	public CIMProperty<?>[] getKeys() {
252 		return this.iObjPath.getKeys();
253 	}
254 
255 	/**
256 	 * Returns the <code>CIMObjectPath</code> that represents this instance.
257 	 *
258 	 * @return The <code>CIMObjectPath</code> that represents this instance.
259 	 */
260 	public CIMObjectPath getObjectPath() {
261 		return this.iObjPath;
262 	}
263 
264 	/**
265 	 * Retrieve an array of the properties for this instance.
266 	 *
267 	 * @return An array of the CIM properties for this instance.
268 	 */
269 	public CIMProperty<?>[] getProperties() {
270 		return this.iProps == null ? new CIMProperty[0] : this.iProps;
271 	}
272 
273 	/**
274 	 * Get a class property by index.
275 	 *
276 	 * @param pIndex
277 	 *            The index of the class property to retrieve.
278 	 * @return The <code>CIMProperty</code> at the specified index.
279 	 * @throws ArrayIndexOutOfBoundsException
280 	 */
281 	public CIMProperty<?> getProperty(int pIndex) throws ArrayIndexOutOfBoundsException {
282 		return this.iProps[pIndex];
283 	}
284 
285 	/**
286 	 * Returns the specified property.
287 	 *
288 	 * @param pName
289 	 *            The text string for the name of the property.
290 	 * @return The property requested or <code>null</code> if the property does
291 	 *         not exist.
292 	 */
293 	public CIMProperty<?> getProperty(String pName) {
294 		return getProperty(pName, null);
295 	}
296 
297 	/**
298 	 * Returns the specified <code>CIMProperty</code>.
299 	 *
300 	 * @param pName
301 	 *            The string name of the property to get.
302 	 * @param pOriginClass
303 	 *            (Optional) The string name of the class in which the property
304 	 *            was defined.
305 	 * @return <code>null</code> if the property does not exist, otherwise
306 	 *         returns the CIM property.
307 	 */
308 	public CIMProperty<?> getProperty(String pName, String pOriginClass) {
309 		CIMProperty<?> prop = (CIMProperty<?>) CIMElementSorter.find(this.iProps, pName);
310 		if (prop == null) return null;
311 		if (pOriginClass == null) return prop;
312 		if (pOriginClass.equalsIgnoreCase(prop.getOriginClass())) return prop;
313 		return null;
314 	}
315 
316 	/**
317 	 * Get the number of properties defined in this <code>CIMInstance</code>.
318 	 *
319 	 * @return The number of properties defined in the <code>CIMInstance</code>.
320 	 */
321 	public int getPropertyCount() {
322 		return this.iProps == null ? 0 : this.iProps.length;
323 	}
324 
325 	/**
326 	 * Returns the value of a property of this CIM Instance.
327 	 *
328 	 * @param name
329 	 *            The name of the property.
330 	 * @return The value for the specified property name or <code>null</code> if
331 	 *         the property does not exist.
332 	 */
333 	public Object getPropertyValue(String name) {
334 		CIMProperty<?> prop = getProperty(name);
335 		return prop == null ? null : prop.getValue();
336 	}
337 
338 	/**
339 	 * Computes the hash code for this instance. The hash code will be the
340 	 * object path of the instance not including the host or namespace
341 	 * information.
342 	 *
343 	 * @return The integer representing the hash code for this object path.
344 	 */
345 	@Override
346 	public int hashCode() {
347 		return toString().hashCode();
348 	}
349 
350 	/**
351 	 * Returns a <code>String</code> representation of the
352 	 * <code>CIMInstance</code>. This method is intended to be used only for
353 	 * debugging purposes, and the format of the returned string may vary
354 	 * between implementations. The returned string may be empty but may not be
355 	 * <code>null</code>.
356 	 *
357 	 * @return String representation of this instance.
358 	 */
359 	@Override
360 	public String toString() {
361 		return MOF.instanceDeclaration(this, MOF.EMPTY);
362 	}
363 
364 	/**
365 	 * Indicates whether the data types of the two properties are equal.
366 	 *
367 	 * @param pProp0
368 	 *            First property.
369 	 *@param pProp1
370 	 *            Second property.
371 	 * @return <code>true</code> if the data types are the same,
372 	 *         <code>false</code> otherwise.
373 	 */
374 	private static boolean typesEqual(CIMProperty<?> pProp0, CIMProperty<?> pProp1) {
375 		CIMDataType type0 = pProp0.getDataType(), type1 = pProp0.getDataType();
376 		return type0.getType() == type1.getType() && type0.isArray() == type1.isArray();
377 	}
378 }