Monday, June 6, 2011

Configure Timeout for Apache HttpClient 4.0

Adding HTTP request timeout support to HttpClient 4.0  of Appache is quite an easy task. But not as straight forward as one might think. I needed to add such timeout for one of my HTTP requests. I expected to have a method named: "setTimout" or "setConnectionTimeout". But couldn't find any method regarding timeout. After a little digging I found how it can be done. Hope it will save you some time.
In general, all you have to do is create an instance of HttpParams and use it in order to define the connection timeout.
Let's see how the code looks:
package com.bashan.blog.http;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
/**
 * @author Bashan
 */
public class HttpRequest {
  public static void main(String[] args) throws Exception {
    // Set connection timeout
    HttpParams params = new BasicHttpParams();
    HttpConnectionParams.setConnectionTimeout(params, 5000);
    HttpConnectionParams.setSoTimeout(params, 5000);
    HttpClient httpClient = new DefaultHttpClient(params);
    HttpResponse response = httpClient.execute(new HttpGet("http://google.com"));
    System.out.print(EntityUtils.toString(response.getEntity()));
  }
}

You can see in the 3 lines marked in yellow, how the HttpParams class is used in order to define the connection timeout. Later an HttpClient instance is created with params that is passed to it.


You can download this class here.

Friday, May 27, 2011

Show timer with seconds using NSTimer on iPhone and Objective C

I am currently developing an iPhone App using X-Code and Objective-C. I had to show a simple timer showing the elapsed number of seconds and minutes. I don’t know much about Objective-C, but from my past experience I knew this task can be easily accomplished using a Timer. The timer should be called every second, and a simple int variable will hold the seconds. The variable is incremented on every call of the timer.
This is how I the timer is defined:
NSTimer *mainTimer = [NSTimer scheduledTimerWithTimeInterval:1 
                  target:self 
                  selector:@selector(timerController) 
                  userInfo:nil 
                  repeats:YES];

Note that the timer is set to be activated every one second and the function that will be called every one second is named “timerController”.

In the “timerController” function I wrote the code that will increment the seconds variable as well as update a label on the screen. In order to update the label with the minutes and seconds I wrote a small function. The function gets seconds and returns a string of the format: “mm:ss” (for example, for input of 90 the function will return: “01:30”. Let’s see the function that returns the time:


- (NSString*)getTimeStr : (int) secondsElapsed {
  int seconds = secondsElapsed % 60;
  int minutes = secondsElapsed / 60;
  return [NSString stringWithFormat:@"%02d:%02d", minutes, seconds];
}

And let’s have a look at the “timeController” function that use it:


- (void)timerController {
  seconds++;
  [[self timeLabel] setText:[self getTimeStr]];
}

The “timeLable” is a UILabel control that is connected with a label that is show on the iPhone screen.


Thursday, May 26, 2011

Add Facebook Like Button to your Blogger.com (BlogSpot)

Facebook Like button is a great and easy way of sharing things that you like with your friends. If you have a blog on Blogger.com (BlogSpot) you can easily add a Facebook like button to any of your posts. Each post will have it's own Like button. This can help increasing the traffic of your blog.

Let's see how we can easily add Facebook like button:

Step 1: Editing out blog template as HTML:

  • press on: "Design" on your blog main menu.
  • Then press on "Edit HTML" on the upper sub menu.
  • Check "Expand Widget Templates" checkbox.
Step 2: Find the place in which Facebook Like button code should be entered:
Search for the String:
<data:post.body/>
Facebook Like button should be placed before this code.

Step 3: Put the following code in your blog template:
<b:if cond='data:blog.pageType == &quot;item&quot;'>
<iframe allowTransparency='true' expr:src='&quot;http://www.facebook.com/plugins/like.php?href=&quot; + data:post.url + &quot;&amp;layout=standard&amp;show_faces=false&amp;width=100&amp;action=like&amp;font=arial&amp;colorscheme=light&quot;' frameborder='0' scrolling='no' style='border:none; overflow:hidden; width:450px; height:40px;'/>
</b:if>

After you save your template, go to one of your posts. You could see that a Facebook Like button was added right under the name of your post.

Monday, May 16, 2011

Log4j SMTPAppender and deadlocks - Adding Timeout support

On the post: Sending Email alerts with Log4j we saw how we can easily send mails whenever our system has an exception. But we have to remember that using Apache Log4j SMTPAppender, can be very risky if not used cautiously. In general, the Log4j SMTPAppender has 2 main problems:

  1. The part that send the mail, is synchronous. In fact, it is synchronous between all Log4j appenders. It means that when you log an error and a mail is being sent, all log commands are locked. This is quite risky. Especially when your system has many errors (for whatever reason). This may cause your whole system to get stuck. This issue can be easily handled by using: AsyncAppender. I may write about AsyncAppender in more detail in the future.
  2. The code responsible for sending the mail, which is written by Apache developers, doesn't has a Timeout. That mean, a mail being sent can be stuck forever and simply cause your entire system to go into a deadlock.
    In this post, we will improve the Apache SMTPAppender to include a Timeout property. The Timout property will make sure, that if a mail is being sent using SMTP connection for too long, it will be dropped. We may loose a report about an exception, but we will make sure our system won't be stuck indefinitely.


We will create a new class name: SMTPAppenderTimeout, that extends SMTPAppender. This new class will override the SMTPAppender method: createSession.
The new createSession method will make sure to add the following 2 properties to the mail session: 

  • mail.smtp.connectiontimeout
  • mail.smtp.timeout


These 2 properties instruct the Java mail framework to set a timeout on the SMTP connection.
Let's have a look on the SMTPAppenderTimeout class:

package com.bashan.blog; 
import org.apache.log4j.net.SMTPAppender; 
import javax.mail.Authenticator; 
import javax.mail.PasswordAuthentication; 
import javax.mail.Session; 
import java.util.Properties; 
/** 
* @author Bashan 
*/ 
public class SMTPAppenderTimeout extends SMTPAppender { 
  private int timeout; 
  public int getTimeout() { 
    return timeout; 
  } 
  public void setTimeout(int timeout) { 
    this.timeout = timeout; 
  } 
  @Override 
  protected Session createSession() { 
    Properties props; 
    try { 
      props = new Properties(System.getProperties()); 
    } catch (SecurityException ex) { 
      props = new Properties(); 
    } 
    if (timeout > 0) { 
      String timeoutStr = Integer.toString(timeout); 
      props.setProperty("mail.smtp.connectiontimeout", timeoutStr); 
      props.setProperty("mail.smtp.timeout", timeoutStr); 
    } 
    if (getSMTPHost() != null) { 
      props.put("mail.smtp.host", getSMTPHost()); 
    } 
    Authenticator auth = null; 
    if (getSMTPPassword() != null && getSMTPUsername() != null) { 
      props.put("mail.smtp.auth", "true"); 
      auth = new Authenticator() { 
        protected PasswordAuthentication getPasswordAuthentication() { 
          return new PasswordAuthentication(getSMTPUsername(), getSMTPPassword()); 
        } 
      }; 
    } 
    Session session = Session.getInstance(props, auth); 
    if (getSMTPDebug()) { 
      session.setDebug(getSMTPDebug()); 
    } 
    return session; 
  } 
} 

You can also download the SMTPAppenderTimeout.



Let's see an example of a log4j.xml file which use SMTPAppenderTimeout to allow timeout of 5 seconds (5000ms):       


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
	
	<appender name="RollFile" class="org.apache.log4j.RollingFileAppender">
		<param name="File" value="C:\\testlog.txt" />
		<param name="MaxFileSize" value="10MB" />
		<param name="MaxBackupIndex" value="1" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%d{HH:mm:ss} %-5p [%c{1}]: %m%n" />
		</layout>
	</appender>
	<appender name="Email" class="com.bashan.blog.SMTPAppenderTimeout">
		<param name="BufferSize" value="10" />
		<param name="SMTPHost" value="smtpout.secureserver.net" />
		<param name="SMTPUsername" value="test_user" />
		<param name="SMTPPassword" value="test_password" />
		<param name="Timeout" value="5000" />
		<param name="From" value="someone@mail.com" />
		<param name="To" value="bashan@mail.com" />
		<param name="Subject" value="System Error Notification" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%d [%t] %-5p %c %x - %m%n" />
		</layout>
	</appender>
	
	<root>
		<priority value="info" />
		<appender-ref ref="RollFile" />
		<appender-ref ref="Email" />
	</root>
</log4j:configuration>

You can also download the log4j.xml.




Sunday, April 24, 2011

Nikon D7000 vs Nikon D300 or should I wait for the Nikon D400?

I was waiting for the Nikon D400 to come out for too long. It has been more than 4 years since I bought my Nikon D300. I love this camera. But it has gotten too old. I wanted something new and the Nikon D400 doesn’t seem to show any signs of coming out. So I got tired of waiting, and just bought the Nikon D7000. I wanted to share some of my feelings of my new Nikon D7000 and do a small comparison with my good and old Nikon D300, so those of you who own the Nikon D300 could have an easier decision regarding purchasing the Nikon D7000. So, before comparing the Nikon D7000 and Nikon D300, I can spare you from reading and tell you that I simply love my new Nikon D7000 and I do recommend you go and buy one. If you own a Nikon D300, you won’t regret it. Although the Nikon D7000 is less pro, it’s newer technology definitely puts it in a better place than Nikon D300 and even Nikon D300s and all for that for less price. OK, so let’s start to see what is so good on the Nikon D7000:

Focus System:

Nikon D300 has 51 focus points from which 15 are cross-type. 51 focus points are a lot, and the Nikon D300 has great focus system. It is fast, accurate and allows you to do continuous and even tracking focus. But, although the Nikon D7000 has less focus points: 39 from which 9 are cross-type, it has very fast and accurate focus system. I think even faster and better than the one of the Nikon D300. You don’t have anything to worry about, all the focus options from the Nikon D300 exist in the Nikon D7000.

Controls:

That’s one of the things I worried about when I wanted to buy the Nikon D7000. After so much time that I got used to all the fast and easy on-camera controls of the Nikon D300, I worried that I will really miss them on the Nikon D7000. Well, now that I got the Nikon D7000, I can tell you that I don’t miss those buttons much. I mean, it was nice to have these buttons there, but you can easily manage without them on the Nikon D7000. Switching the ISO (I usually choose the ISO manually), White Balance (I almost never change it from Automatic), and metering mode are all all done same as the Nikon D90/D80. But, there is a new button, placed on the focus AF/M selection switch. This new button along with the two front and back wheels allows you to quickly and easily select your desired focus mode. This new cool button, makes it easier to forget those loveable focus switches on the Nikon D300.

Viewfinder:

The Nikon D7000 has 100% viewfinder coverage. comparing to the 95% viewfinder coverage of the Nikon D300, you can see entirely what you are going to shoot. It’s the first time I am using a 100% coverage viewfinder and I like it. Better image

Quality:

The Nikon D7000 has better image quality. You have to look at the results and decide for yourself. In my opinion the results are better. Although the Nikon D7000 has 16.2 MP sensor (comparing to the Nikon D300), the image quality is better at all ISO ranges. A sensor containing more pixels, means smaller pixels. Smaller pixels mean more noise at higher ISOs. But the D7000 seems to be dealing better with noise than the D300. The Nikon D7000 has better color depth: 24bit comparing to 22bit. That’s about x2.5 more colors. In addition, the Nikon D7000 has better dynamic range: 14EV comparing to 12EV of the Nikon D300. That’s more 2 f-stops on the D7000.

Continuous Shooting:

The Nikon D300 shoots 7 frames per second. The Nikon D7000 shoots 6 frames per second. That makes the Nikon D300 a bit better when it comes to continuous shooting. There are times when continuous shooting can be a great help, but the difference between 6 to 7 frames per second is not that big. In addition, when you set the Nikon D300 D-Lightning feature, or you set your ISO to be 800 or higher (when high ISO cleaning option is turned on), the processing is too slow, so after about 8 photos, the shooting rate goes down dramatically. The D7000 doesn’t seem to suffer from this issue.

Shutter Noise:

One of the most annoying things of the Nikon D300 is it’s shutter noise. This is really an extreme noise. I don’t know how Nikon released a camera with such a strong shutter noise. Well, on the Nikon D7000 you don’t have to worry about noise. The shutter makes much less noise, even when shooting continuously. If you want even less noise you have a special “quite” mode that will reduce the noise even further.

Memory Slots:

The Nikon D7000 has 2 memory slots. Additional memory slot means more memory. More memory means you can store more photos. This is good when you shoot on RAW mode which takes considerably more space for each photo, or you shoot 1080p video which takes a lot of space. You can also use the 2 slots to function as backup (each photo is stored on 2 cards). Video: Well, I don’t shoot video. But with the Nikon D7000 you can easily shoot 1080p Video with 24 fps. You shoot the video using your good Nikon lenses, so you can get great results with shallow depth of field. The video is shown on the back screen and there is an automatic focusing system that can identify faces. It is working very nice. You can also edit the video on the camera.

Size and Weight:

The Nikon D7000 is smaller in size and lighter in weight than the Nikon D300, but it still has a strong grip and it feels good in your hands. It is not well built as the Nikon D300, but it still has a very satisfying built quality Price: Event today, after more than 4 years that the Nikon D300 exists in the market (I believe Nikon has already stopped producing it), it is sold for about more than $200 than the Nikon D7000.

Summary:

I own the Nikon D7000 for only 2 days. I have taken with it only 200 photos. It may be a short period for solid opinion, but so far I am very satisfied with it. If you own a Nikon D300 or Nikon D300s I think the Nikon D7000 is a good upgrade choice for a decent price. Since the Nikon D400 is still not on the horizon (with the recent earthquake on Japan, it will probably event take longer), and it seems like it is going to be with the same sensor of the Nikon D7000 but with more focus points and stronger body, I think it is not worth the time and money waiting for the Nikon D400.

Sunday, April 10, 2011

Check if Virtual Box / VMWare can run 64bit Operating Systems

VirtualBox and VMWare are great virtualization software allowing you to easily run virtual operating systems on your machine.

Creating a new virtual machine is an easy task. You create a new virtual machine, set some parameters and you are ready to go. You get a new place to install any operating system of your choice.

Sometime we would like to install 64bit operating system. 64bit operating system, can take advantage of 64bit machine and do some of the operations almost twice faster than 32bit. Todays modern computers are mostly support 64bits. If your machine support 64bit, it means you can install 64bit operating system on it. Buy, it doesn’t mean you can install 64bit operating in a virtual environment. In order to be able to run 64bit operating system on VirtualBox and VMWare you should have a machine that support it. Running a 64bit operating system in a virtual environment requires hardware level support.

VMWare made a small utility that helps you to check if your machine supports installing 64bit operating systems.

The tool is called: Processor Check for 64-Bit Compatibility and you can find on this link.

If your machine allows you to run 64bit operating systems on virtual machines you will get this message:

vmware-1

And if your if your machine doesn’t allow you to run 64bit operating systems on virtual machines you will get this message:

vmware-2

Note that I run this utility on 2 different machines, both are 64bit capable, both have Windows 7 64bit installed. One machine allows running 64bit operating systems on virtual machines and one doesn’t allow.

Tuesday, April 5, 2011

Convert image file .img to .iso

Both “.img” and “.iso” are file formats contains data packed together and ready to be burned.
I recently had to convert “.img” file to “.iso” file. after a little search I got to this small piece of software called Magic ISO.
After a small installation process and loading the application go to “Tools” and select “Convert…” from the menu:

magiciso1


The dialog is open, simply select the “.img” file you would like to convert and set a new directory to locate the outputed “.iso” file (only if you would like a different directory than the one of the “.img” file:

magiciso2

Wednesday, March 30, 2011

Automatically delete Tomcat access log old files

On the post Enable Tomcat acess log we saw how Tomcat can be easily configured to log all HTTP requests coming to our server.
For some reason, Tomcat doesn't have a mechanism that also makes sure to delete old access log files. This is a bit weird, because I assume that Tomcat is using Log4j in order to log the requests, and Log4j has a built in mechanism for rotating and deleting old log files.
Anyway, since Tomcat doesn’t take care of all these access log files that are being added, and since a typical production server may produce access log files of several giga per day, your disk might get out of space pretty quick.
we will build a small class that will handle old access log files deletion.
First, we need to get the following information:
  • Tomcat access log files directory.
  • Access log file structure. The default structure is: localhost_access_log.yyyy-MM-dd.txt
  • Access log date format: The default structure is: yyyy-MM-dd
  • Number of access log files we would like to keep as backup. For example, if we choose: 10 it means that we would like to keep the last 10 access log files.
The idea is very simply:
  • We get all access log files on the directory.
  • We extract the date of each log file.
  • We sort all the files on ascending order.
  • We delete the oldest files making sure to keep the requested number of backups.
Let’s have a look at our access log files deletion class. It’s code is quite simple:
package com.bashan.blog.log;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.File;
import java.io.FilenameFilter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Bashan
*/
public class TomcatAccessLogCleaner extends TimerTask {
  private static final Log log = LogFactory.getLog(TomcatAccessLogCleaner.class);
  private static final String DEFAULT_LOG_FILE_PATTERN = "localhost_access_log\\.yyyy-MM-dd\\.txt";
  private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
  private String dateFormat;
  private Pattern logFilePat;
  private File logFileDir;
  private int numBackups;
 
  public TomcatAccessLogCleaner(File logFileDir, int numBackups) {
    this(logFileDir, DEFAULT_LOG_FILE_PATTERN, DEFAULT_DATE_FORMAT, numBackups);
}
 
  public TomcatAccessLogCleaner(File logFileDir, String logFilePattern, String dateFormat, int numBackups) {
    this.dateFormat = dateFormat;
    this.logFileDir = logFileDir;
String pat = logFilePattern.replace(dateFormat, "(.+?)");
logFilePat = Pattern.compile(pat);
    this.numBackups = numBackups;
}
 
  public void clean() {
log.info("Starting to clean old Tomcat access logs. Number of backups to keep: " + numBackups);
File[] files = logFileDir.listFiles(new FilenameFilter() {
      public boolean accept(File dir, String file) {
        return logFilePat.matcher(file).matches();
}
});
List<LogFile> logFiles = new ArrayList<LogFile>(files.length);
    for (File file : files) {
      try {
LogFile logFile = new LogFile(file, logFilePat, dateFormat);
logFiles.add(logFile);
}  
      catch (ParseException pe) {
}
 
Collections.sort(logFiles, new Comparator<LogFile>() { 
@Override
      public int compare(LogFile o1, LogFile o2) {
        return o1.getLogDate().compareTo(o2.getLogDate());
}
});
 
    int numFilesToClean = logFiles.size() - numBackups;
    int removed = 0;
    for (int i = 0; i < numFilesToClean; i++) {
LogFile logFile = logFiles.get(i);
log.debug("Deleting access log file: " + logFile);
      if (!logFile.getFile().delete()) {
log.warn("Failed deleting log file");
}
}
log.info("Finished cleaning old Tomcat access logs. Total log files: " +
logFiles.size() + ". Deleted: " + removed + " of " + Math.max(0, numFilesToClean));
}
 
public static class LogFile {
  private File file;
  private Date logDate;
  public LogFile(File file, Pattern pattern, String dateFormat) throws ParseException {
Matcher matcher = pattern.matcher(file.getName());
    if (matcher.find()) {
String dateStr = matcher.group(1);
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
logDate = sdf.parse(dateStr);
      this.file = file;
}
}
 
  public File getFile() {
    return file;
}
 
  public void setFile(File file) {
    this.file = file;
 
  public Date getLogDate() {
    return logDate;
}
 
  public void setLogDate(Date logDate) {
    this.logDate = logDate;
}
 
  public void run() {
clean();
}
}
Note that TomcatAccessLogCleaner extends TimeTask. This enables easily using this class with a timer, allowing it to run every fix interval, and clean Tomcat access log files.
You can download this class here.
Let’s have a look of an example, showing how this class can be used in a servlet. The class will be scheduled to run automatically every 24 hours and clean old access log files. The class will be scheduled once when servlet loads. Don’t forget that you have to map servlets on your web.xml:
package com.bashan.blog.log;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import java.io.File;
import java.util.Timer;
/**
* @author Bashan
*/
public class TomcatAccessLogCleanerServlet extends HttpServlet {
  public void init(ServletConfig config) throws ServletException {
    super.init(config);
Timer time = new Timer();
TomcatAccessLogCleaner tomcatAccessLogCleaner = new TomcatAccessLogCleaner(new File("c:\\tomcat access log dir"), 10);
time.scheduleAtFixedRate(tomcatAccessLogCleaner, 0, 1000 * 60 * 60 * 24);
}
}
You can download the servlet here.

Monday, March 28, 2011

List of Mobile Devices and Brands as SQL inserts

I compiled a list of all mobile vendor (brands like Apple, Nokia) and models (mobile devices like iPhone, Galaxy S) as SQL inserts.
This list is a good place to start, but mobile devices are being added all the time. If you have a web application that needs to show list of mobile devices this list can help you. Note that the table contains both vendor and model, so it is best to show data in two drop downs: one for vendors and one for models. The drop down of the vendors is used as a filter to the drop down of the models.
This is the structure of the devices table (mySQL style):
CREATE TABLE `device` (
`vendor` varchar(100) NOT NULL,
`model` varchar(100) NOT NULL,
PRIMARY KEY (`vendor`,`model`)
) ENGINE=InnoDB
The list of the inserts if very long. You can download it by using this link.

Tuesday, March 22, 2011

How to Jump to an Anchor using JavaScript

Just like links/urls are a great way of moving between pages, anchors are great way of moving between locations on the same page.
Suppose we would like to move to a specific location on a page above some <div> tag. All we have to do is simply put an <a> tag above that div and give it some name. For example:
<a name="example"></a>
<div>
...
...
...
</div>

How do we jump to this specific location (named: example)? By putting an <a> on the place from which we would like to jump to this location. For example, somewhere else on the page we put:

<a href="#example">Press here to show example</a>

Note, that the name of the anchor for which we would like to jump contains the hash sign (#) as a prefix.

Now, suppose we would like to jump to some location by clicking something other than <a> (anchor) tag. For example by clicking a simple button. How can we jump to that location? Since we are not using anchor tag, we can no longer be directed to that location automatically.

We can use JavaScript in order to accomplish exactly the same behavior. Let’s see how it can be easily done with our button and by setting the “window.location.hash” property :

<input type="button" value="Press here to show example" onclick="window.location.hash = 'example';"/>

Note that on the JavaScript code we no longer need to use the hash (#) prefix.

Monday, March 21, 2011

Automatically Add “www” to your site on Tomcat or: Canonical Hostnames

Sometimes we would like that our website domain will always contain “www”.

I can this of two good reasons (beside of making all your site’s urls neat and unified) for adding “www” to your site urls:

  • To avoid cookie issues: Cookies are being stored for domains. www.example.com and example.com are 2 different domains when it comes to cookies. So if you would like to store some data in a cookie without wondering where did it disappear. Unify all the urls of your site to contain “www” and you are always working on the same domain.
  • To avoid security issues: Sometimes we would like to do some JavaScript coding on our site that may require us to be on the same domain (for example: running some JavaScript code from an iFrame on the parent window). Since url with “www” and url without “www” is considered to be a different domain, by making sure all of our urls contain the “www” prefix, we make sure we will not fall in all kind of cross domain security traps.

So, how do we make sure all our urls will always contain the “www” prefix" on Tomcat?

Luckily for us there is a great Java open source project named tuckey that can easily help us to accomplish that task. Tuckey is Url rewrite filter. It rewrites our urls according to set of predefined rules. As you noticed tuckey is doing much more than just adding “www” to our urls, but this is not for the scope of this post. You can learn more about tuckey and download it from this web site: http://www.tuckey.org/.

After you download and install tuckey on your web application (it is well details on the tuckey web site how this thing can be done), you simply have to add this rule to you urlrewrite.xml file:

<rule>
  <name>Canonical Hostnames</name>
  <condition name="host" operator="notequal">^www.mydomain.com</condition>
  <condition name="host" operator="notequal">^$</condition>
  <from>^/(.*)</from>
  <to type="redirect" last="true">http://www.mydomain.com/$1</to>
</rule>

Make sure that this rule is the first rule on your urlrewrite.xml file.