Groundwork Guide

Downloading Groundwork:

You can download the most current source distribution of groundwork from groundwork.sourceforge.net.

Unpacking Groundwork:

To unpack the distribution, copy the file to a location on your machine that you have access to and execute the following commands:

This will create a groundwork-X.X directory with include, lib and src directories beneath it.

Compiling Groundwork:

To comple Groundwork, read the INSTALL file, then execute the following commands:

Groundwork should compile and function on any unix-based system using the GNU development system. Other compilers may work too but have not been tested on the current version.

The -pedantic flag must be used with newer GNU compilers.

Upon sucessfull compilation, the lib directory should contain both libgroundwork.a and libgroundwork.so.

Installing Groundwork:

To install Groundwork, become root and execute:

By default, everything is installed under /usr/local/firstworks.

To uninstall Groundwork, become root and execute:

The Directory Structure:

Before developing or delivering software using groundwork, a particular directory structure has to be set up on the server. Groundwork depends on this structure and provides functions for accessing it.

Unless compiled otherwise, groundwork requires the following directory structure:

Groundwork interprets this structure as follows:

This is a fairly complex directory structure which probably requires some explaination.

The directory /usr/local/web is the base directory for all groundwork applications. Other non-groundwork based pages or applications can, of course, be installed anywhere on the server, but groundwork based applications should be installed here.

Beneath this directory are multiple site directories. A single server may host multiple web-sites. In the groundwork directory structure, a directory for each of these sites should be created under /usr/local/web. Applications for each site should be installed under that site's site directory.

Often, a single application is developed that could be used in multiple sites. Creating a /usr/local/web/dev site directory, doing all development there, then installing the releases under the individual sites is recommended. Groundwork provides functions enabling a programmer to avoid hardcoded pathnames. Exclusive use of these functions allows an application to be copied from site to site with little or no modification and no recompilation.

Beneath each site directory are package directories. A given site might have multiple packages installed under it. The groundwork concept of a package is a collection of applications. The groundwork concept of an application is a set of cgi's and html-based interfaces which accomplish a single purpose.

Beneath the package directory are the apps, interfaces and pages directories. Groundwork assumes that any directories between the site directory and apps, interfaces and pages directories are package directories. This enables a package to have sub-packages. To illustrate:

The above organization could use the following directory structure:

In the above directory structure, there are actually 4 packages:

These 4 packages may also be thought of as 2 packages (authentication and ecommerce) with 2 sub-packages each (delivery and maintenance).

Groundwork provides functions enabling a programmer to avoid hardcoded pathnames. Exclusive use of these functions allows a package/sub-package heirarchy to be changed with little or no modification and no recompilation.

Below the package level are 3 directories: apps, interfaces and pages. The pages directory contains any static or semi-static pages that an package may refer to. The apps directory contains a subdirectory for each application of a package. The interfaces directory contains a subdirectory for each interface definition as well as configuration files for each interface. Below each interface directory are subdirectories for each application.

Below each application directory are the src, cgi-bin and sql directories. The src directory contains the source code, Makefiles and other development related files and may be omitted from release distributions. The cgi-bin directory contains executables. As most web-based applications involve database access and most of those databases are sql databases, the sql directory is provided as a repository for sql scripts to avoid embedding sql in the source code of an application. This allows modification of a query with no recompilation.

Below the main interfaces directory are subdirectories for each interface of a package. Why would you ever want multiple interfaces for an application? There are quite a few not-so-obvious reasons for it. Frequently they are so obscure that none can be thought of at development time. But they inevitably crop up down the line.

These reasons include the desires for frames/no-frames interfaces, text-only interfaces, flashy (ie. graphics intense) or not-so-flashy interfaces, browser-specific interfaces, customer-specific interfaces, company-division-specific interfaces; the list goes on and on. And the differences between the interfaces are not always the kind of thing that CSS's alone can handle. Some information may be placed on different pages in some interfaces, or the database to access may be different, or the entire look and feel may be so different that using CSS's to apply the differences is simply impractical.

At any rate, in the groundwork directory structure, there are subdirectories for each interface of a package below the interfaces directory along with configuration files for each interface. Below each of those directories is a directory for each application. Below each of those directories are the html, images, js and css directories.

This may all seem confusing, but the following diagram may explain things. This diagram illustrates a development site containing an ecommerce package with maintenance and delivery sub-packages consisting of catalog, shoppingcart, checkout, catalog maintenance and shipping table maintenance applications and with default and text-only interfaces.



Web Server Configuration:

Web server configuration is an important step in using groundwork to develop or deliver an application. Specifically, the web server must map the directory /usr/local/web to location /web and must control access to any sensitive files or directories in the tree. Groundwork uses files ending in .inf, .ldb and .log for configuration and logging.

When using the apache web server, the following directive in the srm.conf file will map /usr/local/web to /web.

Alias /web /usr/local/web

The following block directives in the access.conf file will restrict access to the sql and src directories and files ending in .inf, .ldb and .log.

<DirectoryMatch sql>
deny from all
</DirectoryMatch>

<DirectoryMatch src>
deny from all
</DirectoryMatch>

<FilesMatch *.inf>
deny from all
</FilesMatch>

<FilesMatch *.ldb>
deny from all
</FilesMatch>

<FilesMatch *.log>
deny from all
</FilesMatch>

The "deny from all" configuration could, of course, be substitited for a less restrictive configuration such as:

order deny, allow
deny from all
allow from mysite.org

Which would deny everyone except someone with a domain name of mysite.org.

Using Groundwork:

The basic approach to writing a cgi using groundwork is to either instantiate a groundwork class and use it's member functions, or to create your own class which inherits from a groundwork class or classes.

Classes and Subclasses:

The C++ class library consists of 2 main classes: groundwork and extendedgroundwork. The groundwork class inherits from the cgi, interface, page and paths classes. The extendedgroundwork class inherits from the groundwork, http, mime, accesslog, loadbal, htmltags and ipsecurity classes.

As a rule of thumb, your cgi should instantiate or inherit from the classes it needs and not from any others.

Below is a simple, example cgi that takes illustrates some groundwork functionality.

/usr/local/web/examplesite/examplepkg/apps/exampleapp/src/example.C

#include <groundwork.h>

class example : public groundwork {
	private:
		int	handleSegment(strstream *container, char *name, char *segment);
		// handleSegment() here overloads page::handleSegment()
		void	sendList(char *segment);
		// sendList() is a segment-handler function
};

int	example::handleSegment(strstream *container, char *name, char *segment) {

	// if the tag: <!-- start list --> is encountered, then
	// the sendList() function is called to process everything between 
	// the <!-- start list --> and <!-- end list --> tags
	if (!strcmp(name,"list")) {
		sendList(segment);
		return 1;
	}
	return 0;
}

void	example::sendList(char *segment) {

	strstream	*index;

	for (int i=0; i<5; i++) {

		index=new strstream();
		*index << i << ends;

		// this call invokes page::parseSegment() which will write out
		// the string pointed to by segment, replacing occurrances of 
		// $(number) with index->str() and call handleSegment() 
		// recursively for any nested segments
		parseSegment(NULL,segment,
				NULL,
				"number",index->str(),
				NULL);

		delete index;
	}
}

main() {


	// instantiate an instance of example which will in turn instantiate
	// an instance of groundwork and it's subclasses
	example	*ex=new example();

	// Initialize groundwork, taking care of some post instantiation
	// initializations.  Don't be tempted to put this in your class
	// instantiator, it passes the "this" pointer to the init functions of
	// child classes which (depending on your compiler and optimizations)
	// may or may not exist before the instantiator is done instantiating.
	// For portabilities sake, call it here or from a member function.
	ex->initGroundwork(15,60);

	// invoke groundwork::execute() which will send a simple mime header
	// and invoke page::parsePage() on the html page
	// page::parsePage() will replace $(...) tags with environment 
	// variables, variables passed into the cgi from a form submission,
	// or special paths class variables.  In addition, page::parsePage()
	// will handle <!-- include ... --> directives internally
	// and <!-- start ... --> ... <!-- end ... --> directives by invoking
	// example::handleSegment()
	ex->execute();


	// clean up
	delete ex;
}

/usr/local/web/examplesite/examplepkg/interfaces/default/exampleapp/html/example.html

<html>
<body>
The browser is $(HTTP_USER_AGENT).<br>
The remote IP is $(REMOTE_ADDR).<br>
A variable passed into this cgi is $(variable).<br>
<br>
Here is a list of numbers 0-4 with a sub-list of 0-4 for each list entry.<br>
<ul>
<!-- start list -->
<li>list item: $(number)</li>
<ul>
<!-- start list -->
<li>sublist item: $(number)</li>
<!-- end list -->
</ul>
<!-- end list -->
</ul>
</body>
</html>

If the above cgi were compiled and accessed in a browser using a url like: http://server.domain.com/web/examplesite/examplepkg/apps/exampleapp/cgi-bin/example.cgi?variable=hello then the following output would result:

The browser is Mozilla/4.7 [en] (X11; U; Linux 2.2.14 i586).
The remote IP is 204.0.85.37.
A variable passed into this cgi is hello.

Here is a list of numbers 0-4 with a sub-list of 0-4 for each list entry.

This is of course, a very simple example which demonstrates only a fraction of the capablities of groundwork.

Database Access:

Any C or C++ compatible database access technology should be compatible with groundwork. Difficulties should only arise if groundwork function names and/or signatures happen to be the same as those of the database access functions that you would like to use.

If you are interested in using a transactional database then a recommended method for accessing one is the firstworks project SQL Relay. SQL Relay offers performance improvements over native API's, but consumes more system resources and requires additional configuration.