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.

Download the whole code now

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.