Saturday, July 30, 2011

IndiMail Quick Installation .!

IndiMail supports two types of virtual domains

1. Non-Clustered domain - A domain existing on a single server
2. Clustered domain - A domain extended across multiple servers, with each
server having its own set of users.

You must decide if you want Non-clustered setup or a clustered setup. If you have millions
of users, then you must chose clustered setup. Even if you chose to install a non-clustered
setup, you can always migrate to a clustered setup later.

IndiMail has yum / RPM / Debian repositories for most of the Linux Distros at

http://download.opensuse.org/repositories/home:/indimail/

The latest RPM (for yet to be released version) can be found at

http://download.opensuse.org/repositories/home:/mbhangui/

Download the RPM for either of the two above repository and proceed below

--------------------------------------------------------------------------------------

Creating a non-clustered Domain
-------------------------------

Install IndiMail from RPM / Debian
% sudo rpm -ivh indimail-1.8.2-1.1.i386.rpm (for RPM)
or
% sudo dpkg -i indimail_1.8.2-1_i386.deb (for Debian)

Create a basic configuration file required by IndiMail
% cd /var/indimail/control
% su
# echo "localhost:indimail:ssh-1.5-:/tmp/mysql.sock" > host.mysql

Start IndiMail
# /var/indimail/sbin/initsvc -on
# exit

x------------------------------------------------------------------------------------x
| NOTE: replace localhost, indimail, ssh-1.5-, /tmp/mysql.sock as relevant to your |
| MySQL installation. You can use 3306 instead of /tmp/mysql.sock in case your MySQL |
| database is on another host. |
| you must use host:user:password:socket or host:user:password:port format |
| for host.mysql (for IndiMail 1.6.9 and above). Also set your PATH to |
| have /var/indimail/bin in the path. |
| If you change the socket/port then you have to edit /var/indimailcontrol/host.* |
| and /var/indimail/etc/indimail.cnf to change the socket path / port |
| |
| Instead of the above initsvc command, you can also do (a more portable way) |
| |
| % sudo service indimail start |
x------------------------------------------------------------------------------------x

Ensure MySQL is running

The RPM installation creates MySQL service in down state. The MySQL service
will not come up unless you use the command svc -u. Also to ensure that the
service comes up automatically after system reboot, remove the file 'down'
Also check the MySQl configuration file /var/indimail/etc/indimail.cnf
for the port and socket parameter.
[client]
port = 3306
socket = /tmp/mysql.sock

% sudo /bin/rm /service/mysql.3306/down
% sudo /var/indimail/bin/svc -u /service/mysql.3306

% sudo /var/indimail/bin/svstat /service/mysql.3306
/service/mysql.3306: up (pid 11936) 5 seconds

Create a virtual domain and do various operations
% sudo /var/indimail/bin/vadddomain example.com pass
% /var/indimail/bin/vuserinfo postmaster@example.com
% sudo /var/indimail/bin/vadduser testuser1@example.com pass
% /var/indimail/bin/vuserinfo testuser1@example.com
% /var/indimail/bin/vpasswd testuser1@example.com newpass
% /var/indimail/bin/vmoduser -q 50000000 testuser1@example.com

--------------------------------------------------------------------------------------

Creating a Clustered Domain
---------------------------

Install IndiMail from RPM / Debian
% sudo rpm -ivh indimail-1.8.2-1.1.i386.rpm
or
% sudo dpkg -i indimail_1.8.2-1_i386.deb (for Debian)

Create basic configuration files required by IndiMail
% cd /var/indimail/control
% su
# echo "localhost:indimail:ssh-1.5-:/tmp/mysql.sock" > host.cntrl
# ln -s host.cntrl host.master
# echo 192.168.1.100 > hostip (replace 192.168.1.100 with your mailserver IP)

Start IndiMail
# /var/indimail/sbin/initsvc -on
# exit

x------------------------------------------------------------------------------------x
| NOTE: replace localhost, indimail, ssh-1.5-, /tmp/mysql.sock as relevant to your |
| MySQL installation. You can use 3306 instead of /tmp/mysql.sock in case your MySQL |
| database is on another host. |
| you must use host:user:password:socket or host:user:password:port format |
| for host.cntrl (for IndiMail 1.6.9 and above). Also set your PATH to |
| have /var/indimail/bin in the path. |
| If you change the socket/port then you have to edit /var/indimailcontrol/host.* |
| and /var/indimail/etc/indimail.cnf to change the socket path / port |
| |
| Instead of the above initsvc command, you can also do (a more portable way) |
| |
| % sudo service indimail start |
x------------------------------------------------------------------------------------x

Ensure MySQL is running

The RPM installation creates MySQL service in down state. The service will
not come up unless you use the command svc -u. Also to ensure that the
service comes up automatically after system reboot, remove the file 'down'

% sudo /bin/rm /service/mysql.3306/down
% sudo /var/indimail/bin/svc -u /service/mysql.3306

% sudo /var/indimail/bin/svstat /service/mysql.3306
/service/mysql.3306: up (pid 11936) 7 seconds

Create a virtual domain and do various operations
% sudo /var/indimail/bin/vadddomain -D indimail -S localhost \
-U indimail -P ssh-1.5- -p 3306 -c example.com pass
% /var/indimail/bin/vuserinfo postmaster@example.com
% sudo /var/indimail/bin/vadduser testuser1@example.com pass
% /var/indimail/bin/vuserinfo testuser1@example.com
% /var/indimail/bin/vpasswd testuser1@example.com newpass
% /var/indimail/bin/vmoduser -q 50000000 testuser1@example.com

Query the cluster definition
% /var/indimail/bin/dbinfo -s

--------------------------------------------------------------------------------------

Send / Receive Mails
--------------------

At this stage, your setup is ready to send mails to the outside world. To receive
mails, you need to create your actual domain (instead of example.com) using vadddomain
and setup a mail exchanger record for your domain (MX record).
To send mails, you can either use SMTP or use a sendmail (IndiMail's sendmail replacement
/var/indimail/bin/sendmail).

% ( echo 'First M. Last'; uname -a) | mail -s "IndiMail Installation" manvendra@indimail.org

Replace First M. Last with your name.

--- * --- * ---- * --- * --- THE END --- * --- * --- * --- * ---

x------------------------------------------------------------------------------------x
|NOTE: You can email me at manvendra@indimail.org, if you find this confusing or |
|need any help/clarification. |
x------------------------------------------------------------------------------------x

IndiMail Installation for newbies in 10 steps

Installing IndiMail from RPM
1. Install OS
 

SUSE
o openSUSE 11.4
o openSUSE 11.3
o openSUSE Tumbleweed
o SUSE Linux Enterprise 11 SP1
o SUSE Linux Enterprise 11
o SUSE Linux Enterprise 10
o openSUSE Factory

* Red Hat

o Fedora 15
o Fedora 14
o Red Hat Enterprise Linux 5
o Red Hat Enterprise Linux 6

o CentOS 5
o Mandriva_2010.1

2. Determine if your OS is 32 bit or 64 Bit

% uname -m

The command will output i386, i586, i686 for 32 bit and x86_64 for 64 bit

3. Download the Repo correspoding to your OS from
http://sourceforge.net/projects/indimail/files/Repo/

e.g IndiMail-CentOS_5.repo for CentOS 5 and copy that to /etc/yum.repos.d
% sudo cp IndiMail-CentOS_5.repo /etc/yum.repos.d/indimail.repo

4. Execute the YUM command as per the output of uname command in step 2
% sudo yum install indimail.i386 (for 32 bit)
% sudo yum install indimail.x86_64 (for 64 bit)

The above should install IndiMail

5. Shutdown MySQL if already running and disable MySQL being started up by the system

% /etc/init.d/mysqld stop
% sudo chkconfig mysqld off
% /bin/rm -f /service/mysql.3306/down

6. Start IndiMail
% sudo service indimail start

7. Check if everthing is fine by running the svstat command
% sudo /var/indimail/bin/svstat /service/*
/service/clamd: up (pid 1579) 1028 seconds
/service/fetchmail: up (pid 1578) 1028 seconds
/service/freshclam: up (pid 1584) 1028 seconds
/service/greylist.1999: up (pid 1581) 1028 seconds
/service/indisrvr.4000: up (pid 1570) 1028 seconds
/service/inlookup.infifo: up (pid 1568) 1028 seconds
/service/mysql.3306: up (pid 1555) 1029 seconds
/service/proxy-imapd.4143: up (pid 1549) 1029 seconds
/service/proxy-imapd-ssl.9143: up (pid 1548) 1029 seconds
/service/proxy-pop3d.4110: up (pid 1554) 1029 seconds
/service/proxy-pop3d-ssl.9110: up (pid 1583) 1028 seconds
/service/pwdlookup: up (pid 1580) 1028 seconds
/service/qmail-imapd.143: up (pid 1576) 1028 seconds
/service/qmail-imapd-ssl.993: up (pid 1594) 1028 seconds
/service/qmail-pop3d.110: up (pid 1597) 1028 seconds
/service/qmail-pop3d-ssl.995: up (pid 1577) 1028 seconds
/service/qmail-poppass.106: up (pid 1587) 1028 seconds
/service/qmail-qmqpd.628: down 1029 seconds
/service/qmail-qmtpd.209: up (pid 1564) 1029 seconds
/service/qmail-send.25: up (pid 1553) 1029 seconds
/service/qmail-smtpd.25: up (pid 1598) 1028 seconds
/service/qmail-smtpd.366: up (pid 1565) 1029 seconds
/service/qmail-smtpd.465: up (pid 1551) 1029 seconds
/service/qmail-smtpd.587: up (pid 1559) 1029 seconds
/service/qmail-spamlog: up (pid 1552) 1029 seconds
/service/qscanq: up (pid 3802) 29 seconds


8. Play with the system
Add a domain
% sudo /var/indimail/bin/vadddomain example.com password

Add a user
% sudo /var/indimail/bin/vadduser user01@example.com password

Send an email using SMTP
% swaks --to youremail@yourdomain --from user01@example.com --server localhost

Inject a mail locally
% cat /tmp/email.msg | mail -s "testing indimail" mbhangui@gmail.com you@yourdomain

9. Set up your .bash_profile and RTFM
PATH=$PATH:/var/indimail/bin:/var/indimail/sbin
MANPATH=$MANPATH:/var/indimail/man

% man indimail

10. Buy beer for Varra .. ;)

Sunday, July 24, 2011

Design Concepts -1

For people who have been involved in software projects, they will constantly hear the terms, High Level Design (HLD) and Low Level Design (LLD). So what are the differences between these 2 design stages and when are they respectively used ?

High – level Design(HLD):

It gives the overall System Design in terms of Functional Architecture and Database design. It designs the over all architecture of the entire system from main module to all sub module. This is very useful for the developers to understand the flow of the system. In this phase design team, review team (testers) and customers plays a major role. For this the entry criteria are the requirement document that is SRS. And the exit criteria will be HLD, projects standards, the functional design documents, and the database design document. Further, High level deign gives the overview of the development of product. In other words how the program is going to be divided into functions, modules, subdivision etc.


Low – Level Design (LLD):

During the detailed phase, the view of the application developed during the high level design is broken down into modules and programs. Logic design is done for every program and then documented as program specifications. For every program, a unit test plan is created. The entry criteria for this will be the HLD document. And the exit criteria will the program specification and unit test plan (LLD). The Low Level Design Document gives the design of the actual program code which is designed based on the High Level Design Document. It defines Internal logic of corresponding submodule designers are preparing and mapping individual LLD’s to Every module. A good Low Level Design Document developed will make the program very easy to be developed by developers because if proper analysis is made and the Low Level Design Document is prepared then the code can be developed by developers directly from Low Level Design Document with minimal effort of debugging and testing.

TAR command usgae in Linux/Unix

The tar command stands for "tape archive". It is the "standard" way to read and write archives (collections of files and whole directory trees).

Often you will find archives of stuff with names like stuff.tar, or stuff.tar.gz.  This is stuff in a tar archive, and stuff in a tar archive which has been compressed using the
gzip compression program respectively.

Chances are that if someone gives you a tape written on a UNIX system, it will be in tar format, and you will use tar (and your tape drive) to read it.

Likewise, if you want to write a tape to give to someone else, you should probably use tar as well.

Tar examples:

tar xv      Extracts (x) files from the default tape drive while listing (v = verbose) the file names to the screen.

tar tv      Lists the files from the default tape device without extracting them.

tar cv file1 file2  Write files 'file1' and 'file2' to the default tape device.

tar cvf archive.tar file1 [file2...]   Create a tar archive as a file "archive.tar" containing file1, file2...etc.

tar xvf archive.tar  extract from the archive file

tar cvfz archive.tar.gz dname   Create a gzip compressed tar archive containing everything in the directory 'dname'. This does not work with all versions of tar.

tar xvfz archive.tar.gz  Extract a gzip compressed tar archive.  Does not work with all versions of tar.

tar cvfI archive.tar.bz2 dname Create a bz2 compressed tar archive. Does not work with all versions of tar

Thursday, July 14, 2011

Use primitives instead of wrappers

Overview

There are two good reason to use primitives instead of wrappers where possible.
  • Clarity. By using a primitive, you are making it clear that a null value is not appropriate.
  • Performance. Using primitives is often much faster.
Clarity is often more important than performance, and is the best reason to use them. However, this article discussed the performance implications of using wrappers.

I have had a lot of interest in this article How to avoid Garbage Collection, however this was lacking in much practical detail. This is the first article in a series on ways to reduce demands on the GC.

A followup article Low GC in Java: Using primitives looks at using primitives and collections which support them.

Performance of using wrappers

The following micro-benchmark behaves in a way many application do.
Loop using Wrappers and Wrapper Collection
Map<Integer, Integer> counters = new HashMap<Integer, Integer>();
int runs = 20 * 1000;
for (Integer i = 0; i < runs; i++) {
    Integer x = i % 12;
    Integer y = i / 12 % 12;
    Integer times = x * y;
    Integer count = counters.get(times);
    if (count == null)
        counters.put(times, 1);
    else
        counters.put(times, count + 1);
}
This creates objects for each task. While it is common practice to use int for loop counters its is also common practice to use Iterator You can play around with the types and parameters of this micro-benchmark, however you get a memory profile which will be familiar to many developers who have tried to tune their application. Using VisualVM the heap usage looks like this over a five minute period.
There was 20 minor GCs in about 6 minutes.
The average time of each loop is sub-microsecond which is pretty fast.

Took 4,099 ns per loop
Took 559 ns per loop
Took 115 ns per loop
Took 240 ns per loop
Took 255 ns per loop
In the first test, the JVM hasn't warmed up.

Can using primitives really make much difference?

Performance of using primitives

The following benchmark behaves rather differently to most applications. Even though it is doing the same work as the previous benchmark, there is no objects created.
Loop using Primitives and array
int[] counters = new int[144];
int runs = 20 * 1000;
for (int i = 0; i < runs; i++) {
    int x = i % 12;
    int y = i / 12 % 12;
    int times = x * y;
    counters[times]++;
}
and the heap usage reflects this
There was no GCs over a period of 5 minutes. The test could have run longer and still not triggered a GC.
And the average time per loop is much lower as well

Took 198 ns per loop
Took 17 ns per loop
Took 16 ns per loop
Took 14 ns per loop
Took 15 ns per loop
In the first test, the JVM hasn't warmed up.

Conclusion

Using primitives will perform better. (Unless there is excessive boxing and unboxing)

Even in applications where performance is not critical, it will improve clarity, both of the code and when you do attempt to profile your application, it will reduce the level of "noise" making it clearer as to what the problem is.

Notes

Even in the test where few objects were created, you can see some object allocation. This is mostly due to VisualVM's polling. To reduce this I changed the polling interval from 3 seconds to 20 seconds.

The Eden size was increased to make the graphs clearer with -XX:NewSize=100m This value is not recommend (except perhaps for micro-benchmarks) but its is a parameter you may need to tune for your application.

Full code

Primitive benchmark
Wrapper benchmark

Wednesday, July 13, 2011

Thread Synchronization

What is Thread Synchronization?
In a multithreaded environment, each thread has its own local thread stack and registers. If multiple threads access the same resource for read and write, the value may not be the correct value. For example, let's say our application contains two threads, one thread for reading content from the file and another thread writing the content to the file. If the write thread tries to write and the read thread tries to read the same data, the data might become corrupted. In this situation, we want to lock the file access. The thread synchronization has two stages. Signaled and non-signaled.
The signaled state allows objects to access and modify data. The non-signaled state does allow accessing or modifying the data in the thread local stack.
Thread Synchronization methods:
Many of the thread synchronization methods are used to synchronize multiple threads. The following methods are used to synchronize between objects.
Thread Synchronization on different processes:
Event:
Event is a thread synchronization object used to set the signaled or non-signaled state. The signaled state may be manual or automatic depending on the event declaration.
Mutex:
Mutex is the thread synchronization object which allows to access the resource only one thread at a time. Only when a process goes to the signaled state are the other resources allowed to access.
Example:
Mutex is a key to a meeting room. One person can have the key - occupy the meeting room - at the time. When finished, the person gives (frees) the key to the next person in the queue.
(A mutex is really a semaphore with value 1.)
Semaphore:
Semaphore is a thread synchronization object that allows zero to any number of threads access simultaneously.
Example:
Semaphore is the number of free identical keys. Example, say we have four meeting room with identical locks and keys. The semaphore count - the count of keys - is set to 4 at beginning (all four meeting rooms are free), then the count value is decremented as people are coming in. If all meeting rooms are full, ie. there are no free keys left, the semaphore count is 0. Now, when eq. one person leaves the meeting room, semaphore is increased to 1 (one free key), and given to the next person in the queue.
Thread Synchronization in same process:
Critical Section
The critical section is a thread synchronization object. The other synchronization objects like semaphore, event, and mutex are used to synchronize the resource with different processes. But, the critical section allows synchronization within the same process.

Tuesday, July 12, 2011

The Great SSH Config.!

The SSH server configuration file is located in /etc/ssh/sshd_conf.
You need to restart the SSH service after every change you make to that 
file in order for changes to take effect.

*Change SSH listening port*

By default, SSH listens for connections on port 22. Attackers use port 
scanner software to see whether hosts are running an SSH service. It's 
wise to change the SSH port to a number higher than 1024 because most 
port scanners (including nmap) by default don't scan high ports.

Open the /etc/ssh/sshd_config file and look for the line that says:

Port 22

Change the port number and restart the SSH service:

/etc/init.d/ssh restart

*Allow only SSH protocol 2*

There are two versions of the SSH protocol. Using SSH protocol 2 only is 
much more secure; SSH protocol 1 is subject to security issues including 
man-in-the-middle and insertion attacks. Edit /etc/ssh/sshd_config and 
look for the line that says:

Protocol 2,1

Change the line so it says only protocol 2.

*Allow only specific users to log in via SSH*

You should not permit root logins via SSH, because this is a big and 
unnecessary security risk. If an attacker gains root login for your 
system, he can do more damage than if he gains normal user login. 
Configure SSH server so that root user is not allowed to log in. Find 
the line that says:

PermitRootLogin yes

Change yes to no and restart the service. You can then log in with any 
other defined user and switch to user root if you want to become a 
superuser.

It is wise to create a dummy local user with absolutely no rights on the 
system and use that user to login into SSH. That way no harm can be done 
if the user account is compromised. When creating this user, make sure 
it's in the wheel group, so that you can switch to superuser.

If you would like to have a list of users who are the only ones able to 
log in via SSH, you can specify them in the sshd_config file. For 
example, let's say I want to allow users anze, dasa, and kimy to log in 
via SSH. At the end of sshd_config file I would add a line like this:

AllowUsers anze dasa kimy

*Create a custom SSH banner*

If you would like any user who connects to your SSH service to see a 
specific message, you can create a custom SSH banner. Simply create a 
text file (in my example in /etc/ssh-banner.txt) and put any kind of 
text message in it; for example:

*****************************************************************
*This is a private SSH service. You are not supposed to be here.*
*Please leave immediately. *
*****************************************************************

When done editing, save the file. In the sshd_conf file, find a line 
that says:

#Banner /etc/issue.net

Uncomment the line and change the path to your custom SSH banner text file.

The Grep Filter.!

Search content of text files for matching patterns. It is definitely worth learning at least the basics of this command.
A simple example. The command:
cat * | grep my_word | more
will search all the files in the current working directory (except files starting with a dot) and print the lines which contain the string "my_word".
A shorter form to achieve the same may be:
grep my_word * |more
The patterns are specified using a powerful and standard notation called "regular expressions".
There is also a "recursive" version of grep called rgrep. This will search all the files in the current directory and all its subdirectories for my_word and print the names of the files and the matching line:
rgrep -r my_word . | more

The Bug in the programming Language..!

What is Bug/Defect?
Simple Wikipedia definition of Bug is: “A computer bug is an error, flaw, mistake, failure, or fault in a computer program that prevents it from working correctly or produces an incorrect result. Bugs arise from mistakes and errors, made by people, in either a program’s source code or its design.”
Other definitions can be:
An unwanted and unintended property of a program or piece of hardware, especially one that causes it to malfunction.
or
A fault in a program, which causes the program to perform in an unintended or unanticipated manner.
Lastly the general definition of bug is: “failure to conform to specifications”.
If you want to detect and resolve the defect in early development stage, defect tracking and software development phases should start simultaneously.
We will discuss more on Writing effective bug report in another article. Let’s concentrate here on bug/defect life cycle.
Life cycle of Bug:
1) Log new defect
When tester logs any new bug the mandatory fields are:
Build version, Submit On, Product, Module, Severity, Synopsis and Description to Reproduce
In above list you can add some optional fields if you are using manual Bug submission template:
These Optional Fields are: Customer name, Browser, Operating system, File Attachments or screenshots.
The following fields remain either specified or blank:
If you have authority to add bug Status, Priority and ‘Assigned to’ fields them you can specify these fields. Otherwise Test manager will set status, Bug priority and assign the bug to respective module owner.
Look at the following Bug life cycle:

[Click on the image to view full size] Ref: Bugzilla bug life cycle
The figure is quite complicated but when you consider the significant steps in bug life cycle you will get quick idea of bug life.
On successful logging the bug is reviewed by Development or Test manager. Test manager can set the bug status as Open, can Assign the bug to developer or bug may be deferred until next release.
When bug gets assigned to developer and can start working on it. Developer can set bug status as won’t fix, Couldn’t reproduce, Need more information or ‘Fixed’.
If the bug status set by developer is either ‘Need more info’ or Fixed then QA responds with specific action. If bug is fixed then QA verifies the bug and can set the bug status as verified closed or Reopen.
Bug status description:
These are various stages of bug life cycle. The status caption may vary depending on the bug tracking system you are using.
1) New: When QA files new bug.
2) Deferred: If the bug is not related to current build or cannot be fixed in this release or bug is not important to fix immediately then the project manager can set the bug status as deferred.
3) Assigned: ‘Assigned to’ field is set by project lead or manager and assigns bug to developer.
4) Resolved/Fixed: When developer makes necessary code changes and verifies the changes then he/she can make bug status as ‘Fixed’ and the bug is passed to testing team.
5) Could not reproduce: If developer is not able to reproduce the bug by the steps given in bug report by QA then developer can mark the bug as ‘CNR’. QA needs action to check if bug is reproduced and can assign to developer with detailed reproducing steps.
6) Need more information: If developer is not clear about the bug reproduce steps provided by QA to reproduce the bug, then he/she can mark it as “Need more information’. In this case QA needs to add detailed reproducing steps and assign bug back to dev for fix.
7) Reopen: If QA is not satisfy with the fix and if bug is still reproducible even after fix then QA can mark it as ‘Reopen’ so that developer can take appropriate action.
8 ) Closed: If bug is verified by the QA team and if the fix is ok and problem is solved then QA can mark bug as ‘Closed’.
9) Rejected/Invalid: Sometimes developer or team lead can mark the bug as Rejected or invalid if the system is working according to specifications and bug is just due to some misinterpretation.

Friday, July 8, 2011

Getting the size of an Object

Overview

Java was designed with the principle that you shouldn't need to know the size of an object. There are times when you really would like to know and want to avoid the guess work.

Measuring how much memory an object uses

There are three factors which make measuring how much an object uses difficult.
  • The TLAB allocates blocks of memory to a thread.  This means small amount of memory don't appear to reduce the free memory. If you do this repeatedly, you will see a block of free memory be used. The way around this is to turn off the TLAB. -XX:-UseTLAB
  • A GC can occur while you are creating your object. This will result in more free memory at the end than when you started. I ignore any negative sizes in this test ;)
  • Other threads in the system could use memory at the same time. I perform multiple test and take the median, which removes any outliers.

Size of objects in a 32-bit JVM


Running this SizeofTest, with on 32-bit Sun/Oracle Java 6 update 26, -XX:-UseTLAB I get

The average size of an int is 4.0 bytes
The average size of an Object is 8.0 bytes
The average size of an Integer is 16.0 bytes
The average size of a Long is 16.0 bytes
The average size of an AtomicReference is 16.0 bytes
The average size of an SimpleEntry(Map.Entry) is 16.0 bytes
The average size of a DateTime is 24.0 bytes
The average size of a Calendar is 424.0 bytes
The average size of an Exception is 400.0 bytes
The average size of a bit in a BitSet is 0.125 bytes

Looking a the size of Long confirms the size of header/Object being 8 bytes.

Size of objects with 32-bit references

Running this SizeofTest, with 32-bit references On Sun/Oracle Java 6 update 26, -XX:+UseCompressedOops -XX:-UseTLAB I get
The average size of an int is 4.0 bytes
The average size of an Object is 16.0 bytes
The average size of an Integer is 16.0 bytes
The average size of a Long is 24.0 bytes
The average size of an AtomicReference is 16.0 bytes
The average size of an SimpleEntry(Map.Entry) is 24.0 bytes
The average size of a DateTime is 24.0 bytes
The average size of a Calendar is 448.0 bytes
The average size of an Exception is 440.0 bytes
The average size of a bit in a BitSet is 0.125 bytes

Objects are 8-byte aligned on this JVM, and you could conclude from the size of an Integer that the header is 12-bytes in size.

Size of objects with 64-bit references

Running the same test with 64-bit references. i.e. -XX:-UseCompressedOops -XX:-UseTLAB
The average size of an int is 4.0 bytes
The average size of an Object is 16.0 bytes
The average size of an Integer is 24.0 bytes
The average size of a Long is 24.0 bytes
The average size of an AtomicReference is 24.0 bytes
The average size of an SimpleEntry(Map.Entry) is 32.0 bytes
The average size of a DateTime is 32.0 bytes
The average size of a Calendar is 544.0 bytes
The average size of an Exception is 648.0 bytes
The average size of a bit in a BitSet is 0.125 bytes
From looking at the size of a Long, confirms the size of the header/Object is 16 bytes in length.

The code for the SizeofUtil

The code for the SizeofUtil is here

Thursday, July 7, 2011

Deploying Web Applications.!

Deploying Web Applications:

A Java servlet/JSP engine is not really useful without servlets and JSPs, and deploying servlets can sometimes be a difficult and error-prone process, because, in addition to writing and compiling the servlet, you will need to edit at least 2 XML files to get the servlet properly deployed. I will cover the manual method here, but there are other ways, such as using the Manager Web Application or developing an Ant build process. There is also a deployer package that you can download. I don't know how to use it though. If you do know, please email me!

We will write and compile a simple "HelloWorld" servlet and deploy it, using this example to "bootstrap" future deployments. We need to test if the deployment environment is properly setup, and try out some customization features, so we will keep our first servlet simple to familiarize ourselves with the process.

1. Creating the HelloWorld Servlet

First, open your favorite text editor or Java IDE and create the following file :

Example 1. HelloWorld Servlet

// Filename : HelloWorld.java
// Description : This servlet merely says hello!


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloWorld extends HttpServlet {

        public void doGet ( HttpServletRequest request, HttpServletResponse response )
        throws ServletException, IOException    {

                response.setContentType("text/html");
                PrintWriter out = response.getWriter();

                out.println("<html>");
                out.println("<head><title>Hello, Cruel World!</title></head>");
                out.println("<body>");
                out.println("<h1>Hello, Cruel World !</h1>");
                out.println("This is my first servlet.");
                out.println("</body>");
        }// end doGet

}///:~

Now, we save the file as HelloWorld.java and compile it. Here, you will find the first of several differences between Tomcat 4 and Tomcat 5.
If you're like me, you normally use the servlet classes supplied by Tomcat to compile your servlets, take note that the filename of the package has changed : it is now called servlet-api.jar, not servlet.jar, as it was previously.
( Am I wrong ? Let me know ! )
If you don't know what I'm talking about, just compile the servlet using the following command:


# javac -classpath $CATALINA_HOME/common/lib/servlet-apijar HelloWorld.java
To avoid having to key in the "classpath" switch every time, just include the servlet-api.jar package inside your CLASSPATH. That is,

export CLASSPATH=$CLASSPATH:$CATALINA_HOME/common/lib/servlet-api.jar
Your servlet should compile cleanly without errors, but if you do, check the syntax in your source code. If you just cut and pasted my code above, you should not get any errors.
If your compile completed successfully, you should see a file called HelloWorld.class inside the same directory. You are now ready to proceed to deploying your first servlet.

2. Deploying "HelloWorld"

2.1. Creating the directory structure

Before you begin deployment, you will need to create a directory structure under the $CATALINA_HOME/webapps directory that conforms to the servlet specifications. For our example "HelloWorld" servlet, we are going to create a directory called "MyFirst", and we are going to save our "HelloWorld" servlet under that directory.
As tomcat user,

$ cd $CATALINA_HOME/webapps
$ mkdir MyFirst
$ mkdir MyFirst/WEB-INF
$ mkdir MyFirst/WEB-INF/classes
$ mkdir MyFirst/WEB-INF/lib

You should get a directory structure similar to the one below:


Directory structure of a new web application



A little explanation may be helpful at this point. The directory structure is important to the servlet engine. The purposes of the various directories are shown below :

Table 4-1. Web Application Directory Structure

/MyFirst This is the web applications root directory. This is analogous to a directory in the Apache webserver, in that you will put your static HTML files, image files (gif, jpg, etc.) and JavaServer Pages (JSPs) here. If you have an index.html file in this directory, the URL used in a browser to view it is http://hostname.domain.com:8080/MyFirst/index.html. You can create a subdirectory here that stores other HTML files or image files.
/MyFirst/WEB-INF This is where your web application's configuration file web.xml will go.
/MyFirst/WEB-INF/classes This is where the servlets that make up your web application should be copied or saved.
/MyFirst/WEB-INF/lib If your application requires additional support libraries, for example JDBC drivers, they should be copied here.
To illustrate this graphically, our final web application should be laid out as shown below:


Directory structure of a new web application



4.2.2. Creating the Context Descriptor file


This section has been revised and is different from older versions of this document. See this Appendix for an explanation of the changes.

The context descriptor file, according to the Tomcat official documentation, is "used to define Tomcat specific configuration options, such as loggers, data sources, session manager configuration and more".
The file follows an XML syntax, and the name of the file is always the name of the web application, with a .xml extension. So, for this application, called MyFirst, the name of the context descriptor is MyFirst.xml.
Create a file called MyFirst.xml with the following contents:


<!-- MyFirst Context -->
<Context path="/MyFirst" docBase="MyFirst" debug="0" reloadable="true"/>
Save the file into $CATALINA_HOME/conf/Catalina/localhost/ directory.
With much older versions of Tomcat, such as the early Tomcat 3.x series or 4.0.x series, you had to add the <Context> definitions inside server.xml. If you are reading an older version of my article, you may notice that I still described the server.xml method. With Tomcat 5.x, the context descriptor provides a cleaner separation of web application configuration and the main Tomcat server configuration. An added benefit is that web applications deployed in this way do not require a stop and restart of the Tomcat server process. Tomcat should automatically pick it up while it is still running.

4.2.3. Creating a web.xml file for the web application

The file web.xml is sometimes known as a deployment descriptor, and it is basically the configuration file for your web application. In this file, you determine, among other things :

  • the URL of the servlets in your web application

  • the authentication method you wish to use

  • Your filter definitions

For now, we will simply register HelloWorld as a servlet in the web application called MyFirst. We create a new web.xml file with the following contents inside it :

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

<servlet>
        <servlet-name>HelloWorld</servlet-name>
        <servlet-class>HelloWorld</servlet-class>

</servlet>

<servlet-mapping>
        <servlet-name>HelloWorld</servlet-name>
        <url-pattern>/HelloWorld</url-pattern>
</servlet-mapping>

</web-app>
You will notice that we had to do two things here :

  • Associate the servlet class file (in this case, HelloWorld.class) with a handler (HelloWorld)

  • Define how the servlet is accessed via a URL
In previous releases of Tomcat, if you did not define the <servlet-mapping> element, you could still invoke the servlet by typing http://hostname.domain.com/MyFirst/servlet/HelloWorld. As of version 4.1.18, this option is turned off, and you will have to define your servlet's URI.
In the web.xml file we just created, we told Tomcat that the servlet called HelloWorld.class is referred to as HelloWorld, and that the URL by which this servlet is to be referred to is http://hostname.domain.com:8080/MyFirst/HelloWorld.

4.2.4. Copying the servlets, JSPs and support files to their respective directories

Now we can copy the Java class file that we compiled earlier, into the deployment directory. Because this is a servlet, it will go into $CATALINA_HOME/webapps/MyFirst/WEB-INF/classes directory. There is no need to copy the source file into that directory.
For more complicated deployments, such as servlets that require additional classes, such as JDBC drivers, or libraries, these additional files must be stored inside the /WEB-INF/lib subdirectory of the web application directory. If you wish to make these libraries available to all web applications in Tomcat, save them inside $CATALINA_HOME/common/lib/ directory.
For JavaServer Pages (JSPs), the *.jsp files go in the same directory as the static HTML files, that is, under $CATALINA_HOME/webapps/My_Web_Application/.

4.3. Saying "HelloWorld"

Testing your servlet
We are now ready to test our HelloWorld servlet. Since this is the first servlet we are testing, and we are not really sure what we will see, I strongly advise going into X Windows and opening several terminal windows to display error and information messages, as they occur. Here's how we're going to test and see if our Tomcat deployment can indeed say "HelloWorld" !

  1. Start X Windows and the desktop environment of your choice.

  2. Log in as root


  3. Open 3 terminal windows

  4. In the first terminal window, execute the following commands :

    # cd $CATALINA_HOME/bin
    # ./startup.sh
    
    

  5. In the second terminal window, execute the following commands :

    # cd $CATALINA_HOME/logs
    # tail -f catalina.out
    
    
    This will display the messages that Tomcat writes to the log file catalina.out, which is automatically created, if it does not already exist.

  6. In the third terminal window, execute the following commands :

    # cd $CATALINA_HOME/logs
    
    # tail -f localhost_log.YYYY-MM-DD.txt
    
    substitute YYY-MM-DD with the date (for example : 2003-02-11)
As Tomcat starts up, you can see the messages it writes to the 2 log files ('tail -f' opens the terminal window in a kind of console mode, so you can see events as they happen) . If there are any errors, they will be reflected, sometimes in a very verbose fashion. Take note of the errors, if there are any, and report them on the mailing list, if you cannot solve it yourself.
If Tomcat started without errors (or even if it did have errors), we can test the servlet with our browser.

Checking with a browser

  1. Open Netscape or Mozilla on the local machine

  2. For the URL, key in : http://localhost:8080/MyFirst/HelloWorld

  3. You should see a web page that says, very emphatically, "Hello, Cruel World !". If you see that, then, congratulations ! Your first servlet was successfully deployed !

4.4. Deploying Java Server Pages

This operation is actually quite straightforward. However, from the amount of email I get asking me about this, I thought I'd add a section on this topic.
Deploying JSPs is simpler than deploying web applications. You will still need to do many of the steps outlined above. But you do not need to define your JSP file inside the deployment descriptor, web.xml. If you did not work through the previous example, I strongly urge you to. It will help in your understanding. A summary of steps you need to do to deploy JSPs is shown below:
Deploying JSPs

  1. Install Tomcat


  2. Create a directory structure for your web application

  3. Add a context entry inside server.xml

  4. Create the JSP file

  5. Copy the JSP file to the appropriate directory (i.e. $CATALINA_HOME/webapps/[application_name]/)

For the sake of continuity, I am going to assume you did the previous exercise. To begin, let us create a simple JSP that displays a date and a link to the servlet we created earlier. The source code is shown below:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Hello JSP World!</title>

</head>
<body>
<h1>Hello, JSP World!</h1>

<p>
The time now is : <%= new java.util.Date() %>. 
</p>

<p>
To see the servlet example <a href="HelloWorld">click here</a>.
</p>

</body>
</html>
</programlisting>
After we have created the file, we will save it as index.jsp and we will deploy it by copying it to the web application directory. Recall that the web application directory consists of the following directory structure:

Directory structure of a new web application



We copy the JSP file (and subsequent JSP files) into /opt/tomcat/webapps/MyFirst directory. Not the classes directory -- that is for servlets!

After we copy the file into the directory, we can test it by simply starting up Tomcat and entering the following URL: http://localhost:8080/MyFirst/index.jsp.
You should see a delay, then the page will appear. The delay is caused by Tomcat compiling the JSP, then returning the results to the browser. You can actually pre-compile JSPs to reduce the delay by using the jspc.sh utility in Tomcat. To execute, simply supply the name of the JSP you wish to compile to the utility like so,

# cd $CATALINA_HOME/bin

# ./jspc.sh $CATALINA_HOME/webapps/MyFirst/index.jsp