The Price is Right!
   
 

11 Writing New Extensions for Moto

The moto language, like most web programming languages, was designed primarily for webmasters with some technical ability to intersperse programmatic constructs within web pages to create web applications. Moto was built with performance in mind because the history of web programming languages such as Coldfusion, ASP, and PHP, shows that they are used more often than not as the entire platform for rapid web application development. Nonetheless, the preferred way of using moto is for the user interface and form handling aspects of your web applications alone. Business logic, where possible, should be implemented in a classical programming language such as C.

To this end, an API has been provided for the creation of new moto objects and functions from your own C libraries.

11.1 The Moto Extension Architechture

Moto extensions are organized into libraries that can be used in your moto pages via the $use construct. These libraries reside under the mx directory of your moto home directory. The structure of the mx directory is loosly modelled after a java class library structure. It is heirarchical with the top level subdirectories conventionally named after the source company that maintains the moto extensions within. Underneath each top level directory there may be further subdirectories dividing the contained extensions into frameworks by function. Entensions are made available to the a moto page one folder at a time.

11.2 Adding A New Extension Library

To add a new extension library you should begin by creating a new directory underneath the mx directory. You should then copy the makefile file from one of the existing extensions folders into your new folder. You can now begin creating interface files that map extension functions and object methods to C functions in your own C libraries.

11.3 Writing A Moto Interface File

For each new object or set of related functions you wish to expose to your moto application, you should create one interface file (.i) . The convention is that this interface file be given the same name as the extension which it contains and thus start with a capital letter. Interface files have the following general structure:

Extension: 1st Extension / Class Name

LibraryPath: 1st library path needed to locate shared libs this extension depends upon
LibraryPath: 2nd library path needed to locate shared libs this extension depends upon
...

IncludePath: 1st path to header files needed to compile this extension
IncludePath: 2nd path to header files needed to compile this extension
...

Library: 1st shared library file needed for this extension
Library: 2nd shared library file needed for this extension
...

Archive: 1st archive needed for this extension
Archive: 2nd archive needed for this extension
...

Include: 1st C header file needed to compile this extension
Include: 2nd C header file needed to compile this extension
...

Interface:

prototype mapping ;
prototype mapping ;
prototype mapping ;
...
 

The prototype mapping is where moto functions and methods get translated to their C counterparts. A prototype mapping begins with the return type of the moto function or method preceded by the keyword tracked if the return value is an object created on the heap by the function or method call. If the function or method returns nothing then void should be specified as it's return value. Following the return type is the function or method name. In the case of a method name, the C++ style qualified name should be used

Class Name::Method Name  

After the method name there is an open paren '(' followed by a comma delimeted list of argument type argument name pairs followed by a close paren ')'. After the argument list comes the mapping symbol => and finally the C function prototype. A complete example of an interface file taken from the codex.util library for the SymbolTable class follows:

Extension: SymbolTable

Include: "symboltable.h"
Include: "enumeration.h"

Interface:

tracked SymbolTable SymbolTable::SymbolTable() =>
   SymbolTable *stab_createDefault();
   
void SymbolTable::~SymbolTable() =>
   void *stab_free(SymbolTable *this);
   
void SymbolTable::put(String key, Object value) =>
   void stab_put(SymbolTable *this, char *key, void *value);
   
Object SymbolTable::get(String key) =>
   void *stab_get(SymbolTable *this, char *key);

void SymbolTable::remove(String key) =>
   void *stab_remove(SymbolTable *this, char *key);
   
void SymbolTable::clear() =>
   void *stab_clear(SymbolTable *this);

tracked Enumeration SymbolTable::keys() =>
   Enumeration *stab_getKeys(SymbolTable *this);

int SymbolTable::size() =>
   int stab_size(SymbolTable *table);


 

11.4 Extension Dependencies

There are three important times when the dependencies for an extension must be known.

  1. When the extension is compiled with mxc into .a and .so libraries
  2. When the extension is dynamically loaded by the moto interpreter
  3. When the extension is linked to a binary or apache module with mmc

11.4.1 Includes and IncludePaths

At compilation time when the .a and .so files are created, header files that declare C prototypes used in .i files must be listed using the Include keyword so that they can be included when building extension object files. If these headers aren't in a standard location such as /usr/include the path to the directory containing these header files must also be specified using the IncludePath keyword so that mxc and mmc know where to look for them.

Using IncludePath to add the path to the moto include directory is not necessary as it is automatically included by mxc and mmc.

11.4.2 Libraries and LibraryPaths

The Library keyword in an interface file allows you to specify that your extension depends on a third party library. This keyword should only be used for linking to shared libraries. It will generate a runtime dependency from the extension (and therefore from modules compiled with that extension) to that library.

Libraries you should never link to via the library keyword include libmotom and libcodex. All the symbols from these libraries are included in the command line interpreter and in mod_moto and are automatically linked by mmc. Linking to these libraries will cause duplicate symbol errors on some platforms.

If the shared library you depend on is not in a standard location such as /usr/lib then you must specify the path to the directory containing the shared library by using the LibraryPath keyword.

Often times it is preferable to actually copy the necessary symbols out of a library directly into an extension. This is the case when you do not wish to have the runtime dependency on that library. Specifying a full path to an archive that contains the necessary symbols (a .a file) using the Archive keyword will tell both mxc and mmc to statically link to that archive (copy out symbols).

Sometimes archives and shared libraries may themselved be dependant on symbols in other libraries. These dependencies should also be listed with the Library or Archive keywords.

Often times there will be a choice to link to either a shared library or an archive. The general rule should be to link to common shared libraries that are guarenteed to be present in the same location on platforms where binaries compiled with your extension will be deployed. If you cannot guarentee that, then statically link to an archive if possible.

This diagram shows the current design of the libraries that are distributed with moto.

11.5 Writing an Extension in C

Always include "memsw.h" this is very important because this header redefines malloc, realloc, and free to allocate memory on the shared heap. If your methods in your extension return Objects (a constructor for example) than that memory needs to be allocated on the shared heap. If it is allocated with the plain old system malloc than that memory will leak and never get cleaned up. Worse, your object won't be promotable. That is, moto programmers won't be able to persist it in the session or context and if they try to, Apache will likely segfault when they next try to access it. Bottom line ... include memsw.h .

Usually include "excpfn.h" and "exception.h". With these you will be able to throw and catch exceptions using the macros TRY, CATCH, CATCH_ALL and END_TRY. This is much better than segfaulting (or returning error codes ... yuck) when something goes wrong inside your extension. Moreover excpfn.h defines a number of usefull function that mimic their C stdlib counterparts but allocate memory on the shared heap and throw exceptions when the arguments passed to them are bad. These functions include emalloc, erealloc, estrdup, and estrcmp.

Always create a destructor. Without a destructor moto will just call plain old free on your object and if you have any member objects those won't get cleaned up.