Creating HTML using DOM and JavaScript

We use a lot of XML fetching in our web applications to fetch information from the server and processing it with JavaScript afterwards. What we normally do is to have a target division hardcoded in the correct location on the page and use JavaScript to add content.

The below example is taken out of context and it utilizes a custom JavaScript object that does all the dirty work and calls the processXML(boolean success) method once the XML is ready for processing. The interesting part is where the HTML is dynamically built using the createElement(String name) and appendChild(Element e) functions.

Searcher.prototype.processXML = function(success) {
  // how did we fare ?
  if (!success) {
    window.status = "Something went wrong while getting the XML while searching - aborting...";
    return;
  }

  try {
    // loop databases
    var databases = this.getElementsByTagName("database");
    if (null == databases) return;
    for (var i=0; i<databases.length; i++) {
      // get next database
      var database = databases[i];

      // get the title and path of the database
      var db_title = this.getTagValue(database.childNodes, "title");

      // get all results for database
      var results = null;
      for (var j=0; j<database.childNodes.length; j++) {
        if (database.childNodes[j].tagName == "results") {
          results = database.childNodes[j];
        }
      }

      // get result count
      var r_count = results.getAttribute("count");

      // create element for db title
      var elem_db = document.createElement("div");
      elem_db.id = "database" + i;
      elem_db.innerHTML = db_title + " (" + r_count + " resulter)";
      elem_db.className = "searchresults_database";
      elem_db.onmouseover = changeCursor;
      elem_db.onmouseout = changeCursor;
      elem_db.onclick = clickDatabase;
      this.pResults.appendChild(elem_db);

      // create element for result section (collapsed)
      var elem_results = document.createElement("div");
      elem_results.id = "results" + i;
      elem_results.className = "searchresults";
      elem_results.style.visibility = "hidden";
      elem_results.style.display = "none";
      this.pResults.appendChild(elem_results);

      // loop results
      for (var j=0; j<results.childNodes.length; j++) {
        if (results.childNodes[j].tagName == "result") {
          // get next resultsitem
          var r = results.childNodes[j];

          // get title and key
          var r_title = this.getTagValue(r.childNodes, "title");
          var r_key = this.getTagValue(r.childNodes, "key");
          var r_link = this.getTagValue(r.childNodes, "link");

          // add link anchor
          var elem_link = document.createElement("a");
          elem_link.href = r_link;
          elem_link.className = "searchresult";
          elem_link.appendChild(document.createTextNode(r_title));
          elem_results.appendChild(elem_link);
          elem_results.appendChild(document.createElement("br"));
        }
      }
    }

  } catch (exception) {
    // some error occured
    window.status = "Exception caught in Searcher.processXML(): " + exception.message;
  }
}

One thing I found out is that the Microsoft XML component allows for asynchroneous fetching. This allows you to show a progress bar or similar while loading and processing in the background.

function go() {
   // set to fetch asynchroneous
   this.pXML_data.async = true;
   // set callback method
   this.pXML_data.onreadystatechange = waitForXml;
   // go fish !!
   var success = this.pXML_data.load(url);
}

function waitForXml() {
   // wait for document to be completely loaded
   if (gXML_handler.getXmlIsland().readyState == "interactive") {
      // document has been loaded - process it
      processXML();
   }
}

function processXML() {
   // do processing...
}

Compile Apache 2 with mod_ssl

When configuring Apache 2.0 before compiling (make) and you are enabling mod_ssl you sometimes get an error saying that the OpenSSL headers cannot be found. To fix this make sure to configure using the –with-ssl=<path to OpenSSL installation> parameter.

Connecting to IBM DB2 v.8.x using JDBC

Trying to configure JDBC for DB2 v.8.x I had an error messages that just wouldn’t go away:

java.lang.UnsatisfiedLinkError: no db2jdbc in java.library.path

The problem appeared to be configuration issues and the fact that DB2 v.8 ships with a new universal JDBC driver. There are a number of things that are different about the new driver:

  • New driver jar-file (db2jcc.jar)
  • Requirement for a license jar-file (in my case I guessed that the required license jar-file was db2jcc_license_cu.jar since it was the only one in /opt/IBM/db2/V8.x/java)
  • Change driver class name to
    com.ibm.db2.jcc.DB2Driver
  • Make sure the native library are in the library path if using the type 2 driver (JDBC against a local DB2 installation):

    export DB2PATH=/opt/IBM/db2/V8.1
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DB2PATH/lib
    

The JDBC URL syntax is the same as previously.

If you forget adding the DB2 directory to the LD_LIBRARY_PATH you’ll get an error message saying:

com.ibm.db2.jcc.b.SqlException: Failure in loading T2 native library db2jcct2

Installing IBM DB2 v. 8.x on Linux without X11

To install DB2 manually follow the below steps:

  1. Download DB2 v.8.x for Linux (I downloaded v. 8.1 Express) and transfer the gzip’ed tar-file to the Linux box.
  2. Unpack the distribution to the /tmp directory:

    tar zxf DB2ExE82_Linux.tar.gz -C /tmp
    
  3. Change to root and go to the unpacked DB2 directory and start the installation:

    cd /tmp/Linux
    ./db2_install
    
  4. Select the package to install – I chose “DB2.EXP” since I was installing DB2 Express.
  5. Create an user for the DB2 instance and an user for the administration server (make sure the users belong to a valid group and that the users have a home directory):

    useradd db2inst1
    useradd db2as
    groupadd db2inst1
    groupadd db2as
    mkdir /home/db2inst1
    mkdir /home/db2as
    chown db2inst1:db2inst1 -R /home/db2inst1
    chown db2as:db2as -R /home/db2as
    <associate the group with the user e.g. using yast under SuSE or manually editing
    the /etc/groups file if you are so inclined>
    
  6. Create an instance:

    cd /opt/IBM/V8.1/instance
    ./db2icrt -u db2inst1 db2inst1
    
  7. Create the administration server:

    cd /opt/IBM/V8.1/instance
    ./dascrt -u db2as
    
  8. Set the environment for the db2inst1 user by adding the following to the users ~/.profile:

    ./sqllib/db2profile
    export DB2INSTANCE=db2inst1
    export DB2PATH=~/sqllib
    export PATH=$PATH:$DB2PATH/bin
    
  9. Log in as the db2inst1 user and check the installation by creating the SAMPLE database:

    su - db2inst1
    db2sampl
    

Sources:

Sametime login issues

The problem was that we got confused with the difference types of server names needed in different places. If you got confused what are you doing setting up Sametime servers one might ask, but in our defense this is the first time we experienced this problem. Whether we have just been “lucky” I don’t know. Anyways…

When setting up Sametime for an user you need to input the Sametime server on the person document in the Domino Directory and the Sametime server on the users location document. The problem turned out to be that the server name on the person document should be the fully qualified name of the server (e.g. Sametime1/XYZ/Example) and the server name on the location document should be a resolvable hostname or IP address to the server (e.g. sametime1.example.com / 10.0.0.1). Once we found this out configuring it was a breeze using the Domino Administration and policies.

So much for easy to read documentation… 🙂

Update (18 February 2005): Apparently not the only one being confused – a technote has been published.

Thoughts for a shared mail database

The number one problem we see in Notes installations is the lack of proper support for shared mail databases. I don’t mean shared mail in the Domino sense but a non-primary mail database where a number of people access and read shared e-mail (e.g. mail@example.com). I will now start compiling a list of requirements for this database so we can develop one once and for all.

Requirements

java.lang.OutOfMemoryError

The following goes in the notes.ini on the server – the settings are quite self explainatory:

JavaStackSize=<size in bytes>

JavaMaxHeapSize=<size in bytes>

NotesItemWrapper

'*** Constants ***
Private Const ITEM_MAX_SIZE = 31000


Public Class NotesItemWrapper
	'declarations
	Private pDoc As NotesDocument
	Private pCurrentItem As NotesItem
	Private pItemNames As Variant
	Private pItemIndex As Integer

	'/**
	' * Constructor.
	' */
	Public Sub New(doc As NotesDocument, item_names As Variant, append_data As Boolean)
		'declarations
		Dim i As Integer

		'store the document
		Set Me.pDoc = doc

		'item_names must be an array of strings or a item
		Forall n In item_names
			If Typename(n)  "STRING" Then
				Error 9999, "The supplied item names but be a string or an array of strings."
			End If
		End Forall

		'make sure the item names are an array
		If Not Isarray(item_names) Then
			Dim v(0) As String
			v(0) = Cstr(item_names)
			Me.pItemNames = v
		Else
			'store the item names to use
			Me.pItemNames = item_names
		End If

		'get the first item to use
		If Not append_data Then
			'remove all the items with the supplied names and recreate the first one
			Forall n In Me.pItemNames
				Call Me.pDoc.RemoveItem(n)
			End Forall

			'recreate the first item
			Set Me.pCurrentItem = New NotesItem(Me.pDoc, Me.pItemNames(Me.pItemIndex), "")
		Else
			'find the first item to use
			For i=0 To Ubound(Me.pItemNames)
				'get the first item
				Set Me.pCurrentItem = Me.pDoc.GetFirstItem(Me.pItemNames(Me.pItemIndex))

				'is this item below the threshold
				If Lenb(Me.pCurrentItem.Text) < ITEM_MAX_SIZE Then
					'use this item
					Me.pItemIndex = i
					Exit For
				End If
			Next
		End If
	End Sub

	'/**
	' * Appends text to the item checking whether a new item
	' * is required to hold the text. If no more fields are
	' * available we return an Error 9999.
	' */
	Public Sub AppendText(data As String)
		'check whether there is space for the data
		If Me.pCheckSize(data) Then
			'it is ok - append
			Me.pCurrentItem.Text = Me.pCurrentItem.Text + data
		Else
			'raise error
			Error 9999, "Not enought space to hold the data."
		End If
	End Sub

	'/**
	' * Appends a multi-value item to the item(s). If no more space
	' * is available we return an Error 9999.
	' */
	Public Sub AppendToTextList(data As String)
		'check whether there is space for the data
		If Me.pCheckSize(data) Then
			'it is ok - append
			Call Me.pCurrentItem.AppendToTextList(data)
		Else
			'raise error
			Error 9999, "Not enought space to hold the data."
		End If
	End Sub

	'*****************************************************************************
	'* Private methods
	'*****************************************************************************

	'/**
	' * Checks the size of the current item. Returns True if the item
	' * can hold the supplied data.
	' */
	Private Function pCheckSize(data As String) As Boolean
		'declarations
		Dim size As Long

		'calculate the item size
		size = Lenb(Me.pCurrentItem.Text) + Lenb(data)
		'Print "Size is: " & size & " (index = " & Me.pItemIndex & ", " & Me.pCurrentItem.Name & ")"

		'decide what to do
		If size < ITEM_MAX_SIZE Then
			'item can hold the byte count
			pCheckSize = True
		Else
			'no can do - try and get the next item
			If Me.pItemIndex <= Ubound(Me.pItemNames) Then
				'get the next item
				Me.pItemIndex = Me.pItemIndex + 1
				Set Me.pCurrentItem = New NotesItem(Me.pDoc, Me.pItemNames(Me.pItemIndex), "")

				'return true
				pCheckSize = True
			Else
				'no more items
				pCheckSize = False
			End If
		End If
	End Function

End Class