<Manager pathname=""/>
to the DefaultContext will disable Tomcat's default behavior of saving the session upon shutdown.
UPDATE
lousy, this didn't work.
When I started this blog (2004) it was to document Gentoo linux experiences and *nix adventures. Then it turned into posts regarding software development challenges and other findings. These days I mostly tweet (rollinsruss) and my posts are infrequent.
<Manager pathname=""/>
package org.lds.sql;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.TimeZone;
import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.UserType;
import org.lds.env.utils.DateUtils;
/**
* Custom Hibernate type for precise UTC millisecond persistance and retrieval using a Timestamp.
* All values represent the given time from the Unix Epoch, 1 Jan 1970 00:00:00.000
* See http://en.wikipedia.org/wiki/Unix_epoch for more info.
* Credit: Rob @ "http://www.hibernate.org/100.html
*
*/
public class UtcTimestamp extends Timestamp implements UserType {
/**
* Gets the value of SQL_TYPES
*
* @return the value of SQL_TYPES
*/
public static int[] getSQL_TYPES() {
return UtcTimestamp.SQL_TYPES;
}
/**
* SQL type.
*/
private static final int[] SQL_TYPES = { Types.BIGINT };
/**
* Creates a newUtcTimestamp
instance at this moment.
*
*/
public UtcTimestamp(){
super(System.currentTimeMillis());
}
/**
* With the given milliseconds.
*
* @param utcMillis along
value
*/
public UtcTimestamp(long utcMillis){
super(utcMillis);
}
/**
* Make a copy of the Timestamp.
* @see UserType#deepCopy(java.lang.Object)
*/
public Object deepCopy(Object obj) throws HibernateException {
return (obj == null) ? null : new Timestamp(((Timestamp)obj).getTime());
}
/**
* Compare via {@link Object#equals(java.lang.Object)}.
* @see UserType#equals(java.lang.Object, java.lang.Object)
*/
public boolean equals(Object x, Object y) {
return (x == null) ? (y == null) : x.equals(y);
}
/**
* Timestamps are mutable.
* @see net.sf.hibernate.UserType#isMutable()
*/
public boolean isMutable() {
return true;
}
/**
* Return an instance of the Timestamp or null if no value is specified.
* @see net.sf.hibernate.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object)
*/
public Object nullSafeGet(ResultSet rs, String[] columns, Object owner)
throws HibernateException, SQLException {
long value = rs.getLong(columns[0]);
Timestamp timestamp;
if(rs.wasNull()) {
timestamp = null;
} else {
timestamp = new UtcTimestamp(value);
}
return timestamp;
}
/**
* Set an instance of the Timestamp into the database field.
* @see net.sf.hibernate.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object, int)
*/
public void nullSafeSet(PreparedStatement statement, Object value, int index)
throws HibernateException, SQLException {
if(value == null) {
statement.setNull(index, Types.BIGINT);
} else {
Timestamp timestamp = (Timestamp)value;
statement.setLong(index, timestamp.getTime());
}
}
/**
* Return the {@link Timestamp} class.
* @see net.sf.hibernate.UserType#returnedClass()
*/
public Class returnedClass() {
return org.lds.sql.UtcTimestamp.class;
}
/**
* Return the supported SQL types.
* @see net.sf.hibernate.UserType#sqlTypes()
*/
public int[] sqlTypes() {
return SQL_TYPES;
}
/**
* All dates return their value in GMT time.
*
* @return aString
value
*/
public String toString(){
SimpleDateFormat dateFormat = new SimpleDateFormat(DateUtils.DATE_FORMAT);
dateFormat.setTimeZone(DateUtils.GMT);
return dateFormat.format(this);
}
/**
* Obtain a UtcTimestamp from a Date.
*
* @param date ajava.util.Date
value
* @return anUtcTimestamp
value
*/
public static UtcTimestamp valueOf(java.util.Date date){
UtcTimestamp utcTimestamp = new UtcTimestamp(date.getTime());
return utcTimestamp;
}
}
-------------end Hibernate UserType-------------
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.TimeZone;
import java.sql.ResultSet;
public class TestOracleDate{
public static void main(String[] args){
SQLException exception = null;
Connection con = null;
String connectionString = "jdbc:oracle:thin:@testbox:imstest";
String user = "testuser";
String password = "testpassword";
String database = "testdb";
String uuid="c93d4654-40c2-11da";
String identifier="hoser date test";
String driverClassName="oracle.jdbc.driver.OracleDriver";
try{
Class.forName(driverClassName).newInstance();
}catch(Exception ex){ex.printStackTrace();}
try{
con = DriverManager.getConnection(connectionString,user,password);
String insertString = "INSERT INTO TEST_TABLE (cmn_rswd_identifier,cmn_rswd_statusid,cmn_rswd_mdate,cmn_rswd_cdate,cmn_rswd_uuid) VALUES ('"+identifier+"',1,?,?,'"+uuid+"')";
String deleteString = "DELETE FROM CMN_RESERVED_WORD where cmn_rswd_identifier='"+identifier+"'";
//insert = con.createStatement();
final PreparedStatement insert = con.prepareStatement(insertString);
final PreparedStatement delete = con.prepareStatement(deleteString);
System.out.println("executing: " + deleteString);
delete.executeUpdate();
System.out.println("executing: " + insertString);
TimeZone GMT = TimeZone.getTimeZone("GMT-00:00");
TimeZone MST = TimeZone.getTimeZone("MST7MDT");
System.out.println("First timestamp param, using :" + GMT.getID());
System.out.println("First timestamp param, using :" + MST.getID());
insert.setTimestamp(1,new Timestamp(System.currentTimeMillis()),Calendar.getInstance(GMT));
insert.setTimestamp(2,new Timestamp(System.currentTimeMillis()),Calendar.getInstance(MST));
insert.executeUpdate();
String queryString = "SELECT * FROM CMN_RESERVED_WORD where cmn_rswd_uuid='"+uuid+"'";
Statement query = con.createStatement();
ResultSet rs = query.executeQuery(queryString);
while(rs.next()){
//System.out.println(rs);
System.out.println("-----------------");
System.out.println("cmn_rswd_mdate (positional param 1) " + rs.getTimestamp("cmn_rswd_mdate"));
System.out.println("cmn_rswd_cdate (positional param 2) " + rs.getTimestamp("cmn_rswd_cdate"));
System.out.println("-----------------");
}
}
catch(SQLException ex){
ex.printStackTrace();
}
catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
finally{
try{
if(con != null) con.close();
}catch(Exception ex){ex.printStackTrace();}
}
}
}
public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException{
Timestamp timestamp;
if(value instanceof Timestamp){
timestamp = (Timestamp) value;
}
else{
timestamp = (Timestamp) new LocalizedTimestamp();
}
Calendar gmtCal = Calendar.getInstance(GMT);
//where GMT = TimeZone.getTimeZone("GMT-00:00");
st.setTimestamp(index, timestamp,gmtCal);
}
st.setTimestamp(index, timestamp,gmtCal);
;; gse-locate.el
;; Summary: Emacs front-end to 'locate'.
;; Author: Scott Evans
;; Home: http://www.antisleep.com/elisp
;; Time-stamp: <2004.12.22 23:20:59 gse>
;;
;; Commentary:
;; A handy Emacs interface to 'locate'. Having this interface
;; around is great -- it gives you a one-step way to get around a
;; filesystem, and spend a lot less time navigating directory trees.
;;
;; I lifted a lot of the major mode code from Steve Molitor's
;; rec-files.el (or at least from my modified version).
;;
;; I spend most of my time in Windows now, and porting slocate to
;; Cygwin didn't go real well so I wrote my own simple 'locate'
;; replacement for Cygwin (see http://www.antisleep.com/software/loc).
;;
;; Written for/using XEmacs on Windows. Changes are welcome.
;;
;; Installation:
;; (require 'gse-locate)
;; and if you like:
;; (global-set-key '[f10] 'gse-locate)
;;
;;---------------------------------------------------------------------------
;; Change Log
;; ----------
;; 2005.10.11 Modified to use locate and work in Linux -RR
;; 2004.01.18 Actually, -c is bad.
;; 2004.01.18 Use loc -c, take out backslash replacing.
;; 2004.01.18 Add gse-locate-execute-file.
;; 2004.01.18 Change to major mode with keybindings. Add some customization.
;; 2002.04.08 Created.
;;---------------------------------------------------------------------------
;; Unix (and native Cygwin) users can probably just set this
;; to "locate".
(defvar gse-locate-command "locate"
"*\"locate\" shell command. This will be used as an argument to
shell-command, with the search pattern concatenated to it.
This specified program should take a string (or regular expression, if
you intend to use them) as a parameter, and return a list of files to
stdout, one per line.")
(defvar gse-locate-hooks nil
"List of functions to call when entering gse-locate-mode")
(defvar gse-locate-regexp-list
(list "\\.elc"
"\\.class"
"/CVS"
"/target/classes"
"#"
"~"
".cvsignore"
)
"A list of regular expressions that match \"uninteresting\" filenames.
These will be stripped from the locate list before it is displayed.")
;;---------------------------------------------------------------------------
(defvar gse-locate-prev-wconfig nil)
(defvar gse-locate-buf nil)
(defvar gse-locate-history nil)
;;---------------------------------------------------------------------------
(defun gse-locate (pattern)
"Lightweight interface to locate. PATTERN is the string or regexp
that will be passed to locate (see gse-locate-command).
If exactly one file matches, it will be opened. Otherwise a list
of files will be presented (see gse-locate-mode)."
(interactive
(list
(read-from-minibuffer "locate pattern: " nil nil nil
'gse-locate-history)))
(set-buffer (get-buffer-create "*locate*"))
(setq buffer-read-only nil)
(erase-buffer)
(shell-command (concat gse-locate-command " -d /ext/ext.files.db " pattern) t)
;; Clean up stuff we don't want to see.
(let* ((i 0))
(while (< i (length gse-locate-regexp-list))
(let ((cur-regexp (nth i gse-locate-regexp-list)))
(goto-char (point-min))
(delete-matching-lines cur-regexp))
(setq i (+ i 1))))
(let ((number-matches (count-lines (point-min) (point-max))))
(cond
((= number-matches 0)
(message "No matches."))
((= number-matches 1)
;; One match. Open the file.
(find-file (buffer-substring
(point-min)
(progn
(goto-char (point-min))
(end-of-line)
(point))))
)
(t
;; Multiple matches.
(setq gse-locate-prev-wconfig (current-window-configuration))
(goto-char (point-min))
(switch-to-buffer (current-buffer))
(setq gse-locate-buf (current-buffer))
(gse-locate-mode))
))
)
;;---------------------------------------------------------------------------
(defvar gse-locate-mode-map nil
"Keymap for gse-locate-mode.")
(if gse-locate-mode-map
()
(setq gse-locate-mode-map (make-sparse-keymap))
(define-key gse-locate-mode-map "v" 'gse-locate-select-this-window)
(define-key gse-locate-mode-map "\C-m" 'gse-locate-select-this-window)
(define-key gse-locate-mode-map "o" 'gse-locate-select-other-window)
(define-key gse-locate-mode-map " " 'next-line)
(define-key gse-locate-mode-map "n" 'next-line)
(define-key gse-locate-mode-map "p" 'previous-line)
(define-key gse-locate-mode-map "q" 'gse-locate-quit)
(define-key gse-locate-mode-map "1" 'gse-locate-select-1-window)
(define-key gse-locate-mode-map "?" 'describe-mode)
(when (functionp 'mswindows-shell-execute)
(define-key gse-locate-mode-map "X" 'gse-locate-execute-file))
)
;;---------------------------------------------------------------------------
(defun gse-locate-mode ()
"Lightweight major mode to select a file from \"locate\" output.
Special keys:
\\{gse-locate-mode-map}"
(interactive)
(kill-all-local-variables)
(setq major-mode 'gse-locate-mode)
(setq mode-name "Locate")
(use-local-map gse-locate-mode-map)
(setq truncate-lines t)
(setq buffer-read-only t)
(run-hooks 'gse-locate-hooks))
;;---------------------------------------------------------------------------
(defun gse-locate-current-file ()
(save-excursion
(beginning-of-line)
(buffer-substring
(point)
(search-forward-regexp "$"))))
;;---------------------------------------------------------------------------
(defun gse-locate-find-file (file-name &optional find-function)
"Open file if it exists."
(when (not find-function)
(setq find-function 'find-file))
(if (file-exists-p file-name)
(funcall find-function file-name)
(error "%s%s%s" "File '" file-name "' does not exist!")))
;;---------------------------------------------------------------------------
(defun gse-locate-select-this-window ()
"Select this line's file in this window."
(interactive)
(gse-locate-find-file (gse-locate-current-file)))
;;---------------------------------------------------------------------------
(defun gse-locate-select-other-window ()
"Select this line's file in this window."
(interactive)
(gse-locate-find-file (gse-locate-current-file) 'find-file-other-window))
;;---------------------------------------------------------------------------
(defun gse-locate-select-1-window ()
"Select this line's buffer, alone, in full frame."
(interactive)
(gse-locate-find-file (gse-locate-current-file))
(bury-buffer (other-buffer))
(delete-other-windows))
;;---------------------------------------------------------------------------
(defun gse-locate-quit ()
"Close gse-locate buffer."
(interactive)
(let ((buf (get-buffer gse-locate-buf)))
(and buf (bury-buffer buf)))
(set-window-configuration gse-locate-prev-wconfig))
;;---------------------------------------------------------------------------
(defun gse-locate-execute-file ()
"Launch this line's file. Currently windows-only (and probably
XEmacs-only)."
(interactive)
(let ((file-name (gse-locate-current-file)))
(if (file-exists-p file-name)
(mswindows-shell-execute nil file-name)
(error "%s%s%s" "File '" file-name "' does not exist!"))))
;;---------------------------------------------------------------------------
(provide 'gse-locate)
Location
---------
id type name
-- ---- ----
1 country USA
2 country Canada
3 country UK
4 level1 Alabama
5 level1 Manitoba
6 level1 Southhampton
7 level1 Puerto Rico
8 level1 District of Columbia
9 country Mexico
LocationType
------------
id type
-- ----
1 country
2 level1
3 level2
4 level3
5 level4
Subordinate Types
-----------------
id type
-- ----
1 state
2 province
3 territory
4 county
5 district
6 commonwealth
Subordinate Equivalence
-----------------------
id locationId locationType defaultBit subordinateType defaultLocalizedStringId
-- ---------- ------------ ---------- --------------- ------------------------
1 1 level1 1 state ->"State"
2 1 level1 0 district ->"District"
3 1 level1 0 commonwealth ->"Commonwealth"
4 2 level1 1 province ->"Province"
5 2 level1 0 territory ->"Territory"
6 3 level1 1 county ->"County"
7 3 level1 0 posttown ->"Post Town"
8 1 level2 1 county ->"County"
9 1 level3 1 city ->"City"
10 2 level3 1 city ->"City"
11 3 level4 1 city ->"City"
12 9 level1 1 state ->"Estado"
13 9 level3 1 city ->"Ciudad"
#!/usr/bin/python
import sys, os
BLOCK_CSS_FILE="/home/russ/.opera/adblock.css"
# read current CSS
try:
cssFile=open(BLOCK_CSS_FILE,"r")
except:
cssStr="\n"
else:
cssStr=cssFile.read()
cssFile.close()
# write new CSS
cssFile=open(BLOCK_CSS_FILE,"w")
if len(sys.argv)==2:
cssFile.writelines('img[src="'+sys.argv[1]+'"]')
elif len(sys.argv)==3:
cssFile.writelines(sys.argv[2]+'"'+sys.argv[1]+'"]')
elif len(sys.argv)==5:
cssFile.writelines(sys.argv[2]+'['+sys.argv[3]+sys.argv[4]+'"'+sys.argv[1]+'"]')
elif len(sys.argv)==4:
cssFile.writelines(sys.argv[2]+'['+sys.argv[3]+'='+'"'+sys.argv[1]+'"]')
if (cssStr=="\n")|(cssStr==""):
cssFile.writelines('\n{display:none !important;}')
else:
cssFile.writelines(',\n')
cssFile.writelines(cssStr)
cssFile.close()
function hideOrShowPop(id){
var popin= document.getElementById(id);
var idToFetch = id + "Active";
var popinActive = document.getElementById(idToFetch);
if(popin.style.visibility=="hidden"){
handlePop(id);
}
else{
popin.style.visibility="hidden";
var clone = document.getElementById("clone"+id);
if(clone != null){
clone.style.visibility="hidden";
clone.removeNode(true);
}
}
}
function handlePop(id){
var popinDiv = document.getElementById(id);
var anchorNode = document.getElementById(id+"Anchor");
popinDiv.style.visibility="visible";
popinDiv.style.display="block";
var cloneDiv = popinDiv.cloneNode(false);
//this is for figuring out how to put the popin ANYWHERE on the screen, currently not working
//var anchorPoint = getLocationPoint(anchorNode);
//popinDiv.style.top = anchorPoint.y;
//popinDiv.style.left = anchorPoint.x;
var width = parseInt(popinDiv.style.width);
var height = parseInt(popinDiv.style.height);
cloneDiv.id = "clone" + id;
try{
cloneDiv.zIndex="3";
cloneDiv.innerHTML = "";
popinDiv.parentNode.appendChild(cloneDiv);
popinDiv.parentNode.appendChild(popinDiv);
} catch(e){
alert("Popin exception caused by id: " + idToFetch + " or " + id);
if(ie)
alert(e.description);
else
alert(e);
}
}
/**
* Simple interface declaring required properties for a protected component to (en/dis)abling a component render and its disable(d) state.
*
*/
public interface IProtectedComponent{
/**
* Flag for allowing component render.
*
* @return aBoolean
value
*/
public boolean getAllowRender();
}
/**
* A protected PropertySelection component only rendered if allowedRender is true.
*
*/
public abstract class ProtectedPropertySelection extends PropertySelection implements IProtectedComponent{
protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle){
if(getAllowRender() == true){
super.renderComponent(writer, cycle);
}
}
for(Iterator componentIter = components.keySet().iterator(); componentIter.hasNext();){
String componentId = (String)componentIter.next();
IComponent component = getComponent(componentId);
IBinding elementId = component.getBinding(ELEMENT_IDENTIFIER);
if(IProtectedComponent.class.isAssignableFrom(component.getClass())){
IProtectedComponent protectedComponent = (IProtectedComponent)component;
if(elementId != null){
//resolve rights to component
//boolean updateOrExecute = canAccess(elementId, CRUDAction.UPDATE);
boolean updateOrExecute = true;
if(! updateOrExecute){
//boolean canRead = canAccess(elementId, CRUDAction.READ);
boolean canRead = false;
if(!canRead){
//do not render the component
component.setProperty(ELEMENT_ALLOW_RENDER, "false");
component.setProperty(ELEMENT_DISABLE, Boolean.TRUE);
}
else{
//Render the component, but make it disabled
component.setProperty(ELEMENT_ALLOW_RENDER, "true");
component.setProperty(ELEMENT_DISABLE, Boolean.TRUE);
}
}
else{
//Render the component normally
component.setProperty(ELEMENT_ALLOW_RENDER, Boolean.TRUE);
component.setProperty(ELEMENT_DISABLE, Boolean.FALSE);
}
}
}
}
http://oit.uta.edu/cs/network/vpn/linux/vpn_linux.html
copy to /usr/portage/distfiles
emerge cisco-vpnclient-3des
copy .pcf to /etc/opt/cisco-vpnclient/Profiles
then:
vpnclient connect <profile> user <username>
#!/bin/ruby
require 'net/http'
require 'date'
proxy_addr=ENV['http_proxy'].split(/:/)[1].split('/')[2]
proxy_port=80
#handle the case when the proxy_addr is null
date=nil
while(date == nil)
#fetch date
begin
Net::HTTP::Proxy(proxy_addr,proxy_port).start('www.google.com') {|http|
http.read_timeout = 1
http.open_timeout = 1
p = http.request_head('/')
puts p['content-type']
puts p['date']
date = p['date']
}
rescue
puts "is net connected?"
end
#set date
if(date != nil)
puts date
datetime = DateTime.parse(date)
puts datetime
mst = (datetime.new_offset(-0.25) )
#will need to determine if this is during daylight savings or not and adjust fraction accordingly
puts mst
#parse and format for posix
dates = mst.to_s.split('-')
times = dates.to_s.split(":")
finalDate = dates[1]
finalDate += dates[2][0,2]
finalDate += times[0][9,11]
finalDate += times[1]
finalDate += dates[0]
puts finalDate
`date #{finalDate}`
end
sleep(1)
end
this._dateValue = new java.sql.Timestamp(setDateToUtcHourFromTimeZone((java.util.Date)dateValue).getTime());
return new java.sql.Timestamp(getTimeZoneDate((java.util.Date)_dateValue).getTime());
One important aspect of internationalizing an application may be that of date handling. That is, how will the application read and write dates. Should the scope of the project be limited to viewing only, then the point is moot. However, if the need arises that these dates drive some activity or event then "normalizing" the dates should be heavily considered. Choosing an international standard (UTC) and conforming date entries allows date-specific operations and triggers to be precisely executed.
Consider the following example. An organization has dates that drive specific events or triggers. A monitor/daemon is run that periodically evaluates these dates and fires the appropriate action. Presume the monitor awakes at midnight MST. Then the scenario in which an organization in New Zealand depends on the date of 24 July to trigger some action will then be delayed for 33 hours--and the people/systems dependent upon those date-driven operations will be hosed. Here's how:
Alternatively, if the effective date is stored as a timestamp (even though only the "date" is really relevant considering the requirement to run operations based on "that day") and the monitor runs hourly the problem is solved. The New Zealand "date" of 00:00 July 24 is really 12:00 July 23 UTC. If the monitor then only evaluates per-hour dates, the application can then address international needs required by the effective date handling. Thus, all triggers and date dependent operations will only ever be delayed by an hour and ensuring that at midnight for any given timezone the correct operations for that timezone's day will be executed.
So that's 17370 files, written to disk in .598 seconds! Beautiful! File is ~1.5 meg. How about how fast Java can process the file?
time ruby finderPrinter.rb
17370
real 0m0.598s
user 0m0.427s
sys 0m0.164s
java -classpath . JReader
17370
took 169 milliseconds
Looked for 'a' in all files: 17258 169 milliseconds
public void readFile(String fileName) throws FileNotFoundException{
//see how long it takes to read in the file
//iterate the list
//then search through the list for a given name
long timeStarted = System.currentTimeMillis();
BufferedReader reader = new BufferedReader(new FileReader(fileName));
String currentLine = null;
try{
while(reader.ready()){
currentLine = reader.readLine();
fileList.add(currentLine);
}
reader.close();
}
catch(IOException ex){
ex.printStackTrace();
}
for(Iterator fileIter = fileList.iterator();fileIter.hasNext();){
String filePath = (String)fileIter.next();
if(filePath.indexOf("a") > 0){
resultList.add(filePath);
}
}
System.out.println(fileList.size());
System.out.println("took " + ((System.currentTimeMillis() - timeStarted)) + " milliseconds");
System.out.println("Looked for 'a' in all files: " + resultList.size() + " " + ((System.currentTimeMillis() - timeStarted)) + "milliseconds");
}
Finding files
found
17373
done writing file, now kicking off java process
17373
took 143 milliseconds
Looked for 'a' in all files: 17260 143milliseconds
real 0m0.895s
user 0m0.630s
sys 0m0.211s
time python test.py
18184
--------------------
real 0m0.649s
user 0m0.465s
sys 0m0.182s
time ruby test.rb
19948
--------------------
real 0m0.598s
user 0m0.383s
sys 0m0.195s
--------------------
java -classpath . SimpleTester
19946 took 37 seconds
http://www.gloegl.de/17.html
----------------------------------
If you are working with object-orientated programming and relational
databases, you will surely have noticed that these are two different
paradigms. The relational model deals with relations,tuples and sets -
it is very mathematical by nature. The object-orientated paradigm
however deals with objects, their atributes and associations to each
other. As soon as you want to make objects persistent using a
relational database you will notice: There is a rift between these two
paradigms, the so called object-relational gap. A object-relational
mapper (or ORM as a shorthand) will help you bridge that gap.
Well, how does this gap manifest? If you are passing objects around in
your application and sometimes reach the point where you want to
persist them, you will typically open a JDBC connection, create an SQL
statement and copy all your property values over to the
PreparedStatement or into the SQL string you are building. This may be
easy for a small value object - but consider this for an object with
many properties. Thats not the only problem. What about associations?
If your Cat object you want to store has a List of kittens contained?
Do you store them too? Automatically? Manually? What about foreign key
constraints?
The same applies for loading - let's assume you load a Cat object from
the database and it has a collection of kittens. Do you load the
kittens too? Not load them yet but later? If you load the kittens,
consider each of the kitten object has an association to yet more
objects. In this case, such eager loading may easily load your
complete object tree. Not loading the kittens is however not really
better however - you will need explicit reloading later if you
probably want to access the kittens.
As you can see, the object-relational gap quickly becomes very wide if
you have large object models. And there are a lot more things to
consider like lazy loading, circular references, caching, etc. In
fact, there have been studies that showed that about 35% of an
application code was produced by the mapping between application data
and the datastore.
So what can an ORM do for you? A ORM basically intends to takes most
of that burden of your shoulder. With a good ORM, you have to define
the way you map your classes to tables once - which property maps to
which column, which class to which table, etc
http://www.db40.com
http://www.onjava.com/pub/a/onjava/2004/12/01/db4o.html
http://www.theserverside.com/news/thread.tss?thread_id=30353
Links:
http://java.sys-con.com/read/46050.htm
http://howardlewisship.com/blog/2004_01_01_archive.html
http://www-106.ibm.com/developerworks/library/j-jsf1/
http://howardlewisship.com/blog/2005/02/tapestry-jsf-and-fud.html
"...Erik Hatcher likes to "provoke" JSF-ers, such as David Geary, to
duplicate the Table component. The Table includes links for sorting
and paging through long contents ... these links just work, without
any configuration in the application. This is the Tapestry way -- drop
it in and let it work. JSF's approach is primarily a view component
and apparently can't duplicate this."
http://www.oreillynet.com/cs/user/view/cs_msg/48307
"Tapestry has literally taken a project that was stalled in
development hell for almost a year and finished it, rebuilt from the
groun up, in 3 months. We built it from the ground up using Tapestry.
We added things as we learned, but it was all very intuitive. First,
simple forms for customer input and simple screens for reporting."
Known implementations. Interestingly these all have their drawbacks.
Oracle's is an "early access edition", MyFaces is somewhat
proprietary, "The MyFaces version of Tiles Support requires the
MyFaces JSF implementation. It will not work with the Sun RI or any
other JSF implementation." And AjaxFaces looks the most intriguing,
but it's a commercial solution!
http://www.ajaxfaces.com/
http://www.oracle.com/technology/products/jdev/htdocs/partners/addins/exchange/jsf/index.html
http://myfaces.apache.org/components/overview.html
---------
Think I need to spend a night hosing around with JSF to evaluate it.