     [file version.texi not included]

This file documents the Java-Like Library 2.

Java vs. C plus plus
********************

Garbage Collection
==================

One of Java's most important features is automatic garbage collection which is handled by the Java Virtual Machine. This allows the programmer to create new objects without having to worry when to free or delete them. From time to time the garbage collector goes through the whole heap memory and frees all objects that are not referenced any longer.

Unfortunately C or C++ does not provide an automatic garbage collector. But there are garbage collector libraries out there that can be used instead. Jakelib2 uses Hans-J. Boehm's garbage collector (http://www.hpl.hp.com/personal/Hans_Boehm/gc/).  So this garbage collector library seems to be the limiting factor for jakelib's protability: If the gc can be compiled and does work for a certain platform, jakelib2 should also work. If not, one will have to find out why and fix the issue!

The gc provides a class named gc_cleanup. All classes derived from this base class will be automatically garbage collected and their destructor (finalizer) will be called before disposal. This is why jakelib's counterpart to Java's java.lang.Object - jakelib::lang::Object - is derived from gc_cleanup, so that all of jakelib's classes will be garbage collected.

The garbage collector does not scan arrays allocated by the standard malloc functions. Objects that are referenced only from such arrays will probably be deleted by the gc. The new functions GC_MALLOC, GC_REALLOC and GC_FREE can be used to allocate and free memory that the gc will scan. This is absolutely necessary when storing references in an array like it is done in jakelib::util::ArrayList. On the other hand, a byte buffer for IO operations can be allocated using standard malloc since it will not contain any references to objects.

Problems
--------

The gc will not guarantee that every single object will be freed if it is not referenced any longer. However, it seems that the amount of uncollected objects stays quite stable throughout a program's runtime. Practice shows that we don't need to worry too much about this issue. But one should keep in mind that there is no guarantee!  Thus it's useful to provide some classes with methods like destroy or close that allow to release the acquired resources explicitely (i.e. close a file or free a large buffer).

If a set of objects is referenced cyclically, the garbage collector won't finalize (i.e. call the object's destructor) these objects before disposing of them because there is no way to determine a safe order to finalize and free the objects one by one.

Primitive data types
====================

Java offers a set of well defined primitive data types:

     Type name   size in bits
     boolean         1
     byte            8
     short           16
     int             32
     long            64
     float           32
     double          64
     char            16

When programming in C or C++ the size of a certain primitive type depends on the platform you are actually using. This is why jakelib provides a set of typedefs that are defined in include/jakelib2.h. The names of these typedefs all start with a lower case j. It depends on the certain platform which types are used to represent a jint or a jlong.

On an Intel/Linux system the following substitutions are done:

     Type name   C type
     jboolean    int
     jbyte       char
     jshort      short
     jint        int
     jlong       long long
     jfloat      float
     jdouble     double
     jchar       unsigned short

A jboolean variable should be assigned either true (=1) or false (=0) only. TRUE and FALSE should not be used. null is an alias for NULL and should be used instead.

Interfaces and Classes
======================

In jakelib every class should be derived from jakelib::lang::Object like all Java classes are derived from java.lang.Object. As C++ does not know interfaces in opposition to real classes, jakelib uses abstract classes as a substitution for Java's interfaces. These interface classes are not derived from jakelib::lang::Interface.

Arrays
======

To provide a portable way to work with typed arrays, Jakelib2 uses a special class for every data type to be stored. Templates are not used because they are known to cause problems on certain compilers. However, the result would actually be quite the same.

Primitive data types
--------------------

1-dimensional array classes are already implemented for all of Jakelib2's primitive data types: jchar, jbyte, jint, jlong, jfloat, jdouble, jboolean and jshort.

The array classes have the name of the original data type with an 's' append to express the plural: jchars, jbytes, jints, jlongs, jfloats, jdoubles, jbooleans and jshorts.

Example:

     jints* arr = new jints(10);

     for (int idx = 0; idx < arr->length(); idx++) {
       arr->set(idx, 100*idx);
     }
     for (int idx = 0; idx < arr->length(); idx++) {
       a = arr->get(idx);
     }

Objects
-------

Jakelib2 provides two macros to declare and implement an array class for a given Object-derivate: JAKELIB2_DECLARE_ARRAY(classname) declares an array class (to be used in header files) and JAKELIB2_IMPLEMENT_ARRAY(classname) implements the array class' methods (to be used in jlc-files).

These array classes provide the same operators and methods as those for primitive data types.

By now a 1-dimensional array for String objects has been implemented. More classes will follow as needed.

Run Time Type Identification
============================

All classes derived from jakelib::lang::Object have extra type information that allows RTTI (runtime type identification).

Each Object provides a .getClass() method that returns its Class object. .instanceOf() can be used to determine whether an object is derived from a certian class.

See API documentation for more details.

Exceptions
==========

In Jakelib all exceptions are created using new and thrown as pointers. Example:

     try {
       ...
       throw new FileNotFoundException();
     }
     catch (Exception *ex) {
       System::out->println(ex);
     }

The super-class for all exceptions should be jakelib::lang::Throwable.

Compiling and Installing
************************

Jakelib2 runs under GNU/Linux, Solaris, Win32 and probably some other Unix-like systems.

Jakelib depends on a couple of external libraries: Hans-J. Boehm's garbage collector is absolutely needed to compile and use jakelib2. Other libraries like pcre (Perl Compatible Regular Expressions) and MySQL's client libs are optional.

The garbage collector
=====================

First thing to do is download version 6.0 of the garbage collector, compile and install it. Hans-J. Boehm's garbage collector can be downloaded directly from his own homepage http://www.hpl.hp.com/personal/Hans_Boehm/gc or from http://www.jakelib.org.

Unpack the zipped tar archive:

       gunzip -c boehm-gc.tar.gz | tar x

Cd into the extracted directory:

       cd gc6.0

Configure, compile and install:

       ./configure --enable-threads=pthreads [--prefix=<GC_PREFIX>]
       make
       make install

If you don't supply the --prefix option to ./configure, the library files will be copied to /usr/local/lib.

Jakelib2
========

Now download the latest version of jakelib2 from http://www.jakelib.org.

Unpack the zipped archive:

     gunzip -c jakelib2-2.X.XX.tar.gz | tar x

Cd into the extracted directory:

       cd jakelib2-2.X.XX

Configure and compile:

       ./configure [--prefix=<JAKELIB_PREFIX>]
                   [--with-gc-dir=<GC_PREFIX>/lib]
       make

If you don't supply the --prefix option to ./configure, the library files will be copied to /usr/lib and include files will be copied to /usr/include. If you didn't install the garbage collector in the default location you'll need to supply the --with-gc-dir option. Just set it to the directory where your libgc.a file is located.

If compilation succeeded, run

       make test

to see if it works. The test program covers a wide range of operations all across the library.

Finally run

       make install

to copy the library and include files to their target locations.

Additional external libraries
=============================

There are extension packages for Jakelib2 that make use of the following libraries:

pcre
     Perl Compatible Regular Expressions (http://www.pcre.org)

mysqlclient
     Client libraries for the MySQL data base (http://www.mysql.org)

GTK2
     The Gimp Toolkit: A complete toolkit for GUI programming. Intergration in Jakelib is not yet ready to be used! (http://www.gtk.org)

Using Jakelib2
**************

Jakelib2 is a pure C++ library designed to be statically linked to C++ programs. To use Jakelib2 for your own projects, you need to have several compiler options, include and library paths set. To simplify the process of extending your makefiles accordingly, Jakelib2 provides the jakelib2-config script.

Just call jakelib2-config to see what options and actions are supported.

Examples:

jakelib2-config --cppflags
     Prints all compiler options including include directories to stdout. The output of such a call of jakelib2-config is usually appended to the CPPFLAGS variable in Makefiles.

jakelib2-config --libs
     Prints a list of all libraries to be linked to the user program. The output of such a call of jakelib2-config is usually appended to the xxx_LDADD variable in Makefiles.

jakelib2-config --version
     Prints the complete version number, like 2.0.0g.

Starting a new project using Jakelib2
=====================================

Since Jakelib2 2.0.0j there is a simple but nice script called jakelib2-skeleton that creates all files needed to compile and link a program using Jakelib2.

Just create a new directory, cd into it and run jakelib2-skeleton <projectname>. If there were no errors you should be able to compile your new project by running make. The linked executeable will be called src/<projectname>.

Edit the main source file to get a feeling for the whole thing: src/Main.jlc.

However, notice that JAKELIB_INIT; must be called in your program (preferably in the main() function) before any other Jakelib2 object is created or method called. JAKELIB_INIT is a macro that calls jakelib::lang::Object::initJakelib2() which initializes several classes (such as the default character conversion classes or the standard input and output streams).

Debugging
=========

To debug your own programs written for Jakelib2 (or Jakelib itself ;-) ) I recommend using the famous GNU debugger gdb. You should have at least gdb 5.2 since 5.0 (and prior) won't work when using pthreads.

There are several GUIs providing an easier access to gdb:

KDbg (1.2.5)

Data Display Debugger (DDD) 3.3

Extending Jakelib2
******************

Jakelib uses autoconf and automake to create Makefiles and control the compilation and linking process.

Understanding Jakelib
=====================

Directory structure
-------------------

     jakelib2/
       +-- doc/
       |   +-- html/
       +-- include/
       |   +-- jakelib2/
       |       +-- gc/
       |       +-- gtk/
       |       +-- io/
       |       +-- lang/
       |       +-- lua/
       |       +-- net/
       |       +-- servlet/
       |       |   +-- http/
       |       +-- sql/
       |       +-- text/
       |       |   +-- enc/
       |       +-- util/
       |           +-- regex/
       +-- jlpp/
       |   +-- include/
       |   +-- lib/
       +-- src/
       |   +-- gtk/
       |   +-- io/
       |   +-- lang/
       |   +-- lua/
       |   +-- net/
       |   +-- servlet/
       |   |   +-- http/
       |   +-- sql/
       |   +-- test/
       |   +-- text/
       |   |   +-- enc/
       |   +-- util/
       |       +-- regex/
       +-- samples/

The include/jakelib2/ directory contains a subdirectory for each jakelib:: package. These subdirectories contain the header (.h) files, one for each class. Each subdirectory should also contain a single header file that simply includes all header files in the subdirectory (example: include/jakelib2/util/all.h).

The src/ directory has a subdirectory for every package as well. These subdirectories contain the source files: .jlc and .cpp. Each class should have its own source file. If there is a .jlc file for a certain class, this file will be automatically converted to .cpp by the make process. In this case the .cpp file should not be modified manually.

Coding style
============

Indentation
-----------

Two spaces should be used as the unit of indentation. Avoid using tabs whenever possible. However, tabs must be set exactly every 8 spaces (not 4).

If XEmacs is your text editor of choice, you won't have any problems with this guidelines.

Opening braces '{' should be set on the same code line where their if, while, for or whatever statement is. Exception: braces after class or method declarations. Closing braces should always be set on their own empty line. Example:

     void foo(int n)
     {
       for (int idx = 0; idx < n; idx++) {
         if (doSomeThing(idx)) {
           ...
         }
         else {
           ...
         }
       }
     }

Naming conventions
------------------

Classnames always start with a capital letter, method and variable names start with a lower case letter. Underline characters (_) are neither used in class nor in method or variable names.

Constant names are upper case and may contain underlines to make them more readable.

Pointer operators
-----------------

The pointer operator * should be written next to the variable name rather than the type name:

     String *str = "aaaa";

rather than

     String* str = "aaaa";

The reason is that the pointer operator seems to belong to the variable rather than to the type name as the following example illustrates:

     String* str1, str2;

This does not---as one might expect --- declare two pointer variables *STR1 and *STR2 to String. It rather declares one pointer *STR1 and one static instance STR2. This is why you should write instead:

     String *str1, *str2;

Coding guide lines
==================

This section contains a set of rules that should be followed when developing for Jakelib2. These rules are necessary to achieve a certain level of platform independency.

Some of the rules below are taken - or at least inspired by - Mozilla's coding guide lines (http://www.mozilla.org/hacking/portable-cpp.html).

 1. Do not use C++ templates!

 2. Use pointers (Object* obj) rather than C++ references (Object& obj).

 3. We have a garbage collector! Methods may return new objects without worrying when to delete them. See Garbage Collection.

 4. Don't use static initializers. Code like this will definitely cause problems on one compiler or the other:

          Locale *MyClass::loc = Locale::getDefault();

     The problem is that the order in which such static initializers are called on program start-up is highly compiler-dependend. In this case the class Locale might not yet be initialized when MyClass' initializers are invoked.

 5. Every source file must have a unique name

Writing new classes
===================

To add a new class to Jakelib, you should feel encouraged to follow these steps:

Create a new header file
------------------------

Create a new header file in the according package subdirectory in include/jakelib2/: The given file include/jakelib2/template.h can serve as a template.

The new header file should not contain more #include statements than absolutely necessary. I.e., includes are necessary to make the direct super class known. Classes that are just referenced as properties or parameters for methods or constructors can be declared forward with class <classname>;.

Do not use using namespace jakelib::... to save time when typing the class names! This should be done in the source files only. Instead write the fully qualified class names if the desired class comes from a different package, example: jakelib::lang::String* text.

Example (header file include/jakelib2/util/SampleClass.h for class jakelib::util::SampleClass):

     /*
      * Java-Like C++ Class Library
      * Copyright (C) 2001 Florian Wolff  (florian@donuz.de)
      * ...
      */

     #ifndef INCLUDE_JAKELIB2_UTIL_SAMPLECLASS_H
     # define INCLUDE_JAKELIB2_UTIL_SAMPLECLASS_H
     #include "../lang/Integer.h"

     namespace jakelib {
       namespace io {
         class OutputStream;
       }
       namespace util {
         class Iterator;

         /**
          * This class implements a streamable integer.
          * ...
          * @class SampleClass
          * @version $Id: jakelib2.texi,v 1.52 2006-02-18 12:25:28 florian Exp $
          * @author Your Name Here (email@foo.bar)
          */
         class SampleClass : public jakelib::lang::Integer
           {
           public:

             SampleClass(jakelib::lang::Integer* anInteger);

             jakelib::lang::String* toString();

             Iterator* iterator();

             jakelib::io::OutputStream* getOutputStream();

             JAKELIB_DECLARE_CLASS(SampleClass);
           };
       }
     }
     #endif

Btw, JAKELIB_DECLARE_CLASS is a macro that declares a property and a method used for run time type identification purposes.

Now you should update the Makefile.am file that is located in the same subdirectory: Add the name of your new file to the list of header files (pkginclude_HEADERS).

Create the source file
----------------------

Create a new .jlc source file in the according package subdirectory in src/: The given file src/template.jlc can serve as a template.

After that update the Makefile.am file that is located in the same subdirectory: Add the name of your new file to the EXTRA_DIST list and add the name of the according .cpp file to libjake2_<PACKAGENAME>_a_SOURCES.

Documenting classes
-------------------

Write a test program
--------------------

Strings
*******

In Jakelib2 all strings should be represented by instances of jakelib::lang::String rather than by standard char* arrays.

An instance of jakelib::lang::String holds an immutable unicode character sequence. Every character is represented by one 16-bit wide jchar value. Thus, only the first 65535 unicode characters are actually supported. Perhaps Jakelib will learn how to handle 32-bit wide characters in the future. But it appears that you normally don't need any of these strange characters.

Character Encoding
==================

Whenever strings are created from C-style char* arrays, read from streams or written to streams, character encoding is necessary to convert between the internal unicode representation and any other character encoding.

jakelib::io::InputStreamReader and jakelib::io::OutputStreamWriter do these conversions for IO streams.

The following character encodings are supported by now:

       ISO8859-1    (latin-1)
       ISO8859-2    (latin-2)
       ISO8859-3    (latin-3)
       ISO8859-4    (latin-4)
       ISO8859-5    (Cyrillic)
       ISO8859-6    (Arabic)
       ISO8859-7    (Greek)
       ISO8859-8    (Hebrew)
       ISO8859-9    (latin-5)
       ISO8859-10   (latin-6)
       ISO8859-11   (Thai)
       ISO8859-13   (latin-7)
       ISO8859-14   (latin-8)
       ISO8859-15   (latin-9)
       UTF-8        (Unicode)
       ASCII        (7-bit ASCII)
       CP1252       (Windows)
       CP437        (Windows, US)
       CP850        (Windows, latin1)

The actual work of encoding is done by two groups of classes: jakelib::text::enc::ByteToChar<enc> convert byte sequences to unicode characters (input) and jakelib::text::enc::CharToByte<enc> convert unicode characters to bytes (output).

Jakelib Preprocessor
====================

Jakelib2 has its own C++ preprocessor (jlpp). jlpp helps the programmer as it allows writing more Java-like code. For now this means that string handling is very much simplified.

jlpp creates cpp files from jlc files. So, if you look at Jakelib's sources, don't look at the cpp files. Instead look at the jlc files wherever exsisting.

Without the preprocessor one would have to write something like this:

       System::out->println(String("Just a lousy test: ").plus((jlong) 12345));

In Java the same line of code would look like this:

       System.out.println("Just a lousy test: " + 12345);

The disadvantage of the upper C++ version without jlpp is not just that it looks quite ugly: For every invocation of this println method, a new instance of the (constant) string "Just a lousy test: " is created. This would not only cost memory but also some time because some kind of character encoding needs to be done when creating strings from C-style character arrays.

To avoid this, jlpp replaces string literals by constant static instances of jakelib::lang::String. This way every constant string will be created only once. jlpp also offers the new .. operator which is a substitution for Java's string concatenation operator +. Example:

       System::out->println(`"Just a lousy test: "` .. (jlong) 12345);

By default jlpp replaces only string literals that are enclosed in back ticks ` and double quotes ". This is to stay downwards compatible. Otherwise it would not be possible to call other library functions that take char* as arguments.

In source files that do not contain any function calls to non-jakelib functions taking char* as arguments, the javasyntax pragma can be used:

       #pragma javasyntax
       System::out->println("Just a lousy test: " .. (jlong) 12345);

From the line of code downwards where the javasyntax pragma is given, jlpp will replace string literals that are enclosed in back ticks or double quotes. The cppsyntax pragma returns to the default mode.

       #pragma javasyntax
       System::out->println("Just a lousy test: " .. (jlong) 12345);
       #pragma cppsyntax
       printf("Returning to normal c++ syntax");

For every string literal jlpp encounters, a static jchar array called chars_jakelib2_str_n is inserted at the beginning of the cpp file. This array contains the unicode characters of the string. The string object itself will be created on-demand when it is actually used for the first time. The string objects are stored in an array called jakelib2_strings[].

Note: In multi-threaded applications it is not guaranteed that every string object will be created only once. That is, the on-demand creation of these strings is not synchronized!

Multi Threading
***************

Synchronization
===============

In Java any object derived from Object can be used as a monitor.

In Jakelib only classes implementing the jakelib::lang::Synchronizeable interface can be used as a monitor. This is simply to save system resources.

By now only Java's synchronized keyword is implemented, wait() and notufy() are yet to be implemented.

       class Sync : public Object, public Synchronizeable
       {
         public:
          Sync() {};

          void Sync::foo()
          {
            ...
            {
              JAKELIB_SYNCHRONIZED(this)

              // We are inside the synchronized block :-)
            }

            // End of synchronized block.
            ...
          }
       };

Internally the JAKELIB_SYNCHRONIZED macro instantiates a Sentry object on the stack. A Sentry locks a mutex in its constructor and unlocks it in its destructor which is called when the Sentry object runs out of scope.

License
*******

GNU Lesser General Public License Version 2.1, February 1999

Jakelib2 is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1, or any later version.

This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this package; see the file COPYING.  If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

Copyright © 2000 - 2003 Florian Wolff <florian@jakelib.org>

Verbatim copying and distribution of this entire document is permitted in any medium, provided this notice is preserved.