1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 package com.sun.star.uno;
23 
24 /** This class provides static methods which aim at exploring the contents of an
25  * Any and extracting its value. All public methods take an Object argument that
26  * either is the immediate object, such as Boolean, Type, interface implementation,
27  * or an Any that contains an object. <br>The methods which extract the value do a
28  * widening conversion. See the method comments for the respective conversions.
29  */
30 public class AnyConverter
31 {
32     /** Determines the type of an any object.
33 
34         @param object any object
35         @return type object
36     */
getType( Object object )37     static public Type getType( Object object )
38     {
39         Type t;
40         if (null == object)
41         {
42             t = m_XInterface_type;
43         }
44         else if (object instanceof Any)
45         {
46             t = ((Any)object).getType();
47             // nested any
48             if (TypeClass.ANY_value == t.getTypeClass().getValue())
49                 return getType( ((Any)object).getObject() );
50         }
51         else
52         {
53             t = new Type( object.getClass() );
54         }
55         return t;
56     }
57 
58     /** checks if the any contains the idl type <code>void</code>.
59         @param object the object to check
60         @return true when the any is void, false otherwise
61      */
isVoid(Object object)62 	static public boolean isVoid(Object object){
63 		return containsType(TypeClass.VOID, object);
64 	}
65 
66     /** checks if the any contains a value of the idl type <code>char</code>.
67         @param object the object to check
68         @return true when the any contains a char, false otherwise.
69      */
isChar(Object object)70 	static public boolean isChar(Object object){
71 		return containsType(TypeClass.CHAR, object);
72 	}
73 
74     /** checks if the any contains a value of the idl type <code>boolean</code>.
75         @param object the object to check
76         @return true when the any contains a boolean, false otherwise.
77      */
isBoolean(Object object)78 	static public boolean isBoolean(Object object){
79 		return containsType(TypeClass.BOOLEAN, object);
80 	}
81 
82     /** checks if the any contains a value of the idl type <code>byte</code>.
83         @param object the object to check
84         @return true when the any contains a byte, false otherwise.
85      */
isByte(Object object)86 	static public boolean isByte(Object object){
87 		return containsType(TypeClass.BYTE, object);
88 	}
89 
90     /** checks if the any contains a value of the idl type <code>short</code>.
91         @param object the object to check
92         @return true when the any contains a short, false otherwise.
93      */
isShort(Object object)94 	static public boolean isShort(Object object){
95 		return containsType(TypeClass.SHORT, object);
96 	}
97 
98     /** checks if the any contains a value of the idl type <code>long</code> (which maps to a java-int).
99         @param object the object to check
100         @return true when the any contains a int, false otherwise.
101      */
isInt(Object object)102 	static public boolean isInt(Object object){
103 		return containsType(TypeClass.LONG, object);
104 	}
105 
106     /** checks if the any contains a value of the idl type <code>hyper</code> (which maps to a java-long).
107         @param object the object to check
108         @return true when the any contains a long, false otherwise.
109      */
isLong(Object object)110 	static public boolean isLong(Object object){
111 		return containsType(TypeClass.HYPER, object);
112 	}
113 
114     /** checks if the any contains a value of the idl type <code>float</code>.
115         @param object the object to check
116         @return true when the any contains a float, false otherwise.
117      */
isFloat(Object object)118 	static public boolean isFloat(Object object){
119 		return containsType(TypeClass.FLOAT, object);
120 	}
121 
122     /** checks if the any contains a value of the idl type <code>double</code>.
123         @param object the object to check
124         @return true when the any contains a double, false otherwise.
125      */
isDouble(Object object)126 	static public boolean isDouble(Object object){
127 		return containsType(TypeClass.DOUBLE, object);
128 	}
129 
130     /** checks if the any contains a value of the idl type <code>string</code>.
131         @param object the object to check
132         @return true when the any contains a string, false otherwise.
133      */
isString(Object object)134 	static public boolean isString(Object object){
135 		return containsType(TypeClass.STRING, object);
136 	}
137 
138     /** checks if the any contains a value of the idl type <code>enum</code>.
139         @param object the object to check
140         @return true if the any contains an enum, false otherwise
141      */
isEnum(Object object)142 	static public boolean isEnum(Object object)
143     {
144 		return containsType(TypeClass.ENUM, object);
145 	}
146 
147     /** checks if the any contains a value of the idl type <code>type</code>.
148         @param object the object to check
149         @return true when the any contains a type, false otherwise.
150      */
isType(Object object)151 	static public boolean isType(Object object){
152 		return containsType(TypeClass.TYPE, object);
153 	}
154 
155     /** checks if the any contains an interface, struct, exception, sequence or enum.
156         If <em>object</em> is an any with an interface type, then true is also returned if
157         the any contains a null reference. This is because interfaces are allowed to have
158         a null value contrary to other UNO types.
159         @param object the object to check
160         @return true if the any contains an object
161      */
isObject(Object object)162 	static public boolean isObject(Object object)
163     {
164         int tc = getType(object).getTypeClass().getValue();
165         return (TypeClass.INTERFACE_value == tc ||
166                 TypeClass.STRUCT_value == tc ||
167                 TypeClass.EXCEPTION_value == tc ||
168                 TypeClass.SEQUENCE_value == tc ||
169                 TypeClass.ENUM_value == tc);
170 	}
171 
172     /** checks if the any contains UNO idl sequence value (meaning a java array
173         containing elements which are values of UNO idl types).
174         @param object the object to check
175         @return true when the any contains an object which implements interfaces, false otherwise.
176      */
isArray(Object object)177 	static public boolean isArray(Object object){
178 		return containsType(TypeClass.SEQUENCE, object);
179 	}
180 
181 	/** converts an Char object or an Any object containing a Char object into a simple char.
182         @param object the object to convert
183         @return the char contained within the object
184         @throws com.sun.star.lang.IllegalArgumentException in case no char is contained within object
185         @see #isChar
186     */
toChar(Object object)187 	static public char toChar(Object object) throws  com.sun.star.lang.IllegalArgumentException{
188 		Character ret= (Character)convertSimple(TypeClass.CHAR, null, object);
189 		return ret.charValue();
190 	}
191 
192 	/** converts an Boolean object or an Any object containing a Boolean object into a simple boolean.
193         @param object the object to convert
194         @return the boolean contained within the object
195         @throws com.sun.star.lang.IllegalArgumentException in case no boolean is contained within object
196         @see #isBoolean
197     */
toBoolean(Object object)198 	static public boolean toBoolean(Object object) throws  com.sun.star.lang.IllegalArgumentException{
199 		Boolean ret= (Boolean)convertSimple(TypeClass.BOOLEAN, null, object);
200 		return ret.booleanValue();
201 	}
202 
203 	/** converts an Byte object or an Any object containing a Byte object into a simple byte.
204         @param object the object to convert
205         @return the boolean contained within the object
206         @throws com.sun.star.lang.IllegalArgumentException in case no byte is contained within object
207         @see #isBoolean
208     */
toByte(Object object)209 	static public byte toByte(Object object) throws   com.sun.star.lang.IllegalArgumentException{
210 		Byte ret= (Byte)convertSimple(TypeClass.BYTE, null, object);
211 		return ret.byteValue();
212 	}
213 
214     /** converts a number object into a simple short and allows widening conversions.
215         Allowed argument types are Byte, Short or Any containing these types.
216         @param object the object to convert
217         @throws com.sun.star.lang.IllegalArgumentException in case no short or byte is contained within object
218         @return the short contained within the object
219      */
toShort(Object object)220 	static public short toShort(Object object) throws   com.sun.star.lang.IllegalArgumentException{
221 		Short ret= (Short)convertSimple(TypeClass.SHORT, null, object);
222 		return ret.shortValue();
223 	}
224     /** converts a number object into an idl unsigned short and allows widening conversions.
225         Allowed argument types are Anies containing idl unsigned short values.
226         @param object the object to convert
227         @throws com.sun.star.lang.IllegalArgumentException
228                 in case no idl unsigned short is contained within Any
229         @return an (unsigned) short
230      */
toUnsignedShort(Object object)231 	static public short toUnsignedShort(Object object)
232         throws com.sun.star.lang.IllegalArgumentException
233     {
234 		Short ret= (Short)convertSimple(TypeClass.UNSIGNED_SHORT, null, object);
235 		return ret.shortValue();
236 	}
237 
238     /** converts a number object into a simple int and allows widening conversions.
239         Allowed argument types are Byte, Short, Integer or Any containing these types.
240         @param object the object to convert
241         @throws com.sun.star.lang.IllegalArgumentException in case no short, byte or int is contained within object.
242         @return the int contained within the object
243      */
toInt(Object object)244 	static public int toInt(Object object) throws  com.sun.star.lang.IllegalArgumentException{
245 		Integer ret= (Integer) convertSimple( TypeClass.LONG, null, object);
246 		return ret.intValue();
247 	}
248     /** converts a number object into an idl unsigned long and allows widening conversions.
249         Allowed argument types are Anies containing idl unsigned short or unsigned long values.
250         @param object the object to convert
251         @throws com.sun.star.lang.IllegalArgumentException
252                 in case no idl unsigned short nor unsigned long is contained within Any
253         @return an (unsigned) int
254      */
toUnsignedInt(Object object)255 	static public int toUnsignedInt(Object object)
256         throws  com.sun.star.lang.IllegalArgumentException
257     {
258 		Integer ret = (Integer)convertSimple(TypeClass.UNSIGNED_LONG, null, object);
259 		return ret.intValue();
260 	}
261 
262     /** converts a number object into a simple long and allows widening conversions.
263         Allowed argument types are Byte, Short, Integer, Long or Any containing these types.
264         @param object the object to convert
265         @throws com.sun.star.lang.IllegalArgumentException in case no short, byte, int or long
266                 is contained within object.
267         @return the long contained within the object
268      */
toLong(Object object)269 	static public long toLong(Object object) throws   com.sun.star.lang.IllegalArgumentException{
270 		Long ret= (Long) convertSimple( TypeClass.HYPER, null, object);
271 		return ret.longValue();
272 	}
273     /** converts a number object into an idl unsigned hyper and allows widening conversions.
274         Allowed argument types are Anies containing idl unsigned short, unsigned long or
275         unsigned hyper values.
276         @param object the object to convert
277         @throws com.sun.star.lang.IllegalArgumentException
278                 in case no idl unsigned short, nor unsigned long nor unsigned hyper
279                 is contained within object.
280         @return an (unsigned) long
281      */
toUnsignedLong(Object object)282 	static public long toUnsignedLong(Object object)
283         throws com.sun.star.lang.IllegalArgumentException
284     {
285 		Long ret = (Long)convertSimple(TypeClass.UNSIGNED_HYPER, null, object);
286 		return ret.longValue();
287 	}
288 
289     /** converts a number object into a simple float and allows widening conversions.
290         Allowed argument types are Byte, Short, Float or Any containing these types.
291         @param object the object to convert
292         @throws com.sun.star.lang.IllegalArgumentException in case no byte, short or float
293                 is contained within object.
294         @return the float contained within the object
295      */
toFloat(Object object)296 	static public float toFloat(Object object) throws com.sun.star.lang.IllegalArgumentException{
297 		Float ret= (Float) convertSimple( TypeClass.FLOAT,null, object);
298 		return ret.floatValue();
299 	}
300 
301     /** converts a number object into a simple double and allows widening conversions.
302         Allowed argument types are Byte, Short, Int, Float, Double or Any containing these types.
303         @param object the object to convert
304         @throws com.sun.star.lang.IllegalArgumentException in case no byte, short, int, float
305                 or double is contained within object.
306         @return the double contained within the object
307      */
toDouble(Object object)308 	static public double toDouble(Object object) throws com.sun.star.lang.IllegalArgumentException {
309 		Double ret= (Double) convertSimple( TypeClass.DOUBLE, null, object);
310 		return ret.doubleValue();
311 	}
312 
313     /** converts a string or an any containing a string into a string.
314         @param object the object to convert
315         @throws com.sun.star.lang.IllegalArgumentException in case no string is contained within object.
316         @return the string contained within the object
317      */
toString(Object object)318 	static public String toString(Object object) throws com.sun.star.lang.IllegalArgumentException {
319 		return (String) convertSimple( TypeClass.STRING, null, object);
320 	}
321 
322     /** converts a Type or an any containing a Type into a Type.
323         @param object the object to convert
324         @throws com.sun.star.lang.IllegalArgumentException in case no type is contained within object.
325         @return the type contained within the object
326      */
toType(Object object)327 	static public Type toType(Object object) throws com.sun.star.lang.IllegalArgumentException {
328 		return (Type) convertSimple( TypeClass.TYPE, null, object);
329 	}
330 
331     /** converts a UNO object (struct, exception, sequence, enum or interface) or an Any containing
332      *  these types into an UNO object of a specified destination type.
333      *  For interfaces, the argument <em>object</em> is queried for the interface specified
334      *  by the <em>type</em> argument. That query (UnoRuntime.queryInterface) might return null,
335      *  if the interface is not implemented or a null-ref or a VOID any is given.
336      *
337      *  @param type type of the returned value
338      *  @param object the object that is to be converted
339      *  @return destination object
340      *  @throws com.sun.star.lang.IllegalArgumentException
341      *          in case conversion is not possible
342      */
toObject(Type type, Object object)343 	static public Object toObject(Type type, Object object)
344 		throws com.sun.star.lang.IllegalArgumentException
345     {
346 		return convertSimple( type.getTypeClass(), type, object );
347 	}
348     /** converts a UNO object (struct, exception, sequence, enum or interface) or an Any containing
349      *  these types into an UNO object of a specified destination type.
350      *  For interfaces, the argument <em>object</em> is queried for the interface specified
351      *  by the <em>type</em> argument. That query (UnoRuntime.queryInterface) might return null,
352      *  if the interface is not implemented or a null-ref or a VOID any is given.
353      *
354      *  @param clazz class of the returned value
355      *  @param object the object that is to be converted
356      *  @return destination object
357      *  @throws com.sun.star.lang.IllegalArgumentException
358      *          in case conversion is not possible
359      */
360     @SuppressWarnings("unchecked")
toObject(Class<T> clazz, Object object)361 	static public <T> T toObject(Class<T> clazz, Object object)
362 		throws com.sun.star.lang.IllegalArgumentException
363     {
364         return (T) toObject( new Type( clazz ), object );
365 	}
366 
367     /** converts an array or an any containing an array into an array.
368         @param object the object to convert
369         @throws com.sun.star.lang.IllegalArgumentException in case no array is contained within object.
370         @return the array contained within the object
371      */
toArray( Object object)372 	static public Object toArray( Object object) throws com.sun.star.lang.IllegalArgumentException {
373 		return convertSimple( TypeClass.SEQUENCE, null, object);
374 	}
375 
376 	/**
377 	   Examines the argument <em>object</em> if is correspond to the type in argument <em>what</em>.
378 	   <em>object</em> is either matched directly against the type or if it is an any then the
379 	   contained object is matched against the type.
380 	*/
containsType( TypeClass what, Object object)381 	static private boolean containsType( TypeClass what, Object object){
382         return (getType(object).getTypeClass().getValue() == what.getValue());
383 	}
384 
385     static private final Type m_XInterface_type = new Type( XInterface.class );
386 
convertSimple( TypeClass destTClass, Type destType, Object object_ )387 	static private Object convertSimple( TypeClass destTClass, Type destType, Object object_ )
388 		throws com.sun.star.lang.IllegalArgumentException
389     {
390 		Object object;
391         Type type;
392         if (object_ instanceof Any)
393         {
394             // unbox
395             Any a = (Any)object_;
396             object = a.getObject();
397             type = a.getType();
398             // nested any
399             if (TypeClass.ANY_value == type.getTypeClass().getValue())
400                 return convertSimple( destTClass, destType, object );
401         }
402         else
403         {
404             object = object_;
405             type = (null == object ? m_XInterface_type : new Type( object.getClass() ));
406         }
407 
408         int tc = type.getTypeClass().getValue();
409         int dest_tc = destTClass.getValue();
410 
411         if (null == object)
412         {
413             // special for interfaces
414             if (TypeClass.INTERFACE_value == tc && dest_tc == tc)
415                 return null;
416         }
417         else
418         {
419             switch (dest_tc)
420             {
421             case TypeClass.CHAR_value:
422                 if (tc == TypeClass.CHAR_value)
423                     return object;
424                 break;
425             case TypeClass.BOOLEAN_value:
426                 if (tc == TypeClass.BOOLEAN_value)
427                     return object;
428                 break;
429             case TypeClass.BYTE_value:
430                 if (tc == TypeClass.BYTE_value)
431                     return object;
432                 break;
433             case TypeClass.SHORT_value:
434                 switch (tc)
435                 {
436                 case TypeClass.BYTE_value:
437                     return Short.valueOf( ((Byte)object).byteValue() );
438                 case TypeClass.SHORT_value:
439                     return object;
440                 }
441                 break;
442             case TypeClass.UNSIGNED_SHORT_value:
443                 switch (tc)
444                 {
445                 case TypeClass.UNSIGNED_SHORT_value:
446                     return object;
447                 }
448                 break;
449             case TypeClass.LONG_value:
450                 switch (tc)
451                 {
452                 case TypeClass.BYTE_value:
453                     return Integer.valueOf( ((Byte)object).byteValue() );
454                 case TypeClass.SHORT_value:
455                 case TypeClass.UNSIGNED_SHORT_value:
456                     return Integer.valueOf( ((Short)object).shortValue() );
457                 case TypeClass.LONG_value:
458                     return object;
459                 }
460                 break;
461             case TypeClass.UNSIGNED_LONG_value:
462                 switch (tc)
463                 {
464                 case TypeClass.UNSIGNED_SHORT_value:
465                     return Integer.valueOf( ((Short)object).shortValue() );
466                 case TypeClass.UNSIGNED_LONG_value:
467                     return object;
468                 }
469                 break;
470             case TypeClass.HYPER_value:
471                 switch (tc)
472                 {
473                 case TypeClass.BYTE_value:
474                     return Long.valueOf( ((Byte)object).byteValue() );
475                 case TypeClass.SHORT_value:
476                 case TypeClass.UNSIGNED_SHORT_value:
477                     return Long.valueOf( ((Short)object).shortValue() );
478                 case TypeClass.LONG_value:
479                 case TypeClass.UNSIGNED_LONG_value:
480                     return Long.valueOf( ((Integer)object).intValue() );
481                 case TypeClass.HYPER_value:
482                     return object;
483                 }
484                 break;
485             case TypeClass.UNSIGNED_HYPER_value:
486                 switch (tc)
487                 {
488                 case TypeClass.UNSIGNED_SHORT_value:
489                     return Long.valueOf( ((Short)object).shortValue() );
490                 case TypeClass.UNSIGNED_LONG_value:
491                     return Long.valueOf( ((Integer)object).intValue() );
492                 case TypeClass.UNSIGNED_HYPER_value:
493                     return object;
494                 }
495                 break;
496             case TypeClass.FLOAT_value:
497                 switch (tc)
498                 {
499                 case TypeClass.BYTE_value:
500                     return Float.valueOf( ((Byte)object).byteValue() );
501                 case TypeClass.SHORT_value:
502                     return Float.valueOf( ((Short)object).shortValue() );
503                 case TypeClass.FLOAT_value:
504                     return object;
505                 }
506                 break;
507             case TypeClass.DOUBLE_value:
508                 switch (tc)
509                 {
510                 case TypeClass.BYTE_value:
511                     return Double.valueOf( ((Byte)object).byteValue() );
512                 case TypeClass.SHORT_value:
513                     return Double.valueOf( ((Short)object).shortValue() );
514                 case TypeClass.LONG_value:
515                     return Double.valueOf( ((Integer)object).intValue() );
516                 case TypeClass.FLOAT_value:
517                     return Double.valueOf( ((Float)object).floatValue() );
518                 case TypeClass.DOUBLE_value:
519                     return object;
520                 }
521                 break;
522             case TypeClass.ENUM_value:
523                 if (tc == TypeClass.ENUM_value &&
524                     (null == destTClass || destType.equals( type ) /* optional destType */))
525                 {
526                     return object;
527                 }
528                 break;
529             case TypeClass.STRING_value:
530                 if (tc == TypeClass.STRING_value)
531                     return object;
532                 break;
533             case TypeClass.TYPE_value:
534                 if (tc == TypeClass.TYPE_value)
535                     return object;
536                 break;
537             case TypeClass.INTERFACE_value:
538                 // Because object is a class, not an interface, it is
539                 // controversial what kind of Type "new Type(object.class)"
540                 // above should return (UNKNOWN or INTERFACE), so that we should
541                 // not check here for "tc == TypeClass.INTERFACE_value".
542                 // Instead, we check whether object (indirectly) derives from
543                 // XInterface:
544                 if (object instanceof XInterface)
545                     return UnoRuntime.queryInterface( destType, object );
546                 break;
547             case TypeClass.STRUCT_value:
548             case TypeClass.EXCEPTION_value:
549                 if (destType.isSupertypeOf(type)) {
550                     return object;
551                 }
552                 break;
553             case TypeClass.SEQUENCE_value:
554                 if (tc == TypeClass.SEQUENCE_value &&
555                     (null == destType || destType.equals( type ) /* optional destType */))
556                 {
557                     return object;
558                 }
559                 break;
560             }
561         }
562 		throw new com.sun.star.lang.IllegalArgumentException(
563 			"The Argument did not hold the proper type");
564 	}
565 }
566