31 July 2005

Why I hate going to Funan IT Mall

Yesterday, I went to Funan IT Mall and my intention is to just look for this book called Java Puzzlers, I already know where to look at it's called The Computer Book Centre. But before I went there, a lot of distractions has come my way. Now I have changed my dream developer laptop from Fujitsu E8020 to Toshiba Tecra M3. So I ticked it to my To-Buy List. Although the review about this product is not-so-good since it's just about all those relative things like speed, lack of multimedia buttons, lack of anti-asthma-inhaler and lack of other girly stuff. My point is not about it, it's about development. When I saw it, it already looks worth the price, Toshiba's reputation on TFTs is unbeatable, they have the best screen displays ever. Put it side by side with ThinkPad, Vaio(all with dedicated VRAMs) or what have you, the M3 stands out. Of course since I am an nVidia fan, that's another thing that attracts to this machine, it has an nVidia GeForce 6600 thingy in it. As of this writing, it's priced at SGD$3,299. Not bad. Now where's my credit card?

That's not the point of me being in there in the first place. So I walked with some few paces. Store after store seems to have a life of its own uttering in my ears "M3...M3...M3". Finally, I am heading to where I want to go, The Computer Book Centre. Upon arriving, there's a bunch of books on sale, tempting. O'Reilly has their SWT Developer's Notebook(not the laptop ok!) series at SGD$20 and O'Reilly's Sping Developer's Notebook at $47(?). The O'Reilly Notebook series are another interesting series aside from the Head First series because the book looks like a college math notebook where sample codes has written on it. Again, that's not what I am looking for. I headed to the Java Section there are books of interests about JDO, another JCA, JavaSpaces/Jini. I sat on the floor to scour the bottom, nothing. So I went to the Publishers section then to the Addison-Wesley shelf and...NOTHING! I asked the sales clerk if there's a Java Puzzlers and said that book is still to arrive and asked if I want to advance my order, I refused. Not to put to waste the efforts of going there, I went back to the A-W shelf, now there are three books of interests I am looking at; "Open Source Licensing", "Succeeding with Open Source" and this. I opened the last book and the page that pop on me is p.213 and I quote:

"...Let's say you have a module of legacy code that's in a real mess, and you want to rewrite it rather than keep trying to live with it. You have to involve your boss because it will require significant investment resources.

You could present this choice to your boss:


  1. Do nothing new, keep fixing bugs as they appear.

  2. Total rewrite.



Your boss may choose option 1 outright..."


And I keep on reading the whole page. Damnit! I am sold. I am buying this book now! That's SGD$55 by the way.

29 July 2005

Bug on Acegi's "debug.jsp" Contact example

I notice from the debug.jsp code of Acegi's Contacts sample application that this code snippet:



<%@ page import="net.sf.acegisecurity.context.SecurityContextHolder" %>
<%@ page import="net.sf.acegisecurity.Authentication" %>
<%@ page import="net.sf.acegisecurity.GrantedAuthority" %>
<%@ page import="net.sf.acegisecurity.adapters.AuthByAdapter" %>

<%
Authentication auth = SecurityContextHolder.getAuthentication();
if (auth != null) { %>
Authentication object is of type: <%= auth.getClass().getName() %>


Authentication object as a String: <%= auth.toString() %>




Is wrong, there is no such thing as getAuthentication() within the SecurityContextHolder, it has to be fixed with something like this:


<%@ page import="net.sf.acegisecurity.context.SecurityContextHolder" %>
<%@ page import="net.sf.acegisecurity.context.SecurityContext" %>
<%@ page import="net.sf.acegisecurity.Authentication" %>
<%@ page import="net.sf.acegisecurity.GrantedAuthority" %>
<%@ page import="net.sf.acegisecurity.adapters.AuthByAdapter" %>

<%
SecurityContext securityContext =
SecurityContextHolder.getContext();
Authentication auth =
securityContext.getAuthentication();
if (auth != null) { %>
Authentication object is of type: <%= auth.getClass().getName() %>



Authentication object as a String: <%= auth.toString() %>





No wonder the Contacts sample with every instructions followed can't work. And this file has been sleeping in the CVS for months. Calling Ben Alex, yoohoo!

28 July 2005

Dude, it's called Java Job Interview

I pity the owner or stakeholders of companies who hires god-like asshats in their Software Engineering section. Those uber-coder-turned-CTO or whatever who doesn't know how to pick their own in just 3 hours or less. These high-IQ individuals tend to overlook EQs, which effectively push them downwards to the intellectual echelon.

For technical jobs especially Java-related ones, any type of on-the-spot exam barely proves anything. Whether it's online or written and be subjected to batteries of technical interviews if the candidates happen to pass their so-high-standard tests. I observed that these kind of tests are simply more of intimidation contests rather than getting the right person for the job. These techniques are top time-wasters and outdated, it was formulated by men with fragile egos to protect. They will say these are standard company procedures, WELL, FUCK YOU! Some of it was written by morons who has nothing better to do, and definitely wasting company resources by missing the right people who are truly capable.

I can always get a good guy, not necessarily great ones but capable, in just a three-hour or less semi-technical-behavioural one-on-one interaction. Ok, I will not call it an interview because when I do conduct such things I make sure I don't make the candidate feel he/she is somewhere in Guantanamo. The secret to this selection process is PREPARATION. Every candidates has a unique sets of questions prepared for them based on what they claim to know in their CVs. So making standardized interview questions is a big NO-NO! Preparation will always pay off. My interview sequence always goes this way:


  • Introduction of myself and what am I to the organization I represent

  • Asking the candidate how to address him/her.

  • Then the "can opener" questions



What are the "can opener" questions? These are some of the example questions that I usually starts with, let's say the candidate has extensively wrote about Spring in his CV:


  • "So what do you do in your current job?"


  • At this point, the candidate will express vaguely about what he/she does. And take note, almost everyone in this position will almost, always be honest.

  • "So you've mentioned in your CV that you have used Spring, What's good about it?"


  • Please listen carefully on this part and stop being a zealot for a while, if you tend not to like what the candidate will going to say. This is where your own EQ will be tested. Do not confront the candidate. Give brownie points on keywords like IoC, DI, etc. etc.

  • "What's your most difficult problem in using Spring?"


  • Case-to-case basis, you will know that the candidate is better than you when you hear something new and makes sense.

  • "When do you prefer not to use IoC?"


  • Again, listen and you will get some points for yourself here as well. But stupidity will show it's obvious head. You will find out how easy it is.

  • "Tell me about your experience in working on a team"


  • Never ask "Have you worked on a team?". Because that is answerable by yes/no and you will find yourself in a deadlock, you'll have a hard time getting the information you need to evaluate the candidate.

  • "Tell me about your most difficult teammate"


  • Scrutinize the candidate's behaviour. The way he solves problems, he may have solved it in a technical or smart(insidious) way.

  • "Tell me about your most challenging design problems"


  • Here, buzzwords like Singleton, encapsulation etc. will fly out anywhere and if the candidate really knows what he/she's talking about, smile. This part you will hear with enthusiastic elaboration how the candidate tackled the problems using a pattern and how they mixed patterns to come up with a solution or sets of solutions.
    How one tool sucks from the other, that x database is better than y database for a particular task. OR you'll see an empty stare and a hum here and a hum there.




At this part, while you're still browsing halfway of the candidate's CV. You know if he/she's a go or no go. And can immediately write your recommendations. Potentially save your company some money etc. etc.

I have mastered this skill during my days on the Dark Side. You can formulate your own questions too. But the real key is preparation.

The Falcon Pirate now online

There's a Darth Vader's blog, now it's Han Solo's blogs at The Falcon Pirate. Now I don't know if this has something to do with software development. We'll see.

27 July 2005

Inconsistency on Acegi's Reference Guide

Quoting the intstruction from Acegi Reference Guide, this is what it tells.

"1.11.3. Catalina (Tomcat) Installation

The following was tested with Jakarta Tomcat 4.1.30 and 5.0.19.

$CATALINA_HOME refers to the root of your Catalina (Tomcat) installation.

Edit your $CATALINA_HOME/conf/server.xml file so the section contains only one active entry. An example realm entry:

appContextLocation="conf/acegisecurity.xml"
key="my_password" />

Be sure to remove any other entry from your section.

Copy acegisecurity.xml into $CATALINA_HOME/conf.

Copy acegi-security-catalina-XX.jar into $CATALINA_HOME/server/lib.

Copy the following files into $CATALINA_HOME/common/lib:

*

aopalliance.jar
*

spring.jar
*

commons-codec.jar
*

burlap.jar
*

hessian.jar

None of the above JAR files (or acegi-security-XX.jar) should be in your application's WEB-INF/lib. The realm name indicated in your web.xml does not matter with Catalina."


But building the "Contacts" example and following their Maven(which really^1000000 sucks) build instructions will give a most likely erroneous war file that will cause "IncompatibleClassChangeError, IllegalStateException: No WebApplicationContext found" etc. etc., which leaves the hapless developer gasping for breathe where to go, and most likely be shooed away in the forums to just READ THE FUCKING MANUALS(what manuals?!?). While the cause of these problems are just overlapping of jar files from the common classloaders and webapp classloaders.

So here's my take, don't follow the freaking instructions above and you have a higher chance of making things work. I successfully did it on GlassFish.

Hey Spring/Acegi guys, you made a good job creating this hype, but why can't you agree on what's the right thing to do?

26 July 2005

Of Salsa and Protocol-agnosticism

It's like JavaSpaces. When everybody got to implement the Space interface except me. This is what I felt when I went to Union Square at Tanjong Pagar last Friday night. My Singaporean-American friend happened to be going there and I told her I could drop by and a have a few beers and listen to salsa and other Latin music since I don't can't really dance(and I don't want to). But upon the entrance to the door I saw the dance floor jampacked with every guys and babes doing salsa. My jaw dropped and my chic-magnet points seems to diminish every minute, guys who knows(implements) salsa can dance around with anybody. Feeling like boy in the candy store, I told my friend "this is amazing", never felt like a loser before I really am that night.

My friend told me to join her class, but I am still in self-denial. Anyway, the empire will strike back next time.

25 July 2005

Working Hard(ska Working Stupid) vs. Working Smart

A lot of developers not only in the Java Community, complains a lot about crap-related work, I mean work-related crap. There are developers who were agonized by long painful experiences that it has in-growned to their minds that if you haven't done the "working-hard" stuff, you haven't done enough or you haven't really feel the real work. F&#k that!

Developers in general who "work hard" has some unique behaviours that are different from the developers who work smart. Developers who work smart knows:


  • When to reinvent the wheel

  • When to say the big "NO"

  • That success is a daily happening and should be taken for granted

  • How not to submit to stress

  • That is fun to smirk at workmates who are really weary of what the fuck is going on with their careers. That listening to the backbiting sessions about their superiors are treated as a joke to themselves.
  • how to look at the big picture, and consciously knows his directions

  • how to think ahead of the competition.

  • and understand the fears of the opponents

  • how to effortlessly negotiate with minimal buzzword, less assertiveness and with full control.
  • when to give up.

  • every risk and how to calculate them.

  • how to be a confident asshat, that honestly tell people what he does and doesn't know

  • that pretending and fooling around has consequences

  • that it is stupid to repeat the same stupid mistake

  • how to party and have fun. While "hard-workers" work at weekends and holidays

  • what the task at hand and what to do about it. If doubtful, smart workers are inquisitive species

  • that it is a bad idea to consult with "hard workers"

  • that an "early bird catches the early worm and fucks the prom queen", while hard-workers whines about how to try their best

  • that lunch and other breaks are not the good times for work-related chats

  • that the most difficult of all is preserving integrity over job security, which is by the way achievable

  • that with integrity, job market is not scarce, which takes away their fears of "starting-over-again" dilemma



Working smart is not a skill that is developed overnight. It takes some level of guts and cockiness, some sacrifices as well. There are prices to be paid in exchange for the lessons learned. Smart workers can be mistaken as slackers in the office because the speed and the scope of possibilities laid out by them are tremendous and overwhelming in any given minute that hard-workers will simply scratch heads in awe.

Patriot Update

After several weeks of inactivity, I have created a new source folder for the drivers. Redefined interfaces that will handle SMS messaging thru GSM Modem. I guess the client APIs and SPI should have separate source folders as well, to be able to build the whole thing properly.

More on the Patriot project here.

Building The Empire: Smaller Steps

Four months of no Linux here in Singapore and I am starting to get some sort of a withdrawal syndrome of a heroine junkie. It's really hard not to work with Linux, missing the CLI, means doing stuff the harder way of point-drag-click dance, where you could accomplish 1-3 steps with one press of the "Enter" button.

Incidentally, My eyes happens to tripped on one of the decent idle boxes in our office. It's a Dell Dimension 4300S with just 256MB RAM(for now), good enough as my second development box. Put up a Slackware 10.1 on it, install Glassfish on it. And behold, I was amazed at the startup speed. I don't how many times, but it's really, really much faster than BEA Weblogic 8.1 running on a SparcServer (Solaris 8) with 512MB of RAM which is, by the way, one of my toys that I want to get rid off pretty soon from the office.

So Slackware 10.1, Welcome to Singapore.

23 July 2005

Anatomy of a Corporate Developer

It's funny to watch these species wander around mazes of endless and monotonic cubicles of the corporate world. But don't be decieved by the crisp suit and tie and clean looks, the neater they are the dumber they get. So let's take a look from the uncanny consultant's view of what is a corporate developer.

First, let's determine where they are in the food chain. A corporate developer looks up at only two kinds of superior in the workplace, a clerk and a glorified clerk. His/her favorite term for open source tools are "freebies", freeware, shareware etc. A corporate developer is not really a programmer by heart, he/she only took the programming course because of its job market demand and is willing to get out of programming as soon as better opportunities pop up like taking up a Nursing course and eventually become a caregiver or better he/she wishes to become a glorified clerk ticking up timelines, gantts and some UML diagrams awefully, wrongly drawn.

At work, he's usually the nicest, sweetest smelling guy you can walk past at complete with designer ties and shoes, he thought he looks genius by putting a "The Geek shall inherit the Earth" wallpaper with Bill Gates' face on it. He/she thinks the meaning of JAVA is "Just Another Vague Acronym". He/she believes that the best solutions are the ones you can always buy. At the start of the day a corporate developer usually checks emails first instead of synchronizing his/her codes against the CVS repository. After updating his code, he will proceed back to checking and answering emails for the rest of the day. Corporate developer worships every author of books that's in his seatmate's bookshelf and every blogs that he shares his personal view regarding corporate development, that he/she even quoutes when arguing some important technical issues.

A corporate developer eats buzzwords for breakfast, lunch and dinner. He/she thinks that wearing a shirt with an IT vendor's logo embroidered in the left chest is awesome and geeky. He/she never touched a linux/unix box in his entire development career and never heard of Gnome. And normally, his/her language of choice is Visual Basic or anything high-level until Java became so hot, he/she jumped the bandwagon. He/she believes that good practices aren't necessary as long as the system is currently working. A corporate developer loves BEA even if he/she has been bitten by it, he/she will insist on using it on the next project rather than be "bitten by an unfamiliar snake". And they think learning while working is a waste of time.

This is sometimes sickening, if the corporate developer especially the male variety has some new cool gadget, he knows very well the intricacies and internal workings of that thing rather than the work he is supposed to do.

20 July 2005

How the Integer-masked permission works

Honestly, it's so simple. Let's say we have the following permissions such as read, write, create, delete and administration permissions. We'll assign it like:



administer = 2^0
read = 2^1
write = 2^2
create = 2^3
delete = 2^4


Using the logical inclusive OR ("|") operator we can come up with a series of logical combinations.


read, write = 2 | 4

0010
0100
====
0110 = 6 (READ,WRITE)

read,write,create = 2 | 4 | 8

0010
0100
====
0110
1000
====
1110 = 14 (READ,WRITE,CREATE)

read,write,create,delete = 2 | 4 | 8 | 16

00010
00100
=====
00110
01000
=====
01110
10000
11110 = 30 (READ,WRITE,CREATE,DELETE)

and the list can go on...


Not perfect, but better than anything else. So the only thing needed on any permission tables are the actual integer permission values.

Building The Empire

I as We, declare this day the start of Building The Empire. This island is white and ripe. Get your ploughs, your shovels and your picks. Take that corner and this corner and I will take mine. It's harvest time. Every minute and every second counts. We will liberate this city from proprietary madness, from fear, uncertainty and deceit. From the handshakes to the sealing of contracts there will be no turning back. Everything counts in large amounts. We have the spoils anyone can't refuse. Our technology is no secret, our weapons-of-choice has been laid out. Our battlefield is open, open to those who are ready to fight. We will change the rule of the game. It will fit like water to our pipes. And this will be everyone's unwritten business law: "Adapt or die".

Say "Open Source is not for us", we say "Adapt or die". Say "The old ways works with us", we say "Adapt or die". Say, "This is what they taught in school", we say "Adapt or die". Adapt and we will support. Oppose and we'll bring the game to the next level. Until submission is achieved. Or else, competition is dead before it even started. Such is an art of war.

Let's Build The Empire. It's for everyone. It's extensible, replicable, "commoditizable". It's not unique. Not even a monopoly. What differs from one to another is the value they bring to the battlefield. Not the technology or the strategy they choose adapt. The days of the proprietary software are numbered. Let's Build The Empire and start counting.

Join us and together we'll rule this part of the galaxy.

19 July 2005

Acegi's Integer-masked ACL

Finally, a permission masking that works like chmod in Linux. This is the kind of ACL that makes sense in every Java EE applications. By using Acegi's Integer-masked ACL, permissions and groupings are not directly wired up together. Which is a common flaw in most Java EE applications past and present. This means it will be easier to implement a "by-group" permission. More on this later.

18 July 2005

Testing Acegi Security's Provider-based Authentication

I am taking down this note as this process is very hard to remember when finalized and has been stabilized. The authentication process is very straightforward because most of the dirty works are handled by authentication providers. We will take the assumption that the reader is already familiar with Spring's application-context XML configurations in Acegi. We'll write a testable code based on JUnit. But first we have to enumerate the steps our authentication method will going to take:


  1. Initialize a ListableBeanFactory instance

  2. Initialize the net.sf.acegisecurity.Authentication interface with a proper reference implementation

  3. Obtain an instance of the from the ListableBeanFactory configuration

  4. Invoke the AuthenticationProvider.authenticate()
  5. Get the instance of the net.sf.acegisecurity.providers.dao.User from the AuthenticationProvider.authenticate().getPrincipal()
  6. Check ALL of the following from the User object: isEnabled(), isAccountNonLocked(), isAccountNonExpired(), isCredentialsNonExpired()
  7. Register the Authentication object to the SecureContext

  8. Register the SecureContext object to ContextHolder.setContext() static method.


In code, this is how it looks like:

Listing 1:


public boolean authenticate(String username, String password) {

Authentication authentication =
new UsernamePasswordAuthenticationToken(username, password);

SecureContext secureContext = new SecureContextImpl();

//have chose daoAuthenticationProvider for this.
AuthenticationProvider provider =
(AuthenticationProvider)beanFactory.getBean("daoAuthenticationProvider");
Authentication auth = provider.authenticate(authentication);
System.out.println(auth.getName());
User user = (User)auth.getPrincipal();

if (user.isAccountNonExpired() && user.isAccountNonLocked() &&
user.isCredentialsNonExpired() && user.isEnabled()){
auth.setAuthenticated(true);
}

secureContext.setAuthentication(auth);
ContextHolder.setContext(secureContext);
return auth.isAuthenticated();

}



The test code should assert for the isAuthenticated() method with something like this:

Listing 1:


public void testAuthenticate() {

String[] contexts = {"applicationContext-acegi-security.xml",
"applicationContext-common-business.xml",
"applicationContext-common-authorization.xml"};

ListableBeanFactory beanFactory =
new ClassPathXmlApplicationContext(contexts);

UserAuthenticate authenticate = new UserAuthenticate(beanFactory);

//we assume that you are familiar with JUnit
assertTrue(authenticate.authenticate("scott", "wombat"));

}



To do this test properly, all the AOP-based interceptors must be disabled since it will not be ran on a web container or application server. From a controller class (such as Webwork2 action classes) the authenticate() method at Listing 2 will be shorter because the ContextHolder already has the security credentials provided by AOP interceptors executed during initialization of UsernamePasswordAuthenticationToken class. But for the sake of making a testable code, I have provided those checks for clarity.

17 July 2005

My Non-tech entries

I've been itching to write non-technical stuff for a while. Since it doesn't have a room here in this URL. And I don't want to be tempted to push non-tech stuff here anymore. I would like to invite my good readers to see my non-tech entries at http://jaredflo.multiply.com/journal. So if the "force" doesn't move anywhere in here, its there ;).

Thanks for your patronage.

15 July 2005

Implementing Embedded Database for Corporate Developers

There are some corporate developers who would claim they were able to build "massive" distributed systems that were able to serve 100,000 users or so(I could imagine them now flapping their ears). But if you ask them what if someone/SOMETHING suddenly pulls the network cables behind the asses of their servers or a sudden power outage that no UPS can handle left some part of the data center dead and most of the clusters crippled? Huge chances are these morons will give you a blank stare and will argue that those things are absurd and will never happen.

To make it easy for corporate developers to understand some aspects of "mission-critical" elements of an application. First, we look at the RDBMS/JMS application and how to maintain its data integrity in times of any untoward crisis. Suppose we had a transaction that has to be committed across some distant SQL database when all of a sudden the JMS Provider and the remote DB went down probably due to a nuclear attack leaving only less reliable lines available. Nonetheless, data has still to be transmitted to the other end. So the requirements to perform that has to be streamlined as well which means the absence of using SQL databases is inevitable because the transaction due to its emergency nature has to be fast and stable so therefore the use of JDBC is definitely a big minus also, and the only available transmission is via HTTP. Likewise, we should not forget the RDBMS are all down as well, this is the worst possible scenario. And since the JMS is also down transmission to queues will be impossible.

Now, here's one solution for free. Let's introduce the use of SleepyCat's BerkeleDB Java Edition 1.5. There's no need to tell who uses BerkeleyDB because this article is intended to help corporate developer understands the nature of what they're suppose to be doing in times of crisis.

Let's now look at the code (AlarmLogDBEnv.java)that initializes a BerkeleyDB Database Environment. The nature of this code is to write an Alarm message to BerkeleyDB when RDBMS is not available.



import java.io.File;

import org.apache.log4j.Logger;

import com.sleepycat.bind.serial.StoredClassCatalog;
import com.sleepycat.je.Cursor;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;

/**
* Description:
*
* This is the helper class for utilizing sleepycat embedded db.
*
* @author Jared Odulio
*
*/
public class AlarmLogDBEnv {

private Database alarmlogDB;
private DatabaseConfig dbConfig;
private Environment env;
private EnvironmentConfig envConfig;
private StoredClassCatalog alarmsCatalog;
private Cursor cursor;
private String dbEnv;
private String key;
private DatabaseEntry alarmKey;
private DatabaseEntry alarmData;
private Logger logger;
private File fileEnv;

/**
*
*/
public AlarmLogDBEnv(String dbEnv) {

super();
this.dbEnv = dbEnv;
initialize();

}

/**
* Copy constructor that takes a File object as an
* argument.
*
* @param fileEnv
*/
public AlarmLogDBEnv(File fileEnv){

this.fileEnv = fileEnv;
initWithFile();

}

private void initWithFile(){

logger = Logger.getLogger(this.getClass());

envConfig = new EnvironmentConfig();
envConfig.setAllowCreate(true);
//envConfig.setTransactional(true);

try {

env = new Environment(fileEnv, envConfig);
dbConfig = new DatabaseConfig();
dbConfig.setAllowCreate(true);
//dbConfig.setTransactional(true);
alarmlogDB = env.openDatabase(null, "AlarmLogDB", dbConfig);

} catch (DatabaseException e) {

logger.error(e.toString(), e);

}

}

/**
* Initialize this class with only the String value of the Database
* Environment path as argument.
*
*/
private void initialize(){

logger = Logger.getLogger(this.getClass());

envConfig = new EnvironmentConfig();
envConfig.setAllowCreate(true);
//envConfig.setTransactional(true);

try {

env = new Environment(new File(dbEnv), envConfig);
dbConfig = new DatabaseConfig();
dbConfig.setAllowCreate(true);
//dbConfig.setTransactional(true);
alarmlogDB = env.openDatabase(null, "AlarmLogDB", dbConfig);

} catch (DatabaseException e) {

logger.error(e.toString(), e);

}

}

/**
* @param string
*/
public void setKey(String string) {
key = string;
}


/**
* @return
*/
public Environment getEnv() {
return env;
}

/**
* @return
*/
public Database getAlarmlogDB() {
return alarmlogDB;
}

public void close(){

if (env != null){

try {

alarmlogDB.close();
env.close();

} catch (DatabaseException e) {

logger.error(e.toString(), e);

}
}

}
}


Of course we will need to create a DAO-Pattern-style value object and call it EmbeddedAlarm.java


/**
* Description:
* This is the model used for storing and retrieving alarm log data into the
* Berkeley Embedded DB.
*
* @author Jared Odulio
*
*/
public class EmbeddedAlarm {

private int alarmID;
private int errorID;
private int agentID;
private int moduleID;
private String instanceID;
private String hostAddress;
private int severity;
private String remarks;
private String status;
private long entryDate;
private String userID;
private long clearDate;

/**
* @return
*/
public int getAgentID() {
return agentID;
}

/**
* @return
*/
public int getAlarmID() {
return alarmID;
}

/**
* @return
*/
public long getClearDate() {
return clearDate;
}

/**
* @return
*/
public long getEntryDate() {
return entryDate;
}

/**
* @return
*/
public int getErrorID() {
return errorID;
}

/**
* @return
*/
public String getHostAddress() {
return hostAddress;
}

/**
* @return
*/
public String getInstanceID() {
return instanceID;
}

/**
* @return
*/
public int getModuleID() {
return moduleID;
}

/**
* @return
*/
public String getRemarks() {
return remarks;
}

/**
* @return
*/
public int getSeverity() {
return severity;
}

/**
* @return
*/
public String getUserID() {
return userID;
}

/**
* @param i
*/
public void setAgentID(int i) {
agentID = i;
}

/**
* @param i
*/
public void setAlarmID(int i) {
alarmID = i;
}

/**
* @param l
*/
public void setClearDate(long l) {
clearDate = l;
}

/**
* @param l
*/
public void setEntryDate(long l) {
entryDate = l;
}

/**
* @param i
*/
public void setErrorID(int i) {
errorID = i;
}

/**
* @param string
*/
public void setHostAddress(String string) {
hostAddress = string;
}

/**
* @param i
*/
public void setInstanceID(String string) {
instanceID = string;
}

/**
* @param i
*/
public void setModuleID(int i) {
moduleID = i;
}

/**
* @param string
*/
public void setRemarks(String string) {
remarks = string;
}

/**
* @param i
*/
public void setSeverity(int i) {
severity = i;
}

/**
* @param string
*/
public void setUserID(String string) {
userID = string;
}

/**
* @return
*/
public String getStatus() {
return status;
}

/**
* @param string
*/
public void setStatus(String string) {
status = string;
}

}






This value object needs to be converted in byte arrays so that BerkeleyDB could understand it. So we use our own Custom Binding to do that. AlarmLogBinding.java


import net.smart.umui.logging.model.EmbeddedAlarm;

import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.bind.tuple.TupleInput;
import com.sleepycat.bind.tuple.TupleOutput;

/**
* Description:
*
* This class is used for binding the EmbeddedAlarm class in order to write and read
* complex objects in to BerkeleyDB embedded database.
*
* @author Jared Odulio
*
*/
public class AlarmLogBinding extends TupleBinding {



/* (non-Javadoc)
* @see com.sleepycat.bind.tuple.TupleBinding#entryToObject(com.sleepycat.bind.tuple.TupleInput)
*/
public Object entryToObject(TupleInput ti) {

EmbeddedAlarm alarm = new EmbeddedAlarm();
alarm.setAlarmID(ti.readInt());
alarm.setErrorID(ti.readInt());
alarm.setAgentID(ti.readInt());
alarm.setModuleID(ti.readInt());
alarm.setInstanceID(ti.readString());
alarm.setHostAddress(ti.readString());
alarm.setSeverity(ti.readInt());
alarm.setRemarks(ti.readString());
alarm.setStatus(ti.readString());
alarm.setEntryDate(ti.readLong());
alarm.setUserID(ti.readString());
alarm.setClearDate(ti.readLong());

return alarm;
}

/* (non-Javadoc)
* @see com.sleepycat.bind.tuple.TupleBinding#objectToEntry(java.lang.Object, com.sleepycat.bind.tuple.TupleOutput)
*/
public void objectToEntry(Object obj, TupleOutput to) {

EmbeddedAlarm alarm = (EmbeddedAlarm)obj;

to.writeInt(alarm.getAlarmID());
to.writeInt(alarm.getErrorID());
to.writeInt(alarm.getAgentID());
to.writeInt(alarm.getModuleID());
to.writeString(alarm.getInstanceID());
to.writeString(alarm.getHostAddress());
to.writeInt(alarm.getSeverity());
to.writeString(alarm.getRemarks());
to.writeString(alarm.getStatus());
to.writeLong(alarm.getEntryDate());
to.writeString(alarm.getUserID());
to.writeLong(alarm.getClearDate());


}

}



We also need an enabler class to initialize the Database Environment based on client object's configuration. AlarmLogDB.java



import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import net.smart.umui.binding.AlarmLogBinding;
import net.smart.umui.logging.db.exception.AlarmDBException;
import net.smart.umui.logging.model.EmbeddedAlarm;

import org.apache.log4j.Logger;

import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.je.Cursor;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;

/**
* Description:
*
* This is the BerkeleyDB application class that will use the
* AlarmLogDBEnv class.
*
* @author Jared Odulio
*
*/
public class AlarmLogDB {

private Database alarmLogDB;
private Environment env;
private String dbEnv;
private AlarmLogDBEnv alarmEnv;
private Cursor cursor;
private Logger logger;
private EmbeddedAlarm embedAlarm;
private DatabaseEntry dbEntry;
private DatabaseEntry alarmKey;

private String dbKey;
private TupleBinding alarmBinding;

/**
*
*/
public AlarmLogDB() {

logger = Logger.getLogger(this.getClass());

}

/**
* Initialize the DB for writing or reading functions.
* @param dbEnv
*/
public void setup(String dbEnv){

alarmEnv = new AlarmLogDBEnv(dbEnv);
alarmLogDB = alarmEnv.getAlarmlogDB();
alarmBinding = new AlarmLogBinding();

try {

cursor = alarmLogDB.openCursor(null, null);

logger.info("Cursor has been opened");

} catch (DatabaseException e) {

logger.error(e.toString(), e);

}
}

/**
* Use this method if a File object is to be used instead of the
* String value of the Database Environment path.
*
* @param fileEnv
*/
public void setup(File fileEnv){

alarmEnv = new AlarmLogDBEnv(fileEnv);
alarmLogDB = alarmEnv.getAlarmlogDB();
alarmBinding = new AlarmLogBinding();

try {

cursor = alarmLogDB.openCursor(null, null);

logger.info("Cursor has been opened");

} catch (DatabaseException e) {

logger.error(e.toString(), e);

}

}
/**
* Write Alarm log to embedded db.
*
*/
public void writeAlarm(){

try {

dbEntry = new DatabaseEntry();
alarmKey = new DatabaseEntry(dbKey.getBytes("UTF-8"));
//converts the model to database entry
alarmBinding.objectToEntry(embedAlarm, dbEntry);
cursor.put(alarmKey, dbEntry);

logger.info("Alarm recorded");
cursor.close();
alarmEnv.close();

} catch (UnsupportedEncodingException e) {

logger.error(e.toString(), e);

} catch (DatabaseException de){

logger.error(de.toString(), de);

}

}

/**
* Gets the alarm logs from BerkeleyDB
*
* @return
* @throws AlarmDBException
*/
public List getAlarms() throws AlarmDBException{

List alarmList = new ArrayList();
dbEntry = new DatabaseEntry();
alarmKey = new DatabaseEntry();

try {

while (cursor.getNext(alarmKey, dbEntry, LockMode.DEFAULT) == OperationStatus.SUCCESS){

embedAlarm = (EmbeddedAlarm)alarmBinding.entryToObject(dbEntry);
alarmList.add(embedAlarm);

}

} catch (DatabaseException e) {

throw new AlarmDBException(e);

}

return alarmList;
}

public void deleteAlarms() throws AlarmDBException{

try {
alarmLogDB.truncate(null, false);
} catch (DatabaseException e) {

throw new AlarmDBException(e);
}

}

/**
* Sets the key to be used for the database entry.
*
* @param dbKey
*/
public void setDBEntryKey(String dbKey){
this.dbKey = dbKey;
}

/**
* @param alarm
*/
public void setEmbedAlarm(EmbeddedAlarm alarm) {
embedAlarm = alarm;
}

public void close(){

try {
cursor.close();
} catch (DatabaseException e) {

logger.error(e.toString(), e);
}
alarmEnv.close();

}
}



To test those codes we need to write a couple of classes that we will name TestEmbeddedReader.java and TestEmbeddedWriter.java. For TestEmbeddedWriter.java, heres the code snippet.



import java.io.File;
import java.net.URI;

import org.apache.log4j.Logger;

import net.smart.umui.logging.db.AlarmLogDB;
import net.smart.umui.logging.model.EmbeddedAlarm;

/**
* Description:
*
* Testing writer.
*
* @author Jared Odulio
*
*/
public class TestEmbeddedWriter {

private AlarmLogDB alarmDB;
private EmbeddedAlarm alarmModel;
private File dbenv;
private Logger logger = Logger.getLogger(this.getClass());


/**
*
*/
public TestEmbeddedWriter() {

initialize();

}

private void initialize(){

dbenv = new File("dbEnv");
dbenv.mkdir();

alarmDB = new AlarmLogDB();
alarmDB.setup(dbenv);
alarmModel = new EmbeddedAlarm();
alarmModel.setAgentID(0);
alarmModel.setAlarmID(2);
alarmModel.setClearDate(System.currentTimeMillis());
alarmModel.setEntryDate(System.currentTimeMillis());
alarmModel.setErrorID(1);
alarmModel.setHostAddress("10.121.55.105");
alarmModel.setInstanceID("instanceID");
alarmModel.setModuleID(5);
alarmModel.setRemarks("NO REMARKS");
alarmModel.setSeverity(6);
alarmModel.setStatus("NO STATUS");
alarmModel.setUserID("jared");

alarmDB.setEmbedAlarm(alarmModel);

/*
* If you're going to follow this example think of your own
* unique key. The fully qualified name of your class is definitely
* acceptable.
*/
alarmDB.setDBEntryKey("TestKey3");

}

public void writeToDB(){

alarmDB.writeAlarm();
logger.info("Data has been written");

}

public static void main(String[] args) {

new TestEmbeddedWriter().writeToDB();

}
}



For the TestEmbeddedReader.java.


import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;

import net.smart.umui.logging.db.AlarmLogDB;
import net.smart.umui.logging.db.exception.AlarmDBException;
import net.smart.umui.logging.model.EmbeddedAlarm;

/**
* Description:
*
*
* @author Jared Odulio
*
*/
public class TestEmbeddedReader {

private AlarmLogDB alarmLogDB;
private List logs;
private EmbeddedAlarm alarmModel;
private Logger logger = Logger.getLogger(this.getClass());


/**
*
*/
public TestEmbeddedReader() {

initialize();
}

private void initialize(){

File dbenv = new File("dbEnv");
alarmLogDB = new AlarmLogDB();
alarmLogDB.setup(dbenv);
alarmModel = new EmbeddedAlarm();
alarmLogDB.setEmbedAlarm(alarmModel);
alarmLogDB.setDBEntryKey("TestKey");

}

public List readLogs(){

try {

logs = alarmLogDB.getAlarms();
alarmLogDB.deleteAlarms();
alarmLogDB.close();

} catch (AlarmDBException e) {

logger.error(e.toString(), e);

}

return logs;

}

public Logger getLog4j(){
return logger;
}

public static void main(String[] args) {

EmbeddedAlarm alarms = null;
List logs = null;
TestEmbeddedReader reader = new TestEmbeddedReader();
logs = reader.readLogs();
Logger logger = reader.getLog4j();
Iterator it = logs.iterator();
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss");

while(it.hasNext()){

alarms = (EmbeddedAlarm)it.next();
logger.info("Host Address: " + alarms.getHostAddress());
logger.info("Remarks: " + alarms.getRemarks());
String date = sdf.format(new Date(alarms.getClearDate()));
logger.info("Clear Date: " + date);

}


}

}



Now this is an instant embedded db! all a corporate developer needs to do is download the BerkeleyDB API implementation, modify a few code above that will cause the data to be re-routed from the normal RDBMS/JMS path to the lightweight and fast route of embedded database.

13 July 2005

Simple Ping with Java NIO

If you're learning Java NIO and reading the Sun's example, it's looks complete but so horrific. Sometimes that's not exactly what you want to do. Pinging a remote is one basic thing Java doesn't fundamentally offer because it doesn't support ICMP protocol, But I was intrigued about Java 5.0's InetAddress.isReachable(), according to its javadoc it uses the OS's ICMP implementation. But that's Java 5.0 and many of us maybe moving to that version perhaps by next year or not at all. Believe me, even some "most high-tech" U.S. companies today still uses Java 1.1

Going back to our simple Ping program, we'll be using Java NIO's DatagramChannel to send and receive packets to imitate a ping action. But before we go to the code, here's a brief description of how our Java NIO Ping will work. First it will open a DatagramChannel, connects to the remote host using an InetSocketAddress with echo port 7, sends packets using ByteBuffer, receive packets that contains the sent value in a ByteBuffer indicating a successful ping. Otherwise the remote host is unreachable or has timed out.

Listing 1: Ping.java



import java.nio.*;
import java.net.*;

public class Ping{

public void pingMe(){

try{
ByteBuffer send = ByteBuffer.wrap("Hello".getBytes());
ByteBuffer receive = ByteBuffer.allocate(
"Hello".getBytes().length);
//use echo port 7
InetSocketAddress socketAddress =
new InetSocketAddress("192.168.1.2", 7);
DatagramChannel dgChannel = DatagramChannel.open();
//we have the channel non-blocking.
dgChannel.configureBlocking(false);
dgChannel.connect(socketAddress);
dgChannel.send(send, socketAddress);
/* it's non-blocking so we need some amount of delay
* to get the response
*/
Thread.sleep(100);
dgChannel.receive(receive);
String response = new String(receive.array());
if (response.equals("Hello")){
System.out.println("Ping is alive");
}else{
System.out.println("No response");
}

} catch (IOException e){
e.printStackTrace();
} catch(InterruptedException e){
e.printStackTrace();
}


}
}


Sometimes this is not an ideal solution, but for quick and dirty checking of networks programmatically, this code has been very handy with me ever since NIO came out.

09 July 2005

Open Source Licenses: Let's talk business

While I am preparing this material, someone has thought ahead of me. But this time I am going para-legal because we need to bust the "GPL and anything else" thinking, it scares off businesses who wish to take advantage of open source. Let's start off with a couple of licenses, GPL and BSD.

GPL
===

If anyone will read a a GPL license, there are salient points that need to be considered. For one is

"...0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does..."


Now, these are the questions, is your work "based on the Program"? Does your work "uses the Program"? If your answer is yes to the former question then you have to distribute your work, otherwise you only need to publish appropriate copyrights. And your code is protected. When we say "Program" in this context, it means the GPL'd source code. Basing a work from a "Program" is totally different from a work that "uses" the Program, right? So the use of the "Program" is not covered in this License.



BSD(Berkeley Software Distribution)
===================================

This license is the preferred license for software developers who, in the future, will commoditize their programs or the derivative of it. The terms are very simple, in fact, I could copy and paste the whole license here:


Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.



Here, nothing was mentioned about your work or the derivative of your work, the only thing you need to do is to disclose the copyright of the licensed "Program". That's it. This is a very highly competitive license, it kills software businesses that escrows their sources until its outdated, stale and no longer scalable.

Business should embrace BSD, this is a business-friendly, license. Open Source is not a "one whole thing" it favors those who understands its terms, its rules of the game. Decision makers should not just only listen to the FUDs coming from Forbes, BusinessWeek, Red Herring etc. etc. they are not the authority on this game. It is those who contributed, initiated some work and advocated, and understands its way are the ones who are authorized to tell what is and what will not fit to a particular business.

I also prefer this license in some of our open source projects such as Patriot because in the future the business value of these things might increase and it's there ready to take the spoils. So "GPL and anything else"? It doesn't that work way, you're already dead in the competition before it even started. No such thing as "two kinds of open source licenses".

07 July 2005

And just a few hours...

EU has just rejected the software patent bill. Long Live Open Source! Open Source Rules. This is good for everyone, especially to the business community. Even to the proprietary commercial software development community. As for the open source licenses. This is not the article yet. Coming Soon.

06 July 2005

Get it while it's still hot

Move it! Move it! I am yelling about the rejection of the EU Software Patent directive, it seems that it's now close to being killed soon. The software patent directive can enable anyone to patent every stupid program known to man. True that you can patent compression algorithms but you can't patent payment transaction algorithms alright! Put it as this, I can patent an invention for example is a self-purifying, disinfecting, irreplaceable water-pipe. But no one can patent a plumbing system that is made out of that pipe! This is known as functional device. Functional devices are non-patentable.

This is very good(feichang hao) for open source. It promotes mass innovation aside from other promises. But to appreciate or take advantage of open source in its truest sense one must understand each and every license that is approved as open source. There is no such thing as "GPL and anything else". Go and tell that to court. That will be my next blog material.

01 July 2005

The FUD that is called "Get the Facts"

After watching "War of the Worlds" at Suntec City last night, on the way home, I glanced upon the large LCD screen running an animation with a familiar mascot known to the Linux community as Tux. I watched the commercial carefully and smirked with impish grin. It was Microsoft's "getthefacts" TV commercial, so silly. It's pitiful that it seems only Singapore is the place they know how to scare people because I don't think they will spend much money for such things to be aired in the Philippines and some GNU/Linux/FOSS-very-aware countries including the European and Latin American states, It's going to be a waste of time and money. I can't take a shot at it because too much glare is coming out of my pictures.

But if you'll notice, M$ is gradually shifting its focus from the OS to the gaming console. Because it's payback time for Steve Jobs, the Mac-on-Intel is not a deadly shot for IBM's PowerPC. It's a deadly shot for Windows. Look at the setbacks they are facing now, For one IE7 can't get tabbed-browsing(hey muggles, do you know what tabbed-browsing is?) to work properly. They are practically spreading thinly everywhere.