DeepaMehta Development Guide


Introduction
Defining topic model
Implementing topic behavoir
     Overriding Hooks
     Building Directives
     Building Commands
     Topic Life Cycle
     Accessing Corporate Datasources
     Exception Handling
     LiveTopic Support
Building a Web Application
     Writing the Controler Servlet
     Writing JSP pages
     Writing the JSP Header
     Writing the Java Interface
     Using the HTML generator
     Using the DeepaMehta Basis Servlet
Using the Application Service
     Access live topics
     Navigation
     Get properties
     Set properties
     Create topics
Accessing the Corporate Memory
Writing Corporate Memory Patches



Introduction

DeepaMehta applications are developed in the scope of the DeepaMehta application framework. The DeepaMehta application framework is topic map centric, actually a DeepaMehta application is a collection of topic types and association types. Types can be build by derivation. Topics of new defined types have standard behavoir, custom behavoir can be realized by writing one Java class for the respective type.

Developing a DeepaMehta application involves the following steps

  1. Identify the topic types and/or association types your application consists of.
  2. for each topic type/association type:
    1. Identify the supertype.
      The new type will derive all properties as well as behavoir from the supertype. The root of the topic type hierarchy is the topic type Topic. The root of the association type hierarchy is the association type generic.
    2. Identify the properties.
      Once you have identified the supertype and properties you can add the type to the corporate memory, see section Defining topic model.
    3. Specify the behavoir.
      If standard behavoir is sufficient, nothing more is to do. Custom behavoir can be implemented by means of the DeepaMehta-Application-Framework. A type with custom behavoir is represented as one Java sourcecode file. Topic development can be accomplished by entry-level programmers, no special java knowledge is required.
Is the DeepaMehta-Application-Framework required to be extended, in regards of The Development of the framework itself can only be accomplished by expert-level software engineers.


Defining topic model




Implementing topic behavoir

package de.deepamehta.topics;

import de.deepamehta.BaseTopic;
import de.deepamehta.service.ApplicationService;

public class SampleTopic extends LiveTopic {

	// *******************
	// *** Constructor ***
	// *******************

	public SampleTopic(BaseTopic topic, ApplicationService as) {
		super(topic, as);
	}
}
This is the absolute minimum sourcecode of a topic with custom behavoir. This is already functional but apparently provides no special behavoir. But we can recognize some essentials: Then certain hooks will be overridden, depending on the intended application bahavoir.

As any Java class your class can provide its own methods (called directly or indirectly by the hooks you will override) and can utilize further classes.

Overriding Hooks

Overriding any hook is optional, but apparently a Topic with reasonable custom behavoir will override at least one hook. Which hooks you're required to overridde depends on the intended application bahavoir. Every hook has a reasonable default implementation in the LiveTopic baseclass.

For every hook you override: Think about calling the implementation of the superclass.

Building Directives

In general the task performed by (most) hooks is building and returning directives. Building the directives may involve building the parameter objects required by the directives.

In addition to the apparent client side effect each directive has, at server side the corporate memory is updated programatically. You must keep that in mind when manipulating the corporate memory yourself resp. when using the application application service. You can control the programatical update process by using the gray marked parameters as shown in the detailed description for every directive.

The programatical update of the corporate memory is performed in CorporateDirectives.updateCorporateMemory()

Building Commands

Building commands (provided by de.deepamehta.Commands)
void addCommand(String label, String command)
void addCommand(String label, String command, String iconpath, String iconfile)
void addCommand(String label, String command, String iconpath, String iconfile, int commandState)
void addCommand(String label, String command, int commandState)
Commands addCommandGroup(String label)
Commands addCommandGroup(String label, String iconpath, String iconfile)
void addSeparator()
void add(Commands commands)
static final int COMMAND_STATE_DEFAULT = 0;
static final int COMMAND_STATE_DISABLED = 1;
static final int COMMAND_STATE_SELECTED = 2;
static final int COMMAND_STATE_RADIOBUTTON = 4;
static final int COMMAND_STATE_CHECKBOX = 8;
Utilities for building commands (provided by de.deepamehta.service.CorporateCommands)
void addTopicCommands(Commands cmdGroup, Vector topics, String command, int commandState, BaseTopic selectedTopic, String title, Session session, CorporateDirectives directives)
void addTopicCommands(Commands cmdGroup, Vector topics, String command, int commandState, String selectedTopicID, String title, Session session, CorporateDirectives directives)
void addTopicCommands(Commands cmdGroup, Vector topics, String command, int commandState, Vector selectedTopicIDs, String title, Session session, CorporateDirectives directives)
topics -- For every topic in this vector a command is added.
Vector of topics (BaseTopic) or topic IDs (String)

Topic Life Cycle

Accessing Corporate Datasources

Exception Handling

LiveTopic Support

Hashtable getProperties()
String getProperty(String propName)
String getProperty(BaseTopic topic, String propName)
void createChildTopic(String typeID, String semantic)
void createChildTopic(String typeID, String semantic, Session session, CorporateDirectives directives)



Building a Web Application

Building a web application with DeepaMehta means creating a web interface for a specific task and a corporate design with the DeepaMehta application server as underlying infrastructure. A DeepaMehta web application is build in the context of Servlet/JSP technology.

Prerequisits: Servlet-Engine like Tomcat (Apache Group)

DeepaMehta infrastructure you can build on

To build a DeepaMehta web application you must write Note: The last 2 tasks are not mandatory in the sense of the framework, rather they matter of style. However, the last 2 tasks are the recommended style you should adopt for you own web applications and the remainder of this documentation follows this style.

Writing the Controler Servlet

The controller servlet you have to write acts as the "central processing unit" of your web application. For every request the webbrowser sends the controller processes it by assistance of the DeepaMehta application service and sends back an HTML page as the result. To write a controller servlet the application programmer neither needs special kowledge of the Servlet/JSP APIs nor about the DeepaMehta API because the DeepaMehta basis servlet does the low-level tasks and enables the programmer to simply "plugin" the specific application logic.

The DeepaMehta basis servlet imposes some structure to your web application: every request must contain an "action" parameter which tells the controller what to do next. The controller processes the request and passes the resulting data along with a JSP page to the JSP engine which finally renders the HTML reply. The DeepaMehta basis servlet has 2 protected methods which are overridden by the application programmer to implement the actual website logic.

To write the controller servlet you must derive it from the DeepaMehta basis servlet (de.deepamehta.service.web.DeepaMehtaServlet), override the performAction() method and eventually preparePage(). The controller servlet can be put into any package, the default package is fine for now.
public class MusicServlet extends DeepaMehtaServlet implements Music {

    protected String performAction(String action,
                                   RequestParameter params,
                                   Session session) throws ServletException {
    }

    protected void preparePage(String page,
                                     RequestParameter params,
                                     Session session) throws ServletException {
    }
}

Writing JSP pages

Writing the JSP Header

<%@ page import="de.deepamehta.BaseTopic" %>
<%@ page import="de.deepamehta.service.web.Action" %>
<%@ page import="de.deepamehta.service.web.HTMLGenerator" %>
<%@ page import="de.deepamehta.service.web.TopicTree" %>
<%@ page import="de.deepamehta.topics.TypeTopic" %>
<%@ page import="de.deepamehta.topics.music.Music" %>
<%@ page import="java.io.IOException" %>
<%@ page import="java.util.Vector" %>
<%@ page import="java.util.Hashtable" %>

<%!
    void begin(HttpSession session, JspWriter out) throws IOException {
        BaseTopic user = (BaseTopic) session.getAttribute("user");
        Vector roles = (Vector) session.getAttribute("roles");
        String section = (String) session.getAttribute("section");
        //
        out.println("<HTML>\r<HEAD>\r<TITLE>Music</TITLE>\r</HEAD>\r" +
            "<BODY bgcolor=\"white\">");

    }

    void end(JspWriter out) throws IOException {
        out.println("<P>\r<HR>\r<SMALL>Current time: " + new java.util.Date() +
            "</SMALL>\r</BODY>\r</HTML>");
    }
%>

Writing the Java Interface

The Java interface declares symbolic constants which are representing entities of your application. Then, inside your java code you can use these constants to refer to the respective entities. All declared constants will be valid in The following shows the beginning of the interface for a "Music" application. Put the interface in the package of your application (see the package directive). Import DeepaMehtaConstants and derive your interface from that interface. Only constant declarations are contained in the interface.
package de.deepamehta.topics.music;

import de.deepamehta.DeepaMehtaConstants;

public interface Music extends DeepaMehtaConstants {

    // *****************
    // *** Constants ***
    // *****************

    // -----------------
    // --- Workspace ---
    // -----------------

    static final String WORKSPACE_MUSIC = "t-music";

    // -------------------
    // --- Topic Types ---
    // -------------------

    static final String TOPICTYPE_CD = "tt-cd";
    static final String TOPICTYPE_INTERPRET = "tt-interpret"

    ...
}
The examples shows only the workspace and some topic types. A typical interface will define

Using the HTML generator

For every HTTP session the DeepaMehta basis servlet sets an session attribute with name "html", the value is the HTML generator, an instance of de.deepamehta.service.web.HTMLGenerator. Thus every JSP page can use the HTML generator this way:
<%
    HTMLGenerator html = (HTMLGenerator) session.getAttribute("html");
    //
    out.println(html.info(topicID));
%>
This example generates the information of one topic, the topic is specified by its ID. The following provides an overview of all the HTMLGenerator methods you can use:
String info(String topicID)
String info(String topicID, String[] propSel)
String info(String topicID, String[] propSel, boolean hideSel)
String list(Vector topics)
String list(Vector topics, String[] propSel)
String list(Vector topics, Action[] actions)
String list(Vector topics, String[] propSel, Action[] actions)
String list(Vector topics, Hashtable extraTopics)
String list(Vector topics, String[] propSel, String infoAction, Hashtable extraTopics)
String list(Vector topics, String[] propSel, Action[] actions, String infoAction)
String list(Vector topics, String[] propSel, Action[] actions, Hashtable colWidths)
String list(Vector topics, String[] propSel, Action[] actions, String infoAction, Hashtable colWidths)
String list(Vector topics, String selectedID, String[] propSel, String infoAction, String infoActionParams)
String list(Vector topics, String selectedID, String[] propSel, Action[] actions, String infoAction, String infoActionParams, Hashtable colWidths)
String list(Vector topics, String selectedID, String[] propSel, boolean hideSel, Action[] actions, String infoAction, String infoActionParams, Hashtable colWidths)
String list(Vector topics, String selectedID, String[] propSel, boolean hideSel, Action[] actions, String infoAction, String infoActionParams, Hashtable colWidths, Hashtable extraTopics)
String form(String typeID, String action)
String form(String typeID, String action, String id)
String form(String typeID, String action, String[] propSel)
String form(String typeID, String action, String[] propSel, boolean hideSel)
String form(String typeID, String action, String id, String[] propSel)
String form(String typeID, String action, String id, String[] propSel, boolean hideSel)
String tree(TopicTree tree)
String tree(TopicTree tree, Action[] actions, Vector extended, String highlighted)
String tree(TopicTree tree, Action[] actions, String infoAction, Vector extended, String highlighted)
String tree(TopicTree tree, Action[] actions, String infoAction, Vector extended, String highlighted, int pageNr, int pageSize)
String tree(TopicTree tree, Action[] actions, String infoAction, Vector extended, String extendedParams, String highlighted, int pageNr, int pageSize)
String treeForm(TopicTree tree, String action, String fieldname, String cardinality, Vector selected, Vector extended)
String treeForm(TopicTree tree, String action, String fieldname, String cardinality, Vector selected, Vector extended, String extendedParams)
String message(String key)
String message(String key, Object arg)
String message(String key, String keyNo, String keyOne, String keyMany, Object arg)
String link(String text, String action)
String link(String text, String action, String params)
String linkList(Vector topics, String action)
String staticLink(String text, String link)
String staticLink(String text, String link, String target)
String listHeading(int count, String text, String sing, String plur) *** deprecated, use multi-lingual message() with 5 params instead
String actionButton(String topicID, String action, String iconfile)
String topicChooser(String typeID)
String propertyField(PropertyDefinition propDef, String propValue)
String submitButton(String action)
String imageTag(BaseTopic topic)
String imageTag(BaseTopic topic, boolean withTooltip)
String displayObjects(Vector displayObjects)
info() renders all information about a single topic in table format (one property per row). The most simple form just requires the ID of the topic (if topicID is set to null nothing is rendered). If the propSel parameter is set only the specified properties are rendered (propSel is an array of property names, if null all properties are rendered). If the hideSel parameter is set to true the meaning of the propSel parameter is reversed: all specified properties are not rendered (if propSel is null all properties are still rendered). Properties should be declared in the Java Interface (see above).

list() renders a list of topics in table format (one topic per row, one property per column). The most simple form requires just a vector of topics (type BaseTopic) as returned by most of the corporate memory access methods (see Accessing Corporate Memory). The propSel and hideSel parameters are just the same as with the info() method. If the actions parameter is set every topic is rendered with additionally (imaged) links (if empty or null no no additional links are rendered, the class Action is found in de.deepamehta.service and is just a action-image pair). If the infoAction parameter is set, each topic itself is rendered as link that fires the set action (if null the topic is not rendered as link). If the colWidths parameter is set, the columns are rendered using the specified column widths. The widths (in pixel) are hashed by property name. Properties as well as Actions should be declared in the Java Interface (see above).

form() renders a form for editing topic information. The first 2 parameters are mandatory: typeID specifies the type of the topic being edited. All form elements are created automatically based on the respective type definition, furthermore a "Save" button is created. The action parameter represents the action fired by the "Save" button. If the id parameter is set the informations for the respective topic is presented for being edited, if the id parameter is not set empty fields are presented for entering the information for a new topic instance. The propSel and hideSel parameters are just the same as with the info() method. Topic Types, Properties and Actions should be declared in the Java Interface (see above).

tree() renders a tree of topics. There are 2 features: 1) the user can collapse/extend subtrees by clicking a triangle, if this feature is switched off the whole tree is extended and no triangles are shown, and 2) a large tree can be rendered over several pages while the user can step backward/forward between the pages, if this feature is switched off the whole tree is displayed on one page. In any case one parameter is mandatory: the tree parameter represents the topics to be rendered (the class TopicTree is found in de.deepamehta.topics.helper). For creation of TopicTree objects, the DeepaMehta basis servlet provides the getTopicTree() methods (see ###). The actions and infoAction parameters are just the same as with the list() method. The highlighted parameter is the ID of a topic which is visually highlighted (if null or the specified topic is not part of the tree, no topic is highlighted). Note: rendering begins with the direct child-nodes of the root-node, the root-node itself is never rendered.

To use the "collapse/extend" feature the extended vector must be specified and the ACTION_COLLAPSE_NODE and ACTION_EXTEND_NODE actions must be handled. The extended vector contains the IDs of the extended topics, all other topics are regarded as collapsed. To switch off the collapsable feature set extended to null. Note: in order to keep the collapse/extend states you must hold the extended vector as a sesstion attribute. At least the root-topic should be extended, otherwise no topics are rendered. To use the "several pages" feature, set the pageNr (begins with 0) and pageSize (number of toplevel nodes per page) parameters and handle the ACTION_PREV_PAGE and ACTION_NEXT_PAGE actions. Note: the "several pages" feature is used in conjunction with getTopicTree() which has these parameters respectively. In order to keep the selected page the pageNr value must be hold as a session attribute.

Using the DeepaMehta Basis Servlet

Besides the protected performAction() and preparePage() methods you have to override, the DeepaMehta basis servlet provides utility methods (protected final) to be called from your derived controller servlet.
TopicTree getTopicTree(String topicID)
TopicTree getTopicTree(String topicID, String childTypeID, String assocTypeID)
TopicTree getTopicTree(String topicID, String childTypeID, String assocTypeID, boolean sortAssociations)
TopicTree getTopicTree(String topicID, String childTypeID, String assocTypeID, String[] sortTopicProps, boolean descending)
TopicTree getTopicTree(String topicID, String childTypeID, String assocTypeID, String[] sortTopicProps, boolean descending, int pageNr, int pageSize)
getTopicTree() retrieves a hierarchical structure of topics from corporate memory. Typically a TopicTree object is rendered on a JSP page by means of the HTML generators tree() method (last section). The most simple form of getTopicTree() requires just the ID of the topic acting as the trees root topic. In this case all child topics are expected to be of the same type as the root topic and the constitutional associations are expected to be of type ASSOCIATION_COMPOSITION (direction is always from parent topic to child topic), furthermore child topics are ordered by the Ordinal Number property of their respective associations. By using the childTypeID parameter trees can be retrieved where the type of the root topic is different from the type of the child topics (still all child topics are expected to be of the same type). By using the assocTypeID parameter another association type than ASSOCIATION_COMPOSITION can be specified (still all constitutional associations are expected to be of the same type). The default ordering approach can be suppressed by setting the sortAssociations parameter to false. By using the sortTopicProps parameter child topics are ordered based on their property values. The string array contains the names of the properties which are acting as ordering criterion.
String createTopic(String typeID, RequestParameter params, Session session)

String updateTopic(String typeID, RequestParameter params, Session session)
String updateTopic(String typeID, RequestParameter params, Session session, String topicmapID, String viewmode)

void deleteTopic(String topicID)
void deleteAssociation(String typeID, String topicID1, String topicID2)



Using the Application Service

The application service provides access to the "live" incarnations of topics which are loaded into memory. All methods mentioned here can be called via the as variable which can be used by every live topic (the class ApplicationService is located in package de.deepamehta.service).

Access live topics

LiveTopic getLiveTopic(BaseTopic topic)                                                         throws DeepaMehtaException, TopicInitException
LiveTopic getLiveTopic(String id, int version)                                                  throws DeepaMehtaException, TopicInitException
LiveTopic getLiveTopic(BaseTopic topic, Session session, CorporateDirectives directives)        throws DeepaMehtaException, TopicInitException
LiveTopic getLiveTopic(String id, int version, Session session, CorporateDirectives directives) throws DeepaMehtaException, TopicInitException
If the specified topic is already loaded it is returned, otherwise it is loaded first. Loading a topic means, reading it from corporate memory and instantiate it in memory. The session and directives parameters are passed to the topics initialization routines, see Topic Life Cycle.

Navigation

Use getRelatedTopic() if one topic is expected. By default, a DeepaMehtaException is thrown if no topic is found (emptyAllowed=false). If no topic was found and emptyAllowed is set to true null is returned instead of throwing an exception. If more than one topic was found an AmbiguousSemanticException is thrown.
BaseTopic getRelatedTopic(String topicID, String assocTypeID, int relTopicPos)                                              throws DeepaMehtaException, AmbiguousSemanticException
BaseTopic getRelatedTopic(String topicID, String assocTypeID, int relTopicPos, boolean emptyAllowed)                        throws DeepaMehtaException, AmbiguousSemanticException
BaseTopic getRelatedTopic(String topicID, String assocTypeID, String relTopicTypeID, int relTopicPos, boolean emptyAllowed) throws DeepaMehtaException, AmbiguousSemanticException
Use getRelatedTopics() if many topics are expected.
Vector getRelatedTopics(String topicID, String assocTypeID, int relTopicPos)
Vector getRelatedTopics(String topicID, String assocTypeID, String relTopicTypeID, int relTopicPos)
Vector getRelatedTopics(String topicID, String assocTypeID, String relTopicTypeID, int relTopicPos, boolean sortAssociations)
Vector getRelatedTopics(String topicID, String assocTypeID, String relTopicTypeID, int relTopicPos, boolean sortAssociations, boolean emptyAllowed) throws DeepaMehtaException
BaseTopic getTopic(String typeID, Hashtable properties, String topicmapID, CorporateDirectives directives) throws DeepaMehtaException
BaseAssociation getAssociation(String topicID, String assocTypeID, int relTopicPos, String relTopicTypeID, boolean emptyAllowed, CorporateDirectives directives) throws DeepaMehtaException

Get properties

String getTopicProperty(BaseTopic topic, String propName)
String getTopicProperty(String topicID, int version, String propName)
Hashtable getTopicProperties(BaseTopic topic)
Hashtable getTopicProperties(String topicID, int version)
String getAssocProperty(BaseAssociation assoc, String propName)
String getAssocProperty(String assocID, int version, String propName)
Hashtable getAssocProperties(BaseAssociation assoc)
Hashtable getAssocProperties(String assocID, int version)

Set properties

void setTopicProperty(BaseTopic topic, String propName, String propValue)
void setTopicProperty(String topicID, int version, String propName, String propValue)
void setTopicProperties(String topicID, int version, Hashtable props)
CorporateDirectives setTopicProperty(String topicID, int version, String propName, String propValue, String topicmapID, String viewmode, Session session)
CorporateDirectives setTopicProperties(String topicID, int version, Hashtable props, String topicmapID, boolean triggerPropertiesChangedHook, Session session)
void setAssocProperties(String assocID, int version, Hashtable props)
CorporateDirectives setAssocProperties(String assocID, int version, Hashtable props, String topicmapID, String viewmode, Session session)

Create topics

LiveTopic createLiveTopic(String topicID, String typeID, String name, Session session)
LiveTopic createLiveTopic(String topicID, String typeID, String name, String topicmapID, String viewmode, Session session, CorporateDirectives directives)
LiveTopic createLiveTopic(BaseTopic topic, String topicmapID, String viewmode, Session session, CorporateDirectives directives)


Accessing the Corporate Memory

All live topics can use the cm variable to acces the corporate memory directly, as specified by the CorporateMemory interface (package de.deepamehta.service).
BaseTopic getTopic(String id, int version);
BaseTopic getTopic(String typeID, String name, int version);
Vector getTopics()
Vector getTopics(String typeID)
Vector getTopics(String typeID, String nameFilter)
Vector getTopics(String typeID, Hashtable propertyFilter)
Vector getTopics(String typeID, Hashtable propertyFilter, boolean caseSensitiv)
Vector getTopics(String typeID, Hashtable propertyFilter, String topicmapID)
Vector getTopics(String typeID, Hashtable propertyFilter, String topicmapID, boolean caseSensitiv)
Vector getTopics(String typeID, String nameFilter, Hashtable propertyFilter)
Vector getTopics(String typeID, String nameFilter, Hashtable propertyFilter, String relatedTopicID)
Vector getTopics(String typeID, String nameFilter, Hashtable propertyFilter, String relatedTopicID, String assocTypeID)
Vector getTopics(Vector typeIDs)
Vector getTopics(Vector typeIDs, Hashtable propertyFilter, boolean caseSensitiv);
//
Vector getTopicsByName(String nameFilter)
Hashtable getTopicsByProperty(String searchString)
Vector getRelatedTopics(String topicID)
Vector getRelatedTopics(String topicID, String assocTypeID, int relTopicPos)
Vector getRelatedTopics(String topicID, String assocTypeID, String relTopicTypeID)
Vector getRelatedTopics(String topicID, String assocTypeID, String relTopicTypeID, int relTopicPos)
Vector getRelatedTopics(String topicID, String assocTypeID, String relTopicTypeID, int relTopicPos, String assocProp, String propValue)
Vector getRelatedTopics(String topicID, String assocTypeID, String relTopicTypeID, int relTopicPos, String[] sortTopicProps, boolean descending)
Vector getRelatedTopics(String topicID, String assocTypeID, String relTopicTypeID, int relTopicPos, boolean sortAssociations);
Vector getRelatedTopics(String topicID, String assocTypeID, String relTopicTypeID, int relTopicPos, Vector relTopicIDs, boolean sortAssociations);
Vector getRelatedTopics(String topicID, String assocTypeID, Vector relTopicTypeIDs, int relTopicPos, boolean sortAssociations);
Vector getRelatedTopics(String topicID, String assocTypeID, int relTopicPos, String topicmapID)
Vector getRelatedTopics(String topicID, Vector assocTypeIDs, int relTopicPos)
Vector getTopicIDs(String typeID, String topicmapID)
Vector getTopicIDs(String typeID, String topicmapID, boolean sortByTopicName)



Writing Corporate Memory Patches




24.5.2006, Jörg Richter jri@freenet.de