The TM4J Basic Indexes

This section describes the basic indexes provided with TM4J. All back-ends must support this set of basic indexes and the basic indexes must always be registered with the IndexManager returned by calling the TopicMap.getIndexManager() method. For a developer using these indexes, this means that there is never any need to worry about registering an IndexProvider to access these indexes - that has already been done.

The following table shows the index interfaces provided by the basic index provider and the accessor methods provided by each one.

Table 6.1. TM4J Basic Indexes

Index

Method

Description

org.tm4j.topicmap.index.basic.AssociationTypesIndex
 getAssociationsOfType(Topic t) Returns all associations in the topic map which are typed by the topic t
 getAssociationTypes() Returns all Topics which type one or more Associations in the topic map.
org.tm4j.topicmap.index.basic.MembersTypesIndex
 getMembersOfType(Topic t) Returns all Member objects whose role spec is defined by the topic t
 getMemberTypes() Returns all Topic objects which are used to define the roleSpec of one or more Member objects.
org.tm4j.topicmap.index.basic.OccurrenceLocatorIndex
 getOccurrencesOfLocator(Locator loc) Returns all Occurrence object's whose dataLocator property matches loc
org.tm4j.topicmap.index.basic.OccurrenceTypesIndex
 getOccurrencesOfType(Topic t) Returns all Occurrence objects whose type is defined by the topic t
 getOccurrenceTypes() Returns all Topic objects which are used to define the type of one or more Occurrence objects.
org.tm4j.topicmap.index.basic.ThemesIndex
 getScopedObjects() Returns a collection containing all of the ScopedObject objects contained in the TopicMap.
 getScopedObjects(Topic theme) Returns a collection containing all of the ScopedObjects contained in the TopicMap for which theme is one of the topics in the scope of the ScopedObject.
 getScopedObjects(Topic[] themes, int match) Returns a collection containing all of the ScopedObjects whose scope matches the collection of Topics specified in the themes parameter. How the matching is done depends on the value of the match parameter. With a value of ThemesIndex.SCOPE_MATCH_ALL, then the scope of the ScopedObjects returned will contain all of the topics specified in the themes parameters. With a value of ThemesIndex.SCOPE_MATCH_ANY, the scope of the ScopedObjects returned will contain one or more of the Topics specified in the themes parameter. With a value of ThemesIndex.SCOPE_MATCH_EXACT, the scope of the ScopedObjects returned will contain only those Topics specified in the themes parameter.
 getThemes() Returns all Topic objects which are used as part of the scope of one or more ScopedObjects.
org.tm4j.topicmap.index.basic.TopicTypesIndex
 getTopicsOfType(Topic t) Returns all Topic objects for which t is one of the types.
 getTopicsOfTypes(Topic[] types) Returns all Topic objects for which all of the topics in types are also in the set of types of the topic.
 getTopicTypes() Returns all Topic objects which are used to define the type of one or more Topic objects.

Example 6.1. Using the TM4J Basic Indexes

The following code shows how to retrieve an index of interest for a specific topic map. Depending upon your application, you may choose to do this just once when the topic map is loaded or to open and close the index as required. Although different implementations may vary, if writing your code to be portable across multiple implementations of the TM4J backend, it is wise to assume that opening reindexing operations may involve a significant overhead, and so to cache open indexes wherever possible.

// Assuming that the topic map is already initialised
// and held in the variable tm.

// Get the index manager for the topic map
IndexManager im = tm.getIndexManager();

// (Optional but recommended) - retrieve the meta data for the index
IndexMeta meta = im.getIndexMeta(TopicTypesIndex.class);

// Get the index itself
// NOTE: You only have to do one of these in your code!
// Option 1: by class name (useful when configured from a properties file)
TopicTypesIndex ix = (TopicTypesIndex)im.getIndex("org.tm4j.topicmap.index.basic.TopicTypesIndex");

// or Option 2: by class
ix = (TopicTypesIndex)im.getIndex(TopicTypesIndex.class);

// check to see if an open() or reindex is required
// Note that by definition, opening an index *must* mean that it is uptodate
// so don't open and then reindex - that would add extra overhead
if (!ix.isOpen())
  ix.open()
else if (!meta.isAutomaticallyUpdated())
  ix.reindex()

// Now the index is ready for use
// To use the index, call the methods that the
// interface defines. For example:
Collection results = ix.getTopicsOfType(type);

// If you wish to release the index:
ix.close();

Extending The TM4J Indexes

Example 6.2. Sample Code - Using IndexProviders

The following code shows how to apply a new IndexProvider to an IndexManager.

// Assuming that the topic map is already initialised
// and held in the variable tm.

// Assuming, also that the new IndexProvider interface is
// com.mycorp.tm4j.index.MyIndexProvider

// Note that if you have imported the pacakge symbols for 
// MySpecialIndex and MyIndexProvider explicitly, you can omit the
// long package names.

// Get the index manager fro the topic map
IndexManager im = tm.getIndexManager();

// Get a new instance of MyIndexProvider
IndexProvider myIxProvider = new com.mycorp.tm4j.index.MyIndexProvider();

// Register the IndexProvider
im.registerIndexProvider(myIndexProvider);

// We can now access the index interfaces that MyIndexProvider provides:
com.mycorp.tm4j.index.MySpecialIndex specialIndex = 
    (com.mycorp.tm4j.index.MySpecialIndex) im.getIndex (
                   com.mycorp.tm4j.index.MySpecialIndex.class);

Example 6.3. Sample Code - Creating a new IndexProvider

The following code sample shows a customised IndexProvider implementation which provides access to a single index. Although the code shown here has only one index in the provider, the pattern can be easily extended to support multiple indexes. You can find all of this code and the supporting files as well as a test application to run it in the examples subdirectory of your TM4J installation.

package examples.indexes;

import org.tm4j.topicmap.TopicMap;
import org.tm4j.topicmap.Occurrence;

import org.tm4j.topicmap.index.Index;
import org.tm4j.topicmap.index.IndexMeta;
import org.tm4j.topicmap.index.IndexMetaImpl;
import org.tm4j.topicmap.index.IndexProvider;

/**
 * A sample custom index provider.
 * <p>This index provider manages just one index implementation, however 
 * the basic design is extensible to support multiple indexes in a single
 * provider.</p>
 */

public class CustomIndexProvider implements IndexProvider
{
    /**
     * The class names of the indexes provided by this IndexProvider.
     */
    private static final String[] indexNames = { 
        "examples.indexes.CustomIndex" 
    };
    
    /**
     * The classes of the indexes provided by this IndexProvider. 
     * Note that these are in the same order as the class names in
     * <code>indexNames</code>
     */
    private static final Class[] indexClasses = { 
        examples.indexes.CustomIndex.class };

    /**
     * An array to hold the index instances once the index provider is
     * initialised.
     */
    private Index[] indexInstances  = null;

    /**
     * An array to hold the index meta data objects once the index 
     * provider is initialised.
     */
    private IndexMeta[] indexMeta = null;

    // Implementation of the IndexProvider interface:

    /**
     * Returns the class names of the indexes provided by this class.
     */
    public String[] getIndexNames() 
    {
	return indexNames;
    }

    /**
     * Returns the index with the specified class name.
     * @param interfaceName the full class name of the index required.
     */
    public Index getIndex(String interfaceName)
    {
	for(int i = 0; i < indexNames.length; i++)
	{
	    if (interfaceName.equals(indexNames[i]))
	    {
		return indexInstances[i];
	    }
	}
	return null;
    }

    /**
     * Returns the index which implements the specified class.
     * In this implementation we are not using interfaces to hide the index
     * implementation so <code>interfaceClass</code> is expected to be the
     * actual implementation class of the index to be returned.
     * @param interfaceClass the class of the required index or the
     *                       interface that it implements.
     */
    public Index getIndex(Class interfaceClass)
    {
	for(int i = 0; i < indexClasses.length; i++)
	{
	    if (interfaceClass.equals(indexClasses[i]))
	    {
		return indexInstances[i];
	    }
	}
	return null;
    }

    /**
     * Returns the meta data for the specified index.
     * @param interfaceName the name of the class of index to return
     *                      meta data for or the interface that the
     *                      index implements.
     */
    public IndexMeta getIndexMeta(String interfaceName)
    {
	for(int i = 0; i < indexNames.length; i++)
	{
	    if (interfaceName.equals(indexNames[i]))
	    {
		return indexMeta[i];
	    }
	}
	return null;
    }

    /**
     * Method invoked when the provider is registered with an IndexManager.
     * <p>This implementation uses this method to intialise the indexes and
     *    index meta data.</p>
     * @param tm the TopicMap to which the IndexProvider must bind its indexes.
     */
    public void initialise(TopicMap tm)
    {
	indexInstances = new Index[1];
	indexInstances[0] = new CustomIndex(tm);

	indexMeta = new IndexMeta[1];
	indexMeta[0] = new IndexMetaImpl(false, false);
    }

}

Example 6.4. Using a Custom Index Provider

The code snippet below shows how the custom index provider shown above can be used in a TM4J application.

TopicMap tm;

// Get the topic map
....

// Get the IndexManager which binds all indexes to the topic map
IndexManager ixMgr = tm.getIndexManager();

// Create the custom IndexProvider we wish to use with the topic map
CustomIndexProvider custIxProvider = new CustomIndexProvider();

// Register the custom IndexProvider with the IndexManager
ixMgr.registerIndexProvider(custIxProvider);

// Now we can get the indexes that the IndexProvider provides directly
// from the IndexManager.
CustomIndex custIx = (CustomIndex)ixMgr.getIndex(CustomIndex.class);

// Open the index and use it
custIx.open();

System.out.println(
  "Looking for all occurrences from authority: " + searchDomain);

Collection occs = custIx.getOccurrencesByAuthority(searchDomain);

System.out.println(
  "  Found " + occs.size() + " occurrences from authority " + searchDomain);

Iterator it = occs.iterator();
while (it.hasNext())
{
  Occurrence occ = (Occurrence)it.next();
  System.out.println("    " + occ.getDataLocator().getAddress());
}

// All done! Close the index to release any resources that it used
custIx.close();