This document provides an introduction to developing k42
applications in Java. The complete reference to the API may be found
here. The major aspects of k42 are
introduced gradually using simple examples. The approach to topicmap
development and manipulation is shown.
The
K42_HOME/docs/files directory
contains a Java file with the code used in this guide, and an XTM compliant
file containing the topicmap produced.
Getting Started
See the Installation Guide for information on
installing and setting up the k42 application server.
To begin developing a k42 client application you will need to
use the
com.empolis.topicmaps.client.K42Client class to
obtain a handle to the topicmap.
K42Client
Using an instance of this class will make it easy to get
going, the code below shows a Java source file that hooks into the k42 system.
import com.empolis.topicmaps.client.K42Client; import com.empolis.topicmaps.ik42.*; import java.io.*; class K42Developer { public static void main(String[] args) { K42Client client = new K42Client("C:\\k42\\guide.props"); // new code to follow here } }Ensure that the property file, referred to, exists and is available on your system. This file can be used to store a number of properties, all of which have default values. The first time you run the program, you will find a new file named base.ps , created in the same directory as the
property file. The property file reference may be found in Appendix A of this
document.
ITopicMap
The top-level interface in a k42 system is
the
com.empolis.topicmaps.ik42.ITopicMap . The
K42Client makes it easy to retrieve a
ITopicMap object:ITopicMap tm = client.getTopicMap(); // To clear any existing topicmap data call tm.clear(); tm.clear();The ITopicMap object will enable you to create various
topicmap constructs, such as: topics, topic associations, names, and
occurrences.
As an example: subject, music, and specifically The Beatles,
will be used throughout this document. Start by creating a topic to represent
the group within the topicmap.
ITopic theBeatles = tm.createTopic(); theBeatles.addName("The Beatles");This shows the use of the ITopicMap interface to create
a topic, then the ITopic interface to add a name to that
topic.
What Can You Do Now?
Now is a good time to get familiar with the k42 iterators.
Many methods of the IK42 API return typed iterators. That is, the standard
Java
java.util.Iterator class is not returned (although
all k42 iterators extend this class), and the requirement to cast object types
is significantly reduced.
The code below shows two typed iterators in use:
ITopicIterator topics = tm.getTopics(); while (topics.hasNext()) { INameIterator names = topics.nextTopic().getNames(); while (names.hasNext()) { System.out.println("Topic found with name : " + names.nextName().getValue()); } }You can also retrieve your named topic from the topicmap directly: ITopic topic = tm.getTopicByName("The Beatles"); Topic Classes
With a k42 topicmap, you can create connections between the
k42 objects. There are many different types of associations within topicmaps.
One of the predefined association types is the instanceof association.
This used to enable object oriented techniques to be applied within topicmaps.
In the example below, The Beatles topic is to be made an instance of
the topic
class:Group .
ITopic group = tm.createTopic(); group.addName("class:Group"); theBeatles.addInstanceOf(group);
An object can be an instance of more than one class. More to
the point, any topic can be referred to as a class. A useful convention to
follow, is to use a name like "class:xxxx" to identify topics that are
only be to used as classes, or to make all topics used as classes instances of
a topic called "Class". Also, to avoid confusion, it is useful to restrict
topics to be instances of single classes.
Using this technique further, class topics can be added to
help organise the topicmap.
ITopic class_human = tm.createTopic(); class_human.addName("class:Human"); ITopic class_record = tm.createTopic(); class_record.addName("class:Record"); ITopic class_song = tm.createTopic(); class_song.addName("class:Song"); More Topics
More relevant topics may now be added to the map:
// The group members ITopic john = tm.createTopic(); john.addName("John Lennon"); john.addInstanceOf(class_human); ITopic paul = tm.createTopic(); paul.addName("Paul McCartney"); paul.addInstanceOf(class_human); ITopic george = tm.createTopic(); george.addName("George Harrison"); george.addInstanceOf(class_human); ITopic ringo = tm.createTopic(); ringo.addName("Ringo Star"); ringo.addName("Richard Starkey"); ringo.addInstanceOf(class_human); // A couple of albums ITopic letItBe = tm.createTopic(); letItBe.addName("Let It Be"); letItBe.addInstanceOf(class_record); ITopic abbeyRoad = tm.createTopic(); abbeyRoad.addName("Abbey Road"); abbeyRoad.addInstanceOf(class_record); Class Hierarchy
Topics that act as classes can have superclass topics to
further support the object model, by making use of
the
addSuperClass method on the ITopic interface.ITopic class_media = tm.createTopic(); class_media.addName("class:Media"); ITopic class_mammal = tm.createTopic(); class_mammal.addName("class:Mammal"); ITopic class_primate = tm.createTopic(); class_primate.addName("class:Primate"); class_primate.addSuperClass(class_mammal); class_human.addSuperClass(class_primate); class_record.addSuperClass(class_media); Querying class topics
Class topics can be used to find groups of topics that are
instances of that class.
ITopicIterator humans = class_human.getInstances(); ITopicIterator records = class_record.getInstances(); ITopicIterator classes = class_class.getInstances();You can also investigate the superclass/subclass structures using getSuperClasses()
andgetSubClasses() .
Topic Associations
ITopicAssociation instances are the k42
objects that link topics together. In a topic association, a number of topics
each play a role within an association instance. For example, a "Loves"
association, would have roles for "Lover" and "Loved One". A role is also a
topic.
k42 simplifies the association creation mechanisms to an
extent through the support of association templates, and these are used in the
code examples below. The explicit requirement for role topics also encourages
consideration of the differences between roles and classes.
ITopic bandMember = tm.createTopic(); bandMember.addName("role:Band Member"); ITopic band = tm.createTopic(); band.addName("role:Band"); ITopicAssociation bandMembership = tm.createAssociationTemplate(bandMember, class_human, band, class_group); bandMembership.addName("Band Membership");That is all that is necessary to create an association template. It is useful to be able to read the association information and present the data in an intuitive way. It is now possible to create association instances and retrieve data. bandMembership.creat
"Paul McCartney" plays the role "role:Band Member" in
association "Band Membership" with "The Beatles" playing the role
"role:Band".
Whereas what you would really like to say, in addition to the
above, is:
Paul McCartney is a member of The
Beatles.
So, what can you do to get that kind of data from the
association?
Names in Scopes
In a topicmap, the names of topics, and topic associations can
be given a scope. A scope is defined by a set of topics. In k42, this set of
topics is given an identity, and is called a scopeset.
ITopicMap provides a method to retrieve a
IScopeSet instance when passed an array of
topics.
Scopesets may be used to define the arc labels between two
roles within the association template:
IScopeSet ss1 = tm.getScopeSet(new ITopic[] {bandMembership, band}); bandMember.addName("has member", ss1); IScopeSet ss2 = tm.getScopeSet(new ITopic[] {bandMembership, bandMember}); band.addName("is a member of", ss2);As this process is consistent for creating all association templates, utility methods have been provided for use in the com.empolis.topicmaps.helper.Builder
class, specifically the createAssociationTemplate method.
You can now use this method to create another template:ITopic role_recordMaker = tm.createTopic(); role_recordMaker.addName("role:Record Maker"); ITopic role_madeRecord = tm.createTopic(); role_madeRecord.addName("role:Made Record"); ITopicAssociation makesRecord = builder.createAssociationTemplate( "Makes Record", class_group, role_recordMaker, "makes", class_record, role_madeRecord, "made by");Using these templates, association instances can be created for the primary topics: bandMembership.createInstance(band, theBeatles, bandMember, john); bandMembership.createInstance(band, theBeatles, bandMember, paul); bandMembership.createInstance(band, theBeatles, bandMember, george); bandMembership.createInstance(band, theBeatles, bandMember, ringo); makesRecord.createInstance(role_recordMaker, theBeatles, role_madeRecord, letItBe); makesRecord.createInstance(role_recordMaker, theBeatles, role_madeRecord, abbeyRoad);In order to retrieve the arc labels that have been defined for the roles, the IAssociationArc interface provides access to the arc
string and the target Topic. IAssociationArc s are
retrieved fromIAssociationEnd objects, contained within
ITopicAssociation objects. Consider the following code:IAssociationEnd end = bandMembership.getEnd(bandMember); IAssociationArcIterator templateArcs = end.getArcs(); IAssociationArcIterator instanceArcs = theBeatles.getAssociationEnds().getAssociationArcs();where instanceArcs represents all the arc objects that
connect theBeatles topic to other
topics.
Generic Roles
The specification of the role topic can sometimes appear
difficult. Although, well chosen role topics can add significantly to the
semantic content of the topicmap, a simpler pattern is available for the
majority of associations, and that is to specify more generic topics for the
roles:
ITopic role_agent = tm.createTopic(); role_agent.addName("role:Agent"); ITopic role_object = tm.createTopic(); role_object.addName("role:Object");The two templates above could then be created as follows: ITopicAssociation bandMembership = createTemplate(tm, "Band Membership", class_group, role_agent, "has member", class_record, role_object, "is a member of"); ITopicAssociation makesRecord = createTemplate(tm, "Makes Record", class_group, role_agent, "makes", class_record, role_object, "made by");This example indicates a problem; some associations fit more comfortably into agent-object roles than others. The distinction between the roles in any association, should always be clear. Examining Associations
There are many methods within k42 that allow you to examine
associations. Possible calls are:
ITopicAssociationIterator templates = tm.getAssociationTemplates(); ITopicAssociation template = tm.getAssociationByName("Band Membership"); ITopicAssociationIterator assocs = template.getTemplateChildren(); assocs = theBeatles.getAssociations(); ITopicIterator topics = theBeatles.getAssociatedTopics(); Topic Occurrences
In k42 a resource, as specified by a URI, is represented by a
topic. These resources can be created explicitly or implicitly, as shown in the
following code:
ITopic resource = tm.createResource("http://www.theBeatles.com"); ITopicOccurrence occur1 = theBeatles.createOccurrence(resource); ITopicOccurrence occur2 = john.createOccurrence("http://www.theBeatles.com"); if (resource == occur2.getResource()) { System.out.println("The resource has identity!"); } ITopicOccurrence occur3 = ringo.createOccurrence("http://wwww.theBeatles.com/ringo.html"); What Next?
A good approach is to experiment with the k42 API. Not all k42
concepts have been introduced in this document, but you have seen enough to be
able to get started and produce useful topicmaps.
The
k42 Concepts Guide
and
k42 API Documentation
should now become your main reference documents.
Appendix A: Property File Reference
The property file can be used to override defaults for a
number of purposes; the syntax used, is for a standard Java property file. When
processing the property file, the K42Client will first look for a specified RMI
server; if one is found, then an attempt is made to connect to the server. The
Installation Guide gives information on how to setup an RMI Server. If no
server is specified, the
K42Client will attempt to
initialise a local environment, using the specified storage file, if present.
The K42Client will then retrieve the named topicmap
object, using a default name, if none is specified.
Appendix B: Plugins
Plugins enable instances of classes derived from
the
com.empolis.topicmaps.k42.K42PlugIn class to be
loaded on start-up of a k42 RMI Server VM. Each K42PlugIn must have a default
constructor to support instance creation from the provided classname, and must
provide an implementation for the following method:
void initialize(ITopicMap tm, Properties properties)
A plugin could be used for any number of reasons. For example:
a plugin could carry out some validity check, or ensure some minimum data
initialisation.
In k42, plugins are used to implement services for TopicMap
Viewer and WebAuthor. The technique used here is for the plugins to provide
custom socket interfaces directly into the server VM, avoiding the overhead of
repeated communication over RMI.
Appendix C: RMI Clients
This is simply a case of defining the correct properties in
the property file. All that is necessary is to provide a value for
the
empolis.rmiserver property. The RMI client will
start-up and try to connect to the named RMI server.
Appendix D: TopicMap Query Language (TMQL) User
Guide
TMQL is a querying mechanism for topicmaps. It allows the
user to select single or multiple topics, occurrences, associations, roles etc.
based on an SQL-like syntax.
Using TMQL
TMQL can be used through the k42 API for topicmaps. In order
to use TMQL in this way, you need to import the
QueryMgr
class:
import com.empolis.topicmaps.tmql.QueryMgr;You can then create an instance of the QueryMgr class
which can be used to execute queries. The constructor for the
QueryMgr class must be passed
anITopicMap instance which is the topicmap to make
queries on.
// tm is an ITopicMap instance of the topic map to make queries on QueryMgr tmqlParser = new QueryMgr(tm);The QueryMgr can then be used to execute queries. The
results of queries are stored in an IQueryResult object.
The IQueryResult class is in the same package as
QueryMgr . There are various ways that a
QueryMgr
can be used to execute TMQL queries. They all return
IQueryResult objects. The main method takes a string
parameter which is the TMQL query. For example: IQueryResult res =
tmqlParser.executeQuery("SELECT topic x WHERE x in
assoc"); The
QueryMgr object can also hold the
current query string in a StringBuffer . This means that
you can build up the query before executing it. To execute the currently stored
query, the executeQuery method of
QueryMgr is called without arguments. For example:tmqlParser.setCurrentQuery("SELECT topic x WHERE x in assoc"); tmqlParser.getCurrentQuery().append(" AND x named 'myTopic'"); IQueryResult res = tmqlParser.executeQuery();
It is also possible to execute queries using the results of
previous queries. If, for example, we wanted to find all of the topics with a
particular name and then find the subset of those topics that were in
associations, we could do the following:
IQueryResult res1 = tmql.executeQuery("SELECT topic x WHERE x named name is 'myName'"); IQueryResult res2 = tmql.executeQuery("SELECT topic x WHERE x in assoc", res1);By passing the results of the first query into the second, we are telling the TMQL query manager to only use values of x that are in the first query, rather than all possible topics. It is in effect a way of ANDing the two queries. Copyright (c) empolis UK LTD. All rights reserved.
|