Weblog

IDE productivity for JSF: a screencast

It seems my previous posts on JSF components and productivity have been cause for some discussion, see The serverside and the Tapestry – User mailinglist.

I like the productivity of ADF Faces in combination with JDeveloper. This doesn’t mean i think it’s the greatest technology in the world. I wouldn’t use jsf if i wanted total control of the generated html (and i’m pretty anal when it comes to semantically and structurally correct html). I also wouldn’t use adf if i knew the product also had to be maintained in something else than JDeveloper. ADF bindings and ADF Faces are great for productivity, but i don’t like it when you have to code with it. Everything is dynamic, which means you don’t get code completion and a lot of errors are only caught at runtime.

In my opinion this is just a tradeoff you have to make when using a technology stack suited for tooling. The ADF bindings and ADF Faces toolstack works well with tools, but for hand coding i prefer a combination of JSP (i haven’t tried Tapestry yet), Spring and Hibernate. Some frameworks are great for tools , some are great for coders.

But i think there are a lot of IT-managers who are waiting for a tool that will give them 4GL like productivity, something they are used to with Oracle Forms or Oracle Designer. And they want a tool which is going to enable 4GL programmers (property-clickers) to create java web applications. And i think Oracle is going into that direction with JDeveloper.

I’ve made a screencast to show you JDeveloper’s JSF support: Developing JSF applications with JDeveloper. In 6 minutes i’m building a jsf page to add, delete and edit weblog posts. The page consists of a data entry form and a table listing weblog posts. You can page through the table, sort the columns, a calendar popup is available, and a dropdown list with weblog categories. All without a single line of coding. The application is not finished, nor polished. (And it contains a simple to fix error. If you can spot it, apply for a job here ;-)

The model is created using ADF Business Components, which is an Oracle proprietary ORM framework. JDeveloper doesn’t limit your model choices, You can use EJB3 or Toplink. You could also use Hibernate or Pojo’s. On a previous project (pdf) i’ve used Castor generated Pojo’s in combination with ADF. Whatever you choose, you can drag and drop your data on JSF pages, and visually build your application.

Calling c from plsql

At the moment we are implementing an internet application (with ADF faces)and have to call a (pro*)C-module. This c-module is an old monster of 8000 lines of code and there is no time to rewrite (and test !) it to plsql. The module is also called in the backoffice system in webforms (ora_ffi).

I want :

  • to use the same dynamic link library (DLL) for both systems
  • no linking of pro*C libraries in the java application
  • security

The solution is to build a plsql wrapper around the DLL and store this in the database so that you can call the plsql module in the database.

This is what I did (Linux) :

1. Listener proces.

Start a new listener proces exclusively for external procedures. By default the agent that handles the procedures is named extproc.

tnsnames.ora

EXTPROC_CONNECTION_DATA =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS =
        (PROTOCOL = IPC)
        (KEY = EXTPROC_KEY)
      )
    )
    (CONNECT_DATA =
      (SID = EXTPROC_AGENT)
    )
  )

listener.ora

PLS_LISTENER =
    (DESCRIPTION =
        (ADDRESS = (PROTOCOL = IPC)
                   (KEY = EXTPROC_KEY)
        )
    )

SID_LIST_PLS_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (SID_NAME = EXTPROC_AGENT)
      (ORACLE_HOME = /u01/product/1010)
      (PROGRAM = extproc)
      (ENVS="C_LIB_HOME=/u01/projects/bin")
    )
  )

$C_LIB_HOME is an environment variable which is used for the location in step 2. De KEY in tnsnames.ora and listener.ora must be the same.

2. Make the location of the library known in the database

Run this command in sqlplus :

create or replace library c_analyse is
  '${C_LIB_HOME}/analyse.so'
/

3. Build the wrapper per function.

This can de done with the AS LANGUAGE clause in plsql functions, procedures or packages. I prefer the package specification. In the package body you can then add other code which is related to the c-module.

create or replace package C_wrapper
as

   function init
   return pls_integer
   as language c
      name "init"
      library c_analyse;

   function do_things( par1  pls_integer
                     , par2  pls_integer
                     )
   return pls_integer
   as language c
      name "do_things"
      library c_analyse
      parameters(par1 long, par2 long);

end;

4. Errorhandling.

With step 1-3 it all works fine and I have not changed a single line of code in the C monster. But if you want to get proper error messages back from the call, you have to add a parameter in each call and some(?) more lines in the code. You can make use of the OCI functions OCIExtProcRaiseExcp or OCIExtProcRaiseExcpWithMsg. Add the parameter context pointer to all the functions.

int do_things( OCIExtProcContext *ctx
             , long par1
             , long par2
             )
...
     if (OCIExtProcRaiseExcpWithMsg(ctx, (int)20100,
          "This is the error message", 0) == OCIEXTPROC_SUCCESS)
    {
      return;
...

In the plsql wrapper add the WITH CONTEXT clause and the extra parameter:

   function do_things( par1  pls_integer
                     , par2  pls_integer
                     )
   return pls_integer
   as language c
      name "do_things"
      library c_analyse
      with context
      parameters(context, par1 long, par2 long);

JSF productivity

I noticed some people are linking to yesterdays post Creating a jsf div component as an example of how non-productive jsf is. I agree, it is a lot of work, just to create a simple component. But as i said before, it’s an example of how to create a component. You don’t have to use a component to render a div.

But the fact that it’s easier in Tapestry to create a component doesn’t mean that developing in Tapestry is more productive. To be truly productive you need more than a powerful framework, you also need IDE support. I think this is where JDeveloper’s support for JSF beats whatever IDE support Tapestry has. Overall, developing with JSF and a good IDE will probably be faster than handwriting tapestry pages.

But, yes, i would appreciate it, if it were simpler to create JSF components, and i would also appreciate it if adf faces would generate some sane Html so i don’t have to create my own components or custom renderers. There is room for improvement.

Update:
See the followup post: IDE productivity for JSF: a screencast.

Creating a jsf div component

While creating a prototype for a web application using ADF Faces i noticed that Oracle’s JSF implementation still generates Html like it’s 1999. Lots of tables, more tables and more nested tables. ADF Faces even contains an ObjectSpacer component which adds a transparent image in your page. Ough. Big ugly mess.

The problem with tables is, apart from the fact that your pages will be bigger than necessary, that they’re pretty rigid. You don’t have a lot of positioning flexibility when creating the appearance of your page. This flexibility is pretty important when creating web application. Companies want their web applications to look good, not standard, when they are used by the outside world.

I started with the PanelPage component to layout the major parts of the page but because of the tables i could not get the required page design. I tried some other ADF Faces components, but didn’t find what i needed. PanelBox generates a single cell table. PanelHeader was the best i could find. It puts all it’s children in a div, but also generates an unwanted header tag.

What are the alternatives? I could use an html div tag or look for a JSF div component elsewhere (i think the MyFaces project contains a Div component). But instead, to learn a bit more about JSF, i decided to implement a custom Div component. I another post i’ll describe another alternative, a customer renderer for an existing component.

Div Component

The JSF component class contains the behaviour of your class. You can include the html rendering, but it’s cleaner to put that in a separate class. A panel doesn’t have a lot of behaviour as you can see in the following code. I’m subclassing UIPanel because it has the same behaviour as the Div component i want to implement.

package nl.iteye.jsf.components;

import javax.faces.component.UIPanel;

public class UIDiv extends UIPanel {
    public static final String COMPONENT_TYPE = "nl.iteye.jsf.Panel";
    public static final String RENDERER_TYPE = "nl.iteye.jsf.Div";

    public UIDiv() {
        setRendererType(RENDERER_TYPE);
    }

}

Div Renderer

The renderer creates the required html code. It is also used to read anything send by the browser, but that’s not needed in this case.

package nl.iteye.jsf.components;

import java.io.IOException;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;

public class DivRenderer extends Renderer {
    public DivRenderer() {
    }

    public void encodeBegin(FacesContext context,
                            UIComponent component) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("div", component);
        writer.writeAttribute("id", component.getClientId(context),
                              "clientId");
        writer.writeAttribute("class",
                              component.getAttributes().get("styleclass"),
                              "styleclass");
        writer.flush();
    }

    public void encodeEnd(FacesContext context,
                          UIComponent component) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        writer.endElement("div");
        writer.flush();
    }

    public void decode(FacesContext context, UIComponent component) {
        return;
    }
}

Div Tag

Next i need to create a JSP tag class, because i’m going to use the JSF component in JSPs. A property for id is not needed, this is provided by the super class.

package nl.iteye.jsf.components;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.webapp.UIComponentTag;

public class DivTag extends UIComponentTag {
    private String styleClass;

    public DivTag() {
    }

    public String getComponentType() {
        return UIDiv.COMPONENT_TYPE;
    }

    public String getRendererType() {
        return UIDiv.RENDERER_TYPE;
    }

    public void setProperties(UIComponent component) {
        super.setProperties(component);
        setStringProperty(component, "styleclass", styleClass);
    }

    public void setStyleclass(String styleClass) {
        this.styleClass = styleClass;
    }

    public String getStyleclass() {
        return styleClass;
    }

    private void setStringProperty(UIComponent component, String name,
                                   String value) {
        if (value == null) {
            return;
        }
        if (isValueReference(value)) {
            component.setValueBinding(name,
                                      FacesContext.getCurrentInstance().getApplication()
                                      .createValueBinding(value));
        } else {
            component.getAttributes().put(name, value);
        }
    }
}

Configuration

Declare the component in the faces configuration file faces-config.xml. Two entries are required, one for the component, and one for the render-kit. A render-kit isn’t specified, which means that the renderer will be part of the default html renderkit.

  <component>
    <component-type>nl.iteye.jsf.Panel</component-type>
    <component-class>nl.iteye.jsf.components.UIDiv</component-class>
  </component>
  <render-kit>
    <renderer>
      <component-family>javax.faces.Panel</component-family>
      <renderer-type>nl.iteye.jsf.Div</renderer-type>
      <renderer-class>nl.iteye.jsf.components.DivRenderer</renderer-class>
    </renderer>
  </render-kit>

Register the Div tag in the tag library file:

<?xml version = '1.0' encoding = 'UTF-8'?>
<!DOCTYPE taglib
  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>2.0</jsp-version>
  <short-name>jsf-layout</short-name>
  <uri>/iteye/jsf</uri>
  <display-name>Layout components</display-name>
  <tag>
    <name>div</name>
    <tag-class>nl.iteye.jsf.components.DivTag</tag-class>
    <attribute>
      <name>id</name>
    </attribute>
    <attribute>
      <name>styleclass</name>
    </attribute>
  </tag>
</taglib>

Example

The following code shows a simple example. Normally i would use an id attribute instead of a class attribute in the example below, because you only have one header and one logo on every page. Unfortunately, JFS makes the id attribute unusable for css styling purposes, as it prepends the ids of all the parent components to the id of a component.

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns="http://www.w3.org/1999/xhtml"
          xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:af="http://xmlns.oracle.com/adf/faces"
          xmlns:wt="/iteye/jsf">
  <f:view>
    <html>
      <body>
        <h:form>
          <wt:div styleclass="page">
            <wt:div styleclass="header">
              <wt:div styleclass="logo">
                <af:objectImage source="/images/logo.gif"/>
              </wt:div>
            </wt:div>
          </wt:div>
        </h:form>
      </body>
    </html>
  </f:view>
</jsp:root>

This is not fastest way to create divs using JSF, but still usefull as an example of how to create a JSF component. As said before, you can just use a html div tag (for an interesting discussing about using html tags, see Chris Schalk’s weblog: JSF: Getting the Right Mixture of Components and Markup), but using html may be a problem when you decide to use a non html render kit. If you don’t need a new component, just different markup, a better option is to create a new renderer.

Update:
See the followup posts: JSF productivity, and IDE productivity for JSF: a screencast.

Need to login twice for Oracle Discoverer Plus

Having the problem that, each time when starting up Oracle Discoverer Plus (10.1.2) and you try to login, you need to login twice to because the first time login failed. Well here’s the solution to your problem. This behaviour is caused by an incorrect conversion of the URL in OC4J.

Quick fix

The shorttime solution (for end users) is to startup Oracle Discoverer Plus using the complete servername and domainname in the URL (instead of using the shortname). Start Discoverer Plus throught: http://servername.domain.com/discoverer/plus

Robust solution

The longtime solution lies in adjusting the Apache/Apache/httpd.conf file.
The servername needs to be modified into the fully qualified servername. (so including the domainname).
Old situation is probably this:

servername      servername

New situation should be:

servername      servername.domainname.com         ## or whatever your domainname is.

After changing and saving the   httpd.conf   configuration file, Stop and Start Apache to make the change effective.

OMBPlus – Create tables based on Source tables

It is very common, when creating a Staging Area in Oracle Warehouse Builder, to create tables in this Oracle Module with the same structure and similar names as the tables in the Oracle Source Modules.

When the above is the case and a lot of tables are needed then it is far more productive and effective to create those tables using an OMBPlus script.

See below script for creating tables.

# Set variables.
puts -nonewline "SET VARIABLES.... "
set project 'DATAWAREHOUSE_PROJECT'

set sourcemodule 'SOURCE_AMSTERDAM'

set targetmodule 'STAGING_AREA'
puts "DONE"

# Get tables from $project/$sourcemodule
  OMBCC $project
  OMBCC $sourcemodule

  set tableList [ OMBLIST TABLES ]
  foreach tableName $tableList {
    puts $fname "$project / $sourcemodule / $tableNamer"
    puts $fname "***********************************************************************************r"
#   Delete last 4 characters (_CUM) of the name of the selected table.
    puts -nonewline "RENAMING TABLE NAME $tableName.... "
#   Get lenght of selected tablename.
    set v_t_lengte [string length '$tableName']
#   Set lenght of string 7 chars smaller;  startposition + (_CUM' )
    incr v_t_lengte -7
#   Create new tablename for SA.
    set v_sourcetable [string range $tableName 0 $v_t_lengte]
    puts "$v_sourcetable"
    puts $fname "MODIFIED TABLE NAME $tableName TO $v_sourcetabler"

    OMBCC '..'
    OMBCC $targetmodule

#   Create new table in SA.
    puts -nonewline "CREATE TABLE $v_sourcetable IN $project/$targetmodule.... "
    OMBCREATE TABLE '$v_sourcetable'
    puts "CREATED"
    puts $fname "TABEL $v_sourcetable CREATED IN $project / $targetmoduler"
    puts $fname "-----------------------------------------------------------------------------------r"
    puts $fname "             TABEL			DATATYPE	LENGTH		NOT_NULLr"
    puts $fname "             ===============		=============	============	========r"

    OMBCC '..'
    OMBCC $sourcemodule
#   Get all colomnnames, datatypes and lenght per table.
    set columnList [ OMBRETRIEVE TABLE '$tableName' GET COLUMNS ]
    foreach columnName $columnList {
      puts "  ADD COLUMN $columnName TO $v_sourcetable"
      puts -nonewline "    GET COLUMN PROPERTIES.... "
      set columnDataType [ OMBRETRIEVE TABLE '$tableName' COLUMN '$columnName' GET PROPERTIES (DATATYPE) ]
      set columnDataNull [ OMBRETRIEVE TABLE '$tableName' COLUMN '$columnName' GET PROPERTIES (NOT_NULL) ]
      set columnDataLength "N/A"
      puts "DONE"
      if {"$columnDataType" == "VARCHAR2"} {
        puts -nonewline "    RESIZE DATATYPE.... "
        set columnDataLength [ OMBRETRIEVE TABLE '$tableName' COLUMN '$columnName' GET PROPERTIES (LENGTH) ]
#       The colomn values need to be changed into the project standards.
#        varchar2 >=   15 wordt varchar2(15)
#        varchar2 >=   50 wordt varchar2(50)
#        varchar2 >=  100 wordt varchar2(100)
#        varchar2 >=  250 wordt varchar2(250)
#        varchar2 >= 1000 wordt varchar2(1000)
        if {$columnDataLength < 15} {
          set columnDataLength 15
        } elseif {$columnDataLength < 50} { set columnDataLength 50
          } elseif {$columnDataLength < 100} { set columnDataLength 100
            } elseif {$columnDataLength < 250} { set columnDataLength 250
              } else { set columnDataLength 1000 }
        puts "RESIZED"
        OMBCC '..'
        OMBCC $targetmodule
        OMBALTER TABLE '$v_sourcetable' ADD COLUMN '$columnName' SET PROPERTIES (DATATYPE, LENGTH, NOT_NULL)
                                                                 VALUES ('$columnDataType', $columnDataLength, $columnDataNull)
      } else {
#         number           becomes (no (precision, scale))
#         date             becomes date
          OMBCC '..'
          OMBCC $targetmodule
          OMBALTER TABLE '$v_sourcetable' ADD COLUMN '$columnName' SET PROPERTIES (DATATYPE, NOT_NULL)
                                                                   VALUES ('$columnDataType', $columnDataNull)
        }
      puts "  ADDED COLUMN; DATATYPE: $columnDataType, LENGTH: $columnDataLength, NOT_NULL: $columnDataNull"
      puts $fname "  ADD COLUMN $columnName			$columnDataType		$columnDataLength	$columnDataNullr"
      OMBCC '..'
      OMBCC $sourcemodule
    }
#     Add new attributes toselected table.
#     Set pointer from $sourcemodule to $targetmodule.
      OMBCC '..'
      OMBCC $targetmodule
      puts -nonewline "ADD NEW ATTRIBUTS.... "
      OMBALTER TABLE '$v_sourcetable' ADD COLUMN 'MUTATIE_CDE' SET PROPERTIES (DATATYPE, LENGTH)
                                                               VALUES ('VARCHAR2', 15)
                                      ADD COLUMN 'PROCES_CDE' SET PROPERTIES (DATATYPE, LENGTH)
                                                              VALUES ('VARCHAR2', 30)
                                      ADD COLUMN 'PROCES_DAT' SET PROPERTIES (DATATYPE)
                                                              VALUES ('DATE')
      puts "DONE"
      puts $fname "  ADD COLUMN MUTATIE_CDE	VARCHAR2		15	0r"
      puts $fname "  ADD COLUMN PROCES_CDE	VARCHAR2		30	0r"
      puts $fname "  ADD COLUMN PROCES_DAT	DATE		0	0r"
      puts $fname "r"
      puts -nonewline "COMMITTING.... "
      OMBCOMMIT
      puts "COMMITTED"
  }

Script was accomplished with the help of Ludo de Heus.
Email: l.deheus@dba.nl

OMBPlus – Create mapping with operators

Below script shows how to create a mapping in Oracle Warehouse Builder with operators using OMBPlus as scripting language based on a list of source tables and a list of target tables. In this example target tables are located in the Staging area and have the same structure as the Source tables except that the target tables have a view attributes extra.

The mapping detects a delta on the data to be loaded using a filter on load date (“laaddatum”).
After that the data is marked with a Mutation_Code for Updating, Deleting or Inserting records when loading to the next stage (Datawarehouse).

  foreach sourceTableName $tableList {

    puts -nonewline "CREATE MAPPING E_$sourceTableName .. "
    OMBCREATE MAPPING 'E_$sourceTableName' SET PROPERTIES (DESCRIPTION )
                                         VALUES ('mapping comment')
    ADD TABLE OPERATOR 'A_$sourceTableName_CUM'
              BOUND TO TABLE '../$sourcemodule/$sourceTableName_CUM'
    ADD TABLE OPERATOR 'B_$sourceTableName_CUM'
              BOUND TO TABLE '../$sourcemodule/$sourceTableName_CUM'
    ADD CONSTANT OPERATOR 'PROCES_VARIABLES'
    ADD ATTRIBUTE 'PROCES_CDE' OF GROUP 'OUTGRP1' OF OPERATOR 'PROCES_VARIABLES' SET PROPERTIES (DATATYPE, LENGTH, EXPRESSION )
                                                                                 VALUES ('VARCHAR2', 30, '''E_$sourceTableName''')
    ADD ATTRIBUTE 'LAAD_DATUM' OF GROUP 'OUTGRP1' OF OPERATOR 'PROCES_VARIABLES' SET PROPERTIES (DATATYPE, EXPRESSION )
                                                                                 VALUES ('DATE', '"SA_ALGEMEEN"."GEEF_LAADDATUM"(''E_$sourceTableName'')')
    ADD FILTER OPERATOR 'A_LAADDATUM' SET PROPERTIES ( FILTER_CONDITION )
                                      VALUES ( 'INOUTGRP1.CREATE_DTT > INOUTGRP1.LAAD_DATUM')
    ADD FILTER OPERATOR 'B_LAADDATUM' SET PROPERTIES ( FILTER_CONDITION )
                                      VALUES ( 'INOUTGRP1.CREATE_DTT > INOUTGRP1.LAAD_DATUM')
    ADD JOINER OPERATOR 'JOIN_DETECT_WIJZIGINGEN' SET PROPERTIES ( JOIN_CONDITION )
                                                  VALUES ( 'INGRP1.MUT_CODE != INGRP2.MUT_CODE' )
    ADD SET_OPERATION OPERATOR 'S_INSERT_EN_DELETE' SET PROPERTIES ( SET_OPERATION )
                                                    VALUES ( 'MINUS' )
    ADD FILTER OPERATOR 'ALLEEN_UPDATE' SET PROPERTIES ( FILTER_CONDITION )
                                        VALUES ( 'INOUTGRP1.MUT_CODE = ''>'' ' )
    ADD SPLITTER OPERATOR 'SPLIT_INSERT_EN_DELETE'
    ADD CONSTANT OPERATOR 'CONST_PROCES_VARIABLE'
    ADD ATTRIBUTE 'I_MUT_CDE' OF GROUP 'OUTGRP1' OF OPERATOR 'CONST_PROCES_VARIABLE' SET PROPERTIES (DATATYPE, LENGTH, EXPRESSION)
                                                                                     VALUES ('VARCHAR2', 15, '''I''')
    ADD ATTRIBUTE 'D_MUT_CDE' OF GROUP 'OUTGRP1' OF OPERATOR 'CONST_PROCES_VARIABLE' SET PROPERTIES (DATATYPE, LENGTH, EXPRESSION)
                                                                                     VALUES ('VARCHAR2', 15, '''D''')
    ADD ATTRIBUTE 'U_MUT_CDE' OF GROUP 'OUTGRP1' OF OPERATOR 'CONST_PROCES_VARIABLE' SET PROPERTIES (DATATYPE, LENGTH, EXPRESSION)
                                                                                     VALUES ('VARCHAR2', 15, '''U''')
    ADD ATTRIBUTE 'PROCES_DAT' OF GROUP 'OUTGRP1' OF OPERATOR 'CONST_PROCES_VARIABLE' SET PROPERTIES (DATATYPE, EXPRESSION)
                                                                                      VALUES ('DATE', 'TRUNC(SYSDATE)')
    ADD TABLE OPERATOR 'I_$sourceTableName'
              BOUND TO TABLE '$sourceTableName'
    ADD TABLE OPERATOR 'D_$sourceTableName'
              BOUND TO TABLE '$sourceTableName'
    ADD TABLE OPERATOR 'U_$sourceTableName'
              BOUND TO TABLE '$sourceTableName'
    ADD CONNECTION FROM GROUP 'INOUTGRP1' OF OPERATOR 'A_$sourceTableName_CUM'
                   TO GROUP 'INOUTGRP1' OF OPERATOR 'A_LAADDATUM'
    ADD CONNECTION FROM GROUP 'INOUTGRP1' OF OPERATOR 'B_$sourceTableName_CUM'
                   TO GROUP 'INOUTGRP1' OF OPERATOR 'B_LAADDATUM'
    ADD CONNECTION FROM GROUP 'OUTGRP1' OF OPERATOR 'PROCES_VARIABLES'
                   TO GROUP 'INOUTGRP1' OF OPERATOR 'A_LAADDATUM'
    ADD CONNECTION FROM GROUP 'OUTGRP1' OF OPERATOR 'PROCES_VARIABLES'
                   TO GROUP 'INOUTGRP1' OF OPERATOR 'B_LAADDATUM'
    ADD CONNECTION FROM GROUP 'INOUTGRP1' OF OPERATOR 'A_LAADDATUM'
                   TO GROUP 'INGRP1' OF OPERATOR 'JOIN_DETECT_WIJZIGINGEN'
    ADD CONNECTION FROM GROUP 'INOUTGRP1' OF OPERATOR 'A_LAADDATUM'
                   TO GROUP 'INGRP1' OF OPERATOR 'S_INSERT_EN_DELETE'
    ADD CONNECTION FROM GROUP 'OUTGRP1' OF OPERATOR 'JOIN_DETECT_WIJZIGINGEN'
                   TO GROUP 'INGRP2' OF OPERATOR 'S_INSERT_EN_DELETE'
    ADD CONNECTION FROM GROUP 'OUTGRP1' OF OPERATOR 'JOIN_DETECT_WIJZIGINGEN'
                   TO GROUP 'INOUTGRP1' OF OPERATOR 'ALLEEN_UPDATE'
    ADD CONNECTION FROM GROUP 'OUTGRP1' OF OPERATOR 'S_INSERT_EN_DELETE'
                   TO GROUP 'INGRP1' OF OPERATOR 'SPLIT_INSERT_EN_DELETE'
    ADD CONNECTION FROM GROUP 'OUTGRP1' OF OPERATOR 'SPLIT_INSERT_EN_DELETE'
                   TO GROUP 'INOUTGRP1' OF OPERATOR 'I_$sourceTableName'
                   BY NAME
    ADD CONNECTION FROM GROUP 'OUTGRP2' OF OPERATOR 'SPLIT_INSERT_EN_DELETE'
                   TO GROUP 'INOUTGRP1' OF OPERATOR 'D_$sourceTableName'
                   BY NAME
    ADD CONNECTION FROM GROUP 'INOUTGRP1' OF OPERATOR 'ALLEEN_UPDATE'
                   TO GROUP 'INOUTGRP1' OF OPERATOR 'U_$sourceTableName'
                   BY NAME
    ADD CONNECTION FROM GROUP 'INOUTGRP1' OF OPERATOR 'B_LAADDATUM'
                   TO GROUP 'INGRP2' OF OPERATOR 'JOIN_DETECT_WIJZIGINGEN'
    ADD CONNECTION FROM ATTRIBUTE 'PROCES_DAT' OF GROUP 'OUTGRP1' OF OPERATOR 'CONST_PROCES_VARIABLE'
                   TO ATTRIBUTE 'PROCES_DAT' OF GROUP 'INOUTGRP1' OF OPERATOR 'I_$sourceTableName'
    ADD CONNECTION FROM ATTRIBUTE 'I_MUT_CDE' OF GROUP 'OUTGRP1' OF OPERATOR 'CONST_PROCES_VARIABLE'
                   TO ATTRIBUTE 'MUTATIE_CDE' OF GROUP 'INOUTGRP1' OF OPERATOR 'I_$sourceTableName'
    ADD CONNECTION FROM ATTRIBUTE 'PROCES_DAT' OF GROUP 'OUTGRP1' OF OPERATOR 'CONST_PROCES_VARIABLE'
                   TO ATTRIBUTE 'PROCES_DAT' OF GROUP 'INOUTGRP1' OF OPERATOR 'D_$sourceTableName'
    ADD CONNECTION FROM ATTRIBUTE 'D_MUT_CDE' OF GROUP 'OUTGRP1' OF OPERATOR 'CONST_PROCES_VARIABLE'
                   TO ATTRIBUTE 'MUTATIE_CDE' OF GROUP 'INOUTGRP1' OF OPERATOR 'D_$sourceTableName'
    ADD CONNECTION FROM ATTRIBUTE 'PROCES_DAT' OF GROUP 'OUTGRP1' OF OPERATOR 'CONST_PROCES_VARIABLE'
                   TO ATTRIBUTE 'PROCES_DAT' OF GROUP 'INOUTGRP1' OF OPERATOR 'U_$sourceTableName'
    ADD CONNECTION FROM ATTRIBUTE 'U_MUT_CDE' OF GROUP 'OUTGRP1' OF OPERATOR 'CONST_PROCES_VARIABLE'
                   TO ATTRIBUTE 'MUTATIE_CDE' OF GROUP 'INOUTGRP1' OF OPERATOR 'U_$sourceTableName'

OMBCOMMIT

Script was accomplished with the help of Ludo de Heus.
Email: l.deheus@dba.nl

Good accessibility required for Dutch government websites

According to Dutch minister Pechtold Dutch government websites currently aren’t accessible enough to people with disabilities. He even states that unaccessible websites should be taken offline. Only 4 percent of about ten thousend websites can be used by blind or handicaped users. The minister wants all government websites to comply with accessibility rules by 2010.

These accessibility rules are listed on Webrichtlijnen.overheid.nl (webguidelines.goverment.nl). According to this website an accessible website should minimally validate as XHTML 1.0 Strict. It should also comply with WCAG 1.0, Priority 1+.

I’m a bit surprised by the XHTML 1.0 Strict requirement. It seems to me that a transitional or even HTML 4 website could also be made accessible. Veerle has an interesting discussion on the value of webstandards for accessibility: Accessibility, Veerle’s point of view and an interesting follow-up A response from an accessibility consultant from Blindsurfer.

Another good Dutch source of information about accessibility is Drempels Weg. In the U.S. Section 508 already requires agencies to create accessible websites.

What does this mean for ADF Faces? According to the documentation ADF Faces has accessibility support. But i already noticed that it’s support for Xhtml could be better. When you create a JSF page you can specify what doctype you want to use, XHTML 1.0 Strict is included in this list. But there are some bugs in the skinning. The css file generated uses tags in upercase (BODY for example). This won’t work in firefox, as css selectors are case sensitive.

Update:
WCAG 1 describes when you should use tables and when you shouldn’t:

Tables should be used to mark up truly tabular information (“data tables”). Content developers should avoid using them to lay out pages (“layout tables”).

Seems like adf faces might not be such a good idea for accessible websites then, it currently relies heavily on tables for layout.

The AJAX Approach to Richer Interfaces

Chris Schalk has written an interesting article for JavaPro: The AJAX Approach to Richer Interfaces. After an introduction about the basics of AJAX he shows how to AJAX enable a JSF component.

The best feature in MS-Word has got to be…

Outline mode. Although MS-Word has had this feature for ages, I don’t see it being used a lot. Why do you need outline mode? Because it saves you time, it lets you write better documents, it will improve the quality of html export, and you’ll have an easier time programmatically processing your documents.

What is outline mode?

Outline mode lets you edit a document hierarchically. This enables you to easily reorder paragraphs, move sections in different order, close paragraphs you do not want to see, promote and demote sections, etc. You can view headings up to a certain level, and hide the rest of your document. There’s no better way to edit the structure of your document than by using outline mode.

Better documents

The most important thing to do before writing a document is to determine the structure of the document. What chapters do you need, what sections and subsections, and what are you going to put in every paragraph.

When I start writing a document I’ll begin with a brainstorm session. I’ll put every word I think relevant for the story in a Word document. When I think I have most of the important keywords, I’ll start putting them into a structure which makes sense. And finally when I have determined the correct structure, I’ll write the actually paragraphs.

Outline mode helps you create the correct structure of your document before you start writing it. It’s like writing a detailed table of contents and then filling it.

Save time

When you are working in outline mode, you don’t need to apply formatting or style. Word will automatically change the style of your heading when you promote or demote it to a different level. This saves you a lot of time, because you don’t have to change the appearance of your headings when you decide to demote a part of your document. No more applying styles or tweaking font types and sizes.

Seriously, using the toolbar to change text properties like font size and weight is highly overrated. If you create a document in outline view and then switch to normal view you’ll see that most of the formatting is pretty good. And you can easily change the appearance of headings at a certain level by changing a single style.

It’s better to use outline mode to really specify what your titles are, than to create title look-alikes using visual properties.

Improve html export

Why should you care if a title just looks like a title, or really is a title? It’s all about Search Engine Optimization (SEO): properly tagged titles result in better search results.

Why? Open a webpage. Now look at the source code of the page. Can you determine what the page is about? Do you see what the paragraph headers of the page are? If you can’t, Google can’t either. But you want Google to know what the titles on your page are, because this is the way it knows what your text is about. The headings basically contain the summary of your document. It’s pretty hard for a search engine to determine if something is a heading, just because you made it look like a heading by making it bold and slightly bigger. That’s why you need to tag it as a header. In my experience the words in your header tags directly influence search engine traffic.

The New York Times recently published an article on the impact of headings on search engines: boring headline is written for Google. It discusses the fact that you can’t write witty headlines if you want to be found by Google. According to this article “The search engine has to get a straightforward, factual headline, so it can understand it”. I don’t think it’s a matter of understanding. It’s probably a lot simpler than this. Search engines mostly just match the words you’re looking for to words in headings. This means that having good html headings is essential if you want to be found by search engines.

So how did we get from Word to Html? Well, many people write documents intended for the web using Word. They save it as (hopefully) filtered html. And just as many people complain about the Html code generated by Word. But if you write in outline mode, and don’t manually alter the appearance of the Word document, the Html code created by Word is actually reasonably decent. Most importantly, it will contain html header tags (h1, h2) instead of paragraph tags with some style to make it look like a heading.

Many people have discussed the advantages of using structurally and semantically correct Html. I think the same also makes sense for Word documents. The important thing to remember is that appearance is nothing. Just because you’ve made a sentence bold, and 24pt so it looks like a title, doesn’t mean that it’s really a title. At least not to a computer program.

Process documents

During a recent project I created some Xslt files to transform Xml files created using Word 2003. One of the major reasons Xml exists is that the strict format makes it easy for programs to process. But just because you have a file in Xml format, doesn’t mean that processing it is easy.

Word uses an XML dialect called WordML. To learn about WordML, I opened a couple of WordML documents in a text editor. When you open these Xml documents you get to see the real mess you can create using Word.

In WordML everything is a paragraph. A paragraph can have properties, for example a style. Inside the paragraph you can have multiple runs of text. And every run can also have properties that determine style, or font weight, or font size. The problem is that you can combine all these properties into one big mess. Your document will look ok, but the generated Xml is really unusable.

Some examples: I found one paragraph with a style indicating that it was a heading. But the paragraph was about 30 lines long, and after the first line, the run properties changed the look of the text into normal body text. I also found one paragraph where the style specified that the paragraph was part of a list. But in the run the list bullet was removed, and indentation was reversed. So in fact, the paragraph really wasn’t part of a list.

There’s a big difference between what you see on your screen and the files created by Word. In this respect Word definitely is not a “What you see is what you get” word processor. You see normal text, but in the xml you’re getting a heading style. You see normal text, but in the xml you’re getting lists. You see a heading, but in the xml it turns out to be just a normal paragraph with a big font.

However, if you write your documents in outline mode, rely on Word for formatting, and don’t manually modify formatting, the Xml created by Word is pretty good and easy to work with.

Outliners

Word is neither the first nor the only outliner. There are many programs that are just outliners, or that use outliners for specific tasks. If you want more information have a look at “About this particular Outliner”. This site has a wealth of information about outliners.

In my opinion document structure editing should be just as common as deleting or copying and pasting. It helps you write better documents, in many ways.

Technology
Ben jij slim genoeg voor IT-eye