Since the beginning of the Google Summer of Code 2005 when I started the OpenOffice.org Eclipse Integration project, I wanted to provide a code completion feature for UNO-IDL. At the beginning I thought at a huge mecanism using IDL parsers to fetch the informations. However, I investigate a bit more on Juergen and Laurent ideas: using the UNO reflection API to introspect any type.
After a small test, I could manage to do it in a small Java application.
I'll try to explain what I did. All the code provided is in very simple
Java main and should be launched with a correct ClassPath (the
OpenOffice.org jars) and LD_LIBRARY_PATH
set to your OpenOffice.org
program directory. This is because OOo Jars use the OOo shared
libraries.
First thing to do is to bootstrap OpenOffice.org to get a component context. There is no mystery in this code: using the Bootstrap class and one of its method is the best way to do it.
try {
//*****************************************************************************
// 1- Bootstrap of OpenOffice.org
//*****************************************************************************
String sofficepath = "file:///opt/openoffice.org2.0/program";
String unoini = sofficepath + "/unorc"; // To change in uno.ini for Windows
Hashtable params = new Hashtable();
params.put("SYSBINDIR", sofficepath);
XComponentContext xCtx = Bootstrap.defaultBootstrap_InitialComponentContext(
unoini, params);
System.out.println(">>> OOo has been bootstrapped");
This second part of code loads a types registry external to OpenOffice.org. You will have to load some if you want to introspect in addons or components types (I mean types which aren't defined in the OpenOffice.org API)
//*****************************************************************************
// 2- Opening a local types regitry
//*****************************************************************************
String localRegistry = "file:///path/to/your/types.rdb";
XMultiComponentFactory xMCF = xCtx.getServiceManager();
XSimpleRegistry xReg = (XSimpleRegistry)UnoRuntime.queryInterface(
XSimpleRegistry.class,
xMCF.createInstanceWithContext("com.sun.star.registry.SimpleRegistry",
xCtx));
xReg.open(localRegistry, true, false);
System.out.println(">>> Local Registry opened");
The thirsd part is the interesting one for this blog article. The first
thing to do before introspecting, is to create a
com.sun.star.reflection.CoreReflection
service. This one will provide
two simple methods:
forName()
: gets a type definition from a string representing the type
name (dot-separated, eg:com.sun.star.uno.XInterface
)getType()
: gets a type definition from an any UNO object.
In our case, we imagine that we don't have any running object to
introspect, but we have just its name (remain that is for code
completion purpose), thus we will use the forName()
method (see point
3.1 in the code).
When we have the desired XIdlClass
, we can do what we like with:
asking its name, its methods or attributes and so on. To get more help
on this please report to the com.sun.star.reflection.XIdlClass
API.
//*****************************************************************************
// 3- Getting the methods of XInterface
//*****************************************************************************
//**** 3.1 - Creating a CoreReflection service
Object oReflection = xCtx.getServiceManager().createInstanceWithContext(
"com.sun.star.reflection.CoreReflection", xCtx);
XIdlReflection xReflection = (XIdlReflection)UnoRuntime.queryInterface(
XIdlReflection.class, oReflection);
System.out.println(">>> Reflection service fetched");
//**** 3.2 - Using XIdlReflexion.forName() like Class.forName() in Java
XIdlClass xClazz = xReflection.forName("com.sun.star.uno.XInterface");
if (xClazz != null) {
System.out.println(">>> IdlClass found: " + xClazz.getName());
// Check for it's methods
System.out.println(">>> Methods:");
//**** 3.3 - A simple use of XIdlClass to list the methods
XIdlMethod[] methods = xClazz.getMethods();
for (int i=0; i<methods.length; i++) {
System.out.println(" * " + methods[i].getName());
}
} else {
System.out.println(">>> No IdlClass found");
}
The rest is the normal ending of a try-catch block and is provided only for the reader to copy-paste the code.
} catch (Exception e) {
e.printStackTrace();
}
System.exit(0);
So you can imagine that I will now have a lot of work to integrate this in the plugin, but you will have it in an indetermined delay... depending on my time.