/* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ package com.sun.star.uno; import java.io.IOException; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Iterator; import java.util.UUID; import java.util.WeakHashMap; import com.sun.star.lib.uno.typedesc.FieldDescription; import com.sun.star.lib.uno.typedesc.TypeDescription; import com.sun.star.lib.util.WeakMap; /** * The central class needed for implementing or using UNO components in Java. * *
The methods queryInterface
and areSame
delegate
* calls to the implementing objects and are used instead of casts,
* instanceof
, ==
, and equals
.
For historic reasons, this class is not final
, and has a
* public
constructor. These artifacts are considered mistakes,
* which might be corrected in a future version of this class, so client code
* should not rely on them.
public
* constructor for this class, which only has static
members.
* Also, this class might be changed to become final
in a
* future version.
*/
@Deprecated
public UnoRuntime() {}
/**
* Generates a worldwide unique identifier string.
*
* It is guaranteed that every invocation of this method generates a new * ID, which is unique within the VM. The quality of “worldwide * unique” will depend on the actual implementation, you should look * at the source to determine if it meets your requirements.
* * @return a uniqueString
*/
public static String getUniqueKey() {
synchronized (uniqueKeyLock) {
if (uniqueKeyCount == Long.MAX_VALUE) {
long time;
for (time = System.currentTimeMillis(); time == uniqueKeyTime;)
{
// Conservatively sleep for 100 millisecond to wait for
// System.currentTimeMillis() to change:
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
uniqueKeyTime = time;
uniqueKeyCount = Long.MIN_VALUE;
}
return uniqueKeyHostPrefix + Long.toString(uniqueKeyTime, 16) + ":"
+ Long.toString(uniqueKeyCount++, 16);
}
}
/**
* Generates a worldwide unique object identifier (OID) for the given
* Java object.
*
* It is guaranteed that subsequent calls to this method with the same * Java object will give the same ID.
* *This method is generally of little use for client code. It should be * considered a mistake that this method is published at all.
* * @param object any object for which an OID shall be generated; must not be *null
* @return the generated OID
* @see com.sun.star.uno.IQueryInterface#getOid
*/
public static String generateOid(Object object) {
String oid = null;
if (object instanceof IQueryInterface) {
oid = ((IQueryInterface) object).getOid();
}
if (oid == null) {
synchronized (oidMap) {
oid = oidMap.get(object);
if (oid == null) {
oid = UUID.randomUUID().toString() + oidSuffix;
oidMap.put(object, oid);
}
}
}
return oid;
}
/**
* Queries the given UNO object for the given UNO interface type.
*
* This method returns null
in case the given UNO object
* does not support the given UNO interface type (or is itself
* null
). Otherwise, a reference to a Java object implementing
* the Java interface type corresponding to the given UNO interface is
* returned. In the latter case, it is unspecified whether the returned
* Java object is the same as the given object, or is another facet of that
* UNO object.
Type
* object representing a UNO interface type
* @param object a reference to any Java object representing (a facet of) a
* UNO object; may be null
* @return a reference to the requested UNO interface type if available,
* otherwise null
* @see com.sun.star.uno.IQueryInterface#queryInterface
*/
public static Object queryInterface(Type type, Object object) {
// Gracefully handle those situations where the passed in UNO object is
// wrapped in an Any. Strictly speaking, such a situation constitutes a
// bug, but it is anticipated that such situations will arise quite
// often in practice (especially since UNO Anys containing an XInterface
// reference are not wrapped in a Java Any, but UNO Anys containing any
// other interface reference are wrapped in a Java Any, which can lead
// to confusion).
if (object instanceof Any) {
Any a = (Any) object;
if (a.getType().getTypeClass() == TypeClass.INTERFACE) {
object = a.getObject();
}
}
if (object instanceof IQueryInterface) {
object = ((IQueryInterface) object).queryInterface(type);
if (object instanceof Any) {
Any a = (Any) object;
object = a.getType().getTypeClass() == TypeClass.INTERFACE
? a.getObject() : null;
}
}
// Ensure that the object implements the requested interface type:
Class> c = type.getZClass();
if (c == null || !c.isInstance(object)) {
object = null;
}
return object;
}
/**
* Queries the given UNO object for the given Java class (which must
* represent a UNO interface type).
*
* @param null
* @return a reference to the requested UNO interface type if available,
* otherwise null
* @see #queryInterface(Type, Object)
*/
@SuppressWarnings("unchecked")
public static ANY
values for equality.
Two UNO values are equal if and only if they are of the same UNO type t, and they meet the following condition, depending on t:
ANY
value.
@param any2 a Java value representing a UNO ANY
value.
@return true
if and only if the two arguments represent
equal UNO values.
*/
public static boolean areSame(Object any1, Object any2) {
Any a1 = Any.complete(any1);
Any a2 = Any.complete(any2);
Type t = a1.getType();
if (!a2.getType().equals(t)) {
return false;
}
Object v1 = a1.getObject();
Object v2 = a2.getObject();
switch (t.getTypeClass().getValue()) {
case TypeClass.VOID_value:
return true;
case TypeClass.BOOLEAN_value:
case TypeClass.BYTE_value:
case TypeClass.SHORT_value:
case TypeClass.UNSIGNED_SHORT_value:
case TypeClass.LONG_value:
case TypeClass.UNSIGNED_LONG_value:
case TypeClass.HYPER_value:
case TypeClass.UNSIGNED_HYPER_value:
case TypeClass.FLOAT_value:
case TypeClass.DOUBLE_value:
case TypeClass.CHAR_value:
case TypeClass.STRING_value:
case TypeClass.TYPE_value:
return v1.equals(v2);
case TypeClass.SEQUENCE_value:
int n = Array.getLength(v1);
if (n != Array.getLength(v2)) {
return false;
}
for (int i = 0; i < n; ++i) {
// Recursively using areSame on Java values that are (boxed)
// elements of Java arrays representing UNO sequence values,
// instead of on Java values that are representations of UNO ANY
// values, works by chance:
if (!areSame(Array.get(v1, i), Array.get(v2, i))) {
return false;
}
}
return true;
case TypeClass.ENUM_value:
return v1 == v2;
case TypeClass.STRUCT_value:
case TypeClass.EXCEPTION_value:
FieldDescription[] fs;
try {
fs = TypeDescription.getTypeDescription(t).
getFieldDescriptions();
} catch (ClassNotFoundException e) {
throw new java.lang.RuntimeException(e);
}
for (int i = 0; i< fs.length; ++i) {
Type ft = new Type(fs[i].getTypeDescription());
try {
// Recursively using areSame on Java values that are (boxed)
// fields of Java classes representing UNO struct or
// exception values, instead of on Java values that are
// representations of UNO ANY values, works by chance:
if (!areSame(
completeValue(ft, fs[i].getField().get(v1)),
completeValue(ft, fs[i].getField().get(v2))))
{
return false;
}
} catch (IllegalAccessException e) {
throw new java.lang.RuntimeException(e);
}
}
return true;
case TypeClass.INTERFACE_value:
return v1 == v2
|| (v1 instanceof IQueryInterface
&& ((IQueryInterface) v1).isSame(v2))
|| (v2 instanceof IQueryInterface
&& ((IQueryInterface) v2).isSame(v1));
default:
throw new java.lang.RuntimeException(
"com.sun.star.uno.Any has bad com.sun.star.uno.TypeClass");
}
}
/**
Complete a UNO value (make sure it is no invalid null
value).
This is useful for members of parameterized type of instantiated
polymorphic struct types, as null
is a valid value there
(and only there, for all types except ANY
and interface
types).
null
.
@return the given value, or the neutral value of the given type, if the
given value was an invalid null
value.
@since UDK 3.2.3
*/
public static final Object completeValue(Type type, Object value) {
if (value != null) {
return value;
}
switch (type.getTypeClass().getValue()) {
case TypeClass.BOOLEAN_value:
return Boolean.FALSE;
case TypeClass.BYTE_value:
return Byte.valueOf((byte) 0);
case TypeClass.SHORT_value:
case TypeClass.UNSIGNED_SHORT_value:
return Short.valueOf((short) 0);
case TypeClass.LONG_value:
case TypeClass.UNSIGNED_LONG_value:
return Integer.valueOf(0);
case TypeClass.HYPER_value:
case TypeClass.UNSIGNED_HYPER_value:
return Long.valueOf(0);
case TypeClass.FLOAT_value:
return new Float(0.0f);
case TypeClass.DOUBLE_value:
return new Double(0.0);
case TypeClass.CHAR_value:
return new Character('\u0000');
case TypeClass.STRING_value:
return "";
case TypeClass.TYPE_value:
return Type.VOID;
case TypeClass.ANY_value:
case TypeClass.INTERFACE_value:
return null;
case TypeClass.SEQUENCE_value:
return Array.newInstance(type.getZClass().getComponentType(), 0);
case TypeClass.STRUCT_value:
try {
return type.getZClass().getConstructor((Class[]) null).
newInstance((Object[]) null);
} catch (java.lang.RuntimeException e) {
throw e;
} catch (java.lang.Exception e) {
throw new java.lang.RuntimeException(e);
}
case TypeClass.ENUM_value:
try {
return type.getZClass().getMethod("getDefault", (Class[]) null).
invoke(null, (Object[]) null);
} catch (java.lang.RuntimeException e) {
throw e;
} catch (java.lang.Exception e) {
throw new java.lang.RuntimeException(e);
}
default:
throw new IllegalArgumentException(
"com.sun.star.uno.UnoRuntime.completeValue called with bad"
+ " com.sun.star.uno.Type");
}
}
/**
* Gets the current context of the current thread, or null
if
* no context has been set for the current thread.
*
* The current context is thread local, which means that this method * returns the context that was last set for this thread.
* * @return the current context of the current thread, ornull
* if no context has been set for the current thread
*/
public static XCurrentContext getCurrentContext() {
return currentContext.get();
}
/**
* Sets the current context for the current thread.
*
* The current context is thread local. To support a stacking behaviour,
* every function that sets the current context should reset it to the
* original value when exiting (for example, within a finally
* block).
null
, any
* previously set context will be removed
*/
public static void setCurrentContext(XCurrentContext context) {
if (context == null) {
currentContext.remove();
} else {
currentContext.set(context);
}
}
/**
* Retrieves an environment of type name
with context
* context
.
*
* Environments are held weakly by this class. If the requested
* environment already exists, this methods simply returns it. Otherwise,
* this method looks for it under
* com.sun.star.lib.uno.environments.name.name_environment
.
from
to environment
* to
.
*
* Creates a new bridge, if the requested bridge does not yet exist, and * hands the arguments to the bridge.
* *If the requested bridge does not exist, it is searched for in package
* com.sun.star.lib.uno.bridges.from_to;
* and the root classpath as
* from_to_bridge
.
from
to environment
* to
.
*
* Creates a new bridge, if the requested bridge does not yet exist, and * hands the arguments to the bridge.
* *If the requested bridge does not exist, it is searched for in package
* com.sun.star.lib.uno.bridges.from_to;
* and the root classpath as
* from_to_bridge
. The used environments
* are retrieved through getEnvironment
.
IBridge
objects
* @see com.sun.star.uno.IBridge
*
* @deprecated As of UDK 3.2.0, this method is deprecated, without
* offering a replacement.
*/
@Deprecated
public static IBridge[] getBridges() {
ArrayList