Korean
Project site
Downloads
Reference site: uEngine
  
       SourceForge.net Logo

metaworks

A simple Database / GUI framework for JAVA

Author: Jinyoung jang    Status: Developed from Nov, 2000 and hybernated now

metaworks is a simple object-oriented application framework that simplifies the repeating tasks in direct coding using JDBC and SQL statements. If you have progammed at least once, you sould understand the horrible nightmare of the tasks such as matching column names, type validation, string manipulation for SQL statments, error processing.. etc. metaworks separates the low-level programming such as SQL scripting, validation, GUI programming from your application codes so that you can use a high abstracted language to communicate with your requirments.

Services

metaworks provides following services

  • Encapsulate the DB row, which is a subclass of Hashtable to be selected, saved, modified, and deleted
  • Automatically generates the UI (Swing dialogs and JPanel) for the database manipulation
  • Provides a consistent pattern of input and validation component interface (Inputter / Validator)
  • Dynamically generates default table by loading the metadata from the database
  • Provides 'Query Form' to easily generate the UI form to search

Objects

metaworks is composed of several interacting objects. Since the objects are intended to be easily understood to the database programmer, the framework mapped these objects into corresponding database objects.

[Table. metaworks objects vs Database Mapping]
class name
Database Mapping
main methods
Database Mapping
Table Table load, find select
Record Record (tuple) save, update, delete insert, update, delete
Field Data get, put select <fieldname>, update set <field>
FieldDescriptor Field Declaration get, put desc <table>
FieldAttribute Field attributes (size, default...)
Inputter Input policy
Validator Check Constraint isValid check (...)

Declaration of Table

Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1526:iman5", "usr", "pwd");

// You can remind the 'create' statement of SQL
Table px_part_newparts = new Table(
	"px_part_newparts",     //  table¸í
				//  column              title           type            iskey
	new FieldDescriptor[]{
		new FieldDescriptor("SEQNO",            "Sequence",         Types.INTEGER,  true),
		new FieldDescriptor("DESCRIPTION",      "Comment"),
		new FieldDescriptor("DEVELOPMENTDATE",  "Due Date To Develop",     Types.DATE),
		new FieldDescriptor("DIVISION",         "Division")
	},
	con			// 'Connection' object of JDBC
);

Manipulating Records - selection, insertion, modification, deletion

selection of record

// selects records that sequence = 1000 from the table declared above
Record [] rec = px_part_newparts.find("SEQNO=10000");

// if found any, print it
if(rec.length> 0){
	System.out.println("DESCRIPTION = " + rec[0].get("DESCRIPTION"));
	System.out.println("SEQNO = "+rec[0].get("SEQNO"));
}

modification

	rec[0].put("DESCRIPTION", "value to change");
	rec[0].update();

deletion

	rec[0].delete();

creating new record

Record newRec = new Record(px_part_newparts);

newRec.put("SEQNO", "5555");
newRec.put("DESCRIPTION", "description of the new record");
newRec.put("DIVISION", "CNZ");

newRec.save();

Automatic UI generation - using InputForm

user can automatically generate a input form panel (JPanel of swing) which can take a row data of given table.

Example 1. Creating a form

public static void main(String args[]) throws Exception{


        Class.forName("oracle.jdbc.driver.OracleDriver");

        Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1526:iman5", "usr", "pwd");
        
	// You can remind the 'create' statement of SQL
	Table px_part_newparts = new Table(
		"px_part_newparts",     //  table¸í
					//  column              title           type            iskey
		new FieldDescriptor[]{
			new FieldDescriptor("SEQNO",            "Sequence",         Types.INTEGER,  true),
			new FieldDescriptor("DESCRIPTION",      "Comment"),
			new FieldDescriptor("DEVELOPMENTDATE",  "Due Date To Develop",     Types.DATE),
			new FieldDescriptor("DIVISION",         "Division")
		},
		con			// 'Connection' object of JDBC
	);
	
        Record [] rec = px_part_newparts.find("seqno=10000");
        
        if(rec.length> 0){
                System.out.println("description = " + rec[0].get("description"));
                System.out.println("seqno = "+rec[0].get("seqno"));
                
        }                       
                
        final InputForm newForm = new InputForm(px_part_newparts, "10000");
        
        JFrame frame = new JFrame("test");
        
        frame.getContentPane().setLayout(new BorderLayout());
        frame.getContentPane().add("Center", newForm);  // <<<<<<<<<<<<<<<
        
        JButton saveBtn = new JButton("Save it!");
        frame.getContentPane().add("South", saveBtn);   // <<<<<<<<<<<<<<<

        saveBtn.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent e){
                        try{
                                newForm.getRecord().save();
                        }catch(Exception ex){}
                }
        });
        

        frame.pack();
        frame.setVisible(true);
}       
 

Example 2. Creating custom inputform

InputForm testForm2 = new InputForm(
        new Table("test2",
                new FieldDescriptor[]{
                        new FieldDescriptor("column1"),
                        new FieldDescriptor("column2"),
                        new FieldDescriptor("column3")
                }
        )
){
        public void onSaveOK(Record rec, JDialog dialog){
                MessageBox.post("'"+ rec.get("column1") +"' A record has been saved", "saved", 1);
        }
        
        public void onSaveFailed(Exception e, JDialog dialog){
                MessageBox.post("Failed to save.\n The error statement =" + e.getMessage(), "failed", 1);
        }
};
testForm2.postInputDialog(frame);

 

Consistent input policy - Inputter component

Inputter adapts the diverse swing controls to be uniformly maintainable and value-accessible with metaworks presentation (GUI) components.
[Table. Default Inputters provided]

Inputter name description default supporting type
TextInput JTextField; Normally used for simple string Types.VARCHAR
NumberInput JTextField allowed only numbers and right-aligned Types.INTEGER
DateInput A calendar control is provided Types.DATE
SelectInput A JComboBox that has several options is provided ¾ø½¿
RadioInput A RadioButton that has several options is provided ¾ø½¿
ReferenceInput A JTable that has the records of referencing table is provided¾ø½¿

Example

The inputter is placed in the 6th parameter of the constructor of class 'FieldDescriptor'.
new FieldDescriptor("MODEL",		"Model",	12,	false,		
	new FieldAttribute[]{
		new FieldAttribute("default", new String("B")),
	},
	new SelectInput(new String[]{"", "A", "B", "C"})	//<<<<<<<<<<
),

new FieldDescriptor("PRICE",	"Price",	2,	false,
	null,
	new NumberInput()  //<<<<<<<<<<
),

...
After declaring like above, you can create a Form panel using class 'InputForm'.
	InputForm inputForm = new InputForm(table);
	someFrame.add(inputForm);
	someFrame.setVisible(true);
	...

Creating a custom Inputter

You can create custom Inputter by extending the class 'AbstractComponentInputter' that asks to you of several interaction logics.
public class AbstractComponentInputter{

	// When InputForm request the value
	abstract public Object getValue();
		
	// When InputForm gives a value (specifically when a update form or push a default value)
	abstract public void setValue(Object obj);
	
	// When the InputForm needs a new component
	abstract public Component getNewComponent();
}
Following is the source code of DateInput
package com.cwpdm.util.db.inputter;

import java.awt.Component;
import javax.swing.*;

import *;
import java.util.Date;
import java.text.*;


public class DateInput extends AbstractComponentInputter{

	public DateInput(){
		super();
	}
	
/////////// implemetations //////////////

	public Object getValue(){
		Date srcDate = ((DateButton)getComponent()).getDate();
		
		if(srcDate==null) return null;
		
		Date rtnDate = new Date(srcDate.getTime()){
			public String toString(){
			       	SimpleDateFormat displayFormatter = new SimpleDateFormat("yyyy-MM-dd");
				String making = displayFormatter.format(this);
						
				return making;
			}			
		};
		
		return rtnDate;

	}
	
	public void setValue(Object obj){
		if(obj instanceof Date && obj!=null)
			((DateButton)getComponent()).setDate((Date)obj);
	}

	public Component getNewComponent(){
		DateButton dateButton = new DateButton();
		dateButton.setDisplayFormat("yyyy-MM-dd");
		
		return dateButton;
	}
	
}

Specializing Inputter

Following example requires that the Level No accepts only numbers and point (.). The code will extend very small part of the inputter 'TextInput' to provide this functionality so that this example shows how the instance specializing enhances the readability and efficiency.

	...
	new FieldDescriptor("LEVELNO",		"LEVEL",	12,	false, null,

		// level no allows only numbers and point (.)
		new TextInput(){
			public Component getNewComponent(){
				CodeField codeField = new CodeField(10);
			
				codeField.setAllowAlphabet(false);
				codeField.setAllowSpace(false);
				codeField.setAllowingCharset(".");
		
				return codeField;
			}
		}
	)
	...

Consistence validation policy - component Validator

This component will be used when validation during processing database. A composition set of validator may cover almost all of desired validation rule. With this validator, the InputForm will automatically process the error messaging.

Default Validators

Validator name description default supported type
NotNullValid Check whether the value is null (similar with "not null" constraint in DB) none
NumberValid Check whether the value is valid numberTypes.INTEGER

Usage

You just only put the validator into the 7th parameter of FieldDescriptor.

Customizing validator

The interaction of AbstractValidator

        1. when the user classes (like InputForm) are about to check the value, they invoke the method 'isValid'
        2. if wrong, validator throws a metaworks error with the message from the method 'getErrorMessage()'.
 

Implementation Example.

new InputForm(
        new Table(
                "validator test",
                new FieldDescriptor[]{
                        new FieldDescriptor("userid", "User ID", 0, true, null, null, 
                                new Validator[]{
                                        // check the length
                                        new AbstractValidator(){
                                                public boolean isValid(Object data){
                                                        return ((String)data).length() > 10;
                                                }
                                                
                                                public String getErrorMessage(){
                                                        return 
                                                           "Userid should be within 10 characters";
                                                }
                                        },
                                        // check the space
                                        new AbstractValidator(){
                                                public boolean isValid(Object data){
                                                        return ((String)data).indexOf(" ") == -1;
                                                }
                                                
                                                public String getErrorMessage(){
                                                        return "Space is not allowed";
                                                }
                                        }
                                }
                        )
                }
        )
).postInputDialog(null);
 

FieldAttribute

FieldAttribute provides information for the user classes, namely, this enables the metadata to be maintained in the same place of table declaration User can extend their FieldAttribute upto their requirements. First add a FieldAttribute, and just use the information in your user classes.

  • Providing several attributes of FieldDescriptor
  • Providing reference information for the class Table to manipulate SQL statements
  • Providing reference information for the calss Inputter

Example)

Table px_part_newparts = new Table(
        "px_part_newparts",     //  table name
                                //  column              title           type            iskey
        new FieldDescriptor[]{
                new FieldDescriptor("NAME",             "Name",         Types.VARCHAR,  true,
                        new FieldAttribute[]{
                                new FieldAttribute("default", new String('pongsor')),	//<<<<<<<<<<<
                                new FieldAttribute("size", new Integer(10))  //<<<<<<<<<
                        },
                ),
                new FieldDescriptor("DATE",             "Birthday",         Types.DATE,  false,
                        new FieldAttribute[]{
                                new FieldAttribute("source", new String('sysdate')),	//<<<<<<<<<<
                        }
                )
        }
);
 

Reserved Attibute Keys

key name Description Usage
default The default value when UI components initialize an insert form new FieldAttribute("default", "MALE"))
size The maximum size of value that you wish to allow new FieldAttribute("size", new Integer(10))
hidden If you add this attribute, the field won't be visible.new FieldAttribute("hidden", "test")
mandatory This means the field is mandatory field. UI components will force users to provide this information.new FieldAttribute("mandatory", new Boolean(true))
source This will provide a fragment of SQL expression for the class Table to direcly make the SQL by the fieldAttribute's value.new FieldAttribute("source", "sysdate") or new FieldAttribute("source", "sequenceA.nextVal")
dontcare This field will not be influenced in any effect. You can use this attribute when you need a redunduncy field for tag information new FieldAttribute("dontcare", new Boolean(true))

Note: You should use only Object value not primitive types. For example, when you need to provide a number, use 'new Integer(value)'.

Highly applied examples

A Table which updates if there row exists and insert if not

	new Table(...){
		public void save(Record rec) throws Exception{
			try{
				rec.update();
			}catch(Exception e){
				super.save(rec);
			}
		}
	}

metaworks can be used only for GUI generation

Even if you need only a dialog to the users, metaworks can provide a language for making GUI in a highly abstracted way.

...	
private class ConfigTable extends Table{

	ConfigTable(){
		super(
			"Table Setting",
			new FieldDescriptor[]{
				new FieldDescriptor("connStr"),
				new FieldDescriptor("uid"),
				new FieldDescriptor("pwd")
			}
		);
	}

	public void save(Record rec) throws Exception{
		setConnection(""+get("connStr"), ""+get("uid"), ""+get("pwd"));
	}
						
	public void update(Record rec) throws Exception{
		save(rec);
	}
}

....

new InputForm(new ConfigTable()){
	public void onSaveOK(Record newConfig){
		MessageBox.post("Configuration completed", "completed", 1);
	}
}.postInputDialog(null, "Confirm", "Modify");
...	
  

Copyright © 2003-2004 Jinyoung Jang, contact at pongsor@users.sourceforge.net