Archive for September, 2007

VirtualBox: access shared folders from Windows XP guest OS

Friday, September 28th, 2007
From the VirtualBox's menu, go to Devices Shared Folders... to add/remove the folders of the host operating system that you would like to share with the guest operating system (Windows XP, in this example). When done click Ok.

Now we are going to access the folders we added. DO NOT open My Network Places! Instead open a new explorer instance. You can do that by pressing WinKey-E or by executing the explorer command (Start Run... type "explorer" Ok). You should see a windows that looks like this:

windows explorer screenshot



Now, carefully click on the expand icon (expand icon) right next to My Network Places. Make sure you click exactly on the expand icon. If you accidentally clicked on My Network Places, you ruined everything and you will have to go back and start all over again. After expanding the My Network Places branch, you should be able to see Entire Network right underneath:

windows explorer screenshot



Now expand the Entire Network branch, too, and you should be able to see VirtualBox Shared Folders:

windows explorer screenshot



Open VirtualBox Shared Folders. Normally, you should be able to see your shared folders in there.

Simple Captcha: java.awt.HeadlessException

Wednesday, September 26th, 2007
If you are trying to use the SimpleCaptcha library on a Unix server without an X-Server running, it is most likely that you will end up getting a java.awt.HeadlessException. That happens because SimpleCaptcha tries to acquire information about the system's default screen, without particular reason.

Fortunately, SimpleCaptcha ships with its source code. What you can do is to edit the nl.captcha.text.imp.DefaultWordRenderer class, and remove the bogus lines of code. This is the original code (around line 53):

public BufferedImage renderWord (String word, int width, int height) {

GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();

GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

Graphics2D g2D = image.createGraphics();
g2D.setColor(Color.black);
...


Simply comment out the first three lines of code. These variables are not used anywhere below this point, so it is safe to take them off. The code should now look like this:

public BufferedImage renderWord (String word, int width, int height) {

//GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();

//GraphicsDevice gd = ge.getDefaultScreenDevice();
//GraphicsConfiguration gc = gd.getDefaultConfiguration();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

Graphics2D g2D = image.createGraphics();
g2D.setColor(Color.black);
...


Build the library and package it in a .jar file and use it. It should be working fine.

You will also have to make sure that you have the X11 libraries installed on your system (even though an X server is not running), and you will also have to invoke the jvm in Headless mode by setting the java.awt.headless system property to true. One easy way to do this is to include it in the command line options of the jvm:

java -Djava.awt.headless=true ...

If you plan to use the SimpleCaptcha library within a Tomcat web application (which is the most likely case), make sure that you include the above command line option in Tomcat's invocation command.

string indexers in javascript

Saturday, September 22nd, 2007
Today I faced a strange bug. I was trying to get the n-th character of a JavaScript string, using the C-String notation, like this:

ch = str[n];

it worked in Firefox but caused errors on Internet Explorer. For IE to work I had to use the Java-String notation:

ch = str.charAt(n);

This one works on both Firefox and Internet Explorer.

This language is full of surprises...

writeable shared folder with samba on ubuntu

Saturday, September 22nd, 2007
First, add the folder you want to share in your Shared Folder list. That is System Administration Shared Folders (if this menu item is missing, pres Alt-F2 and run "shares-admin"). You may need to click on the Unlock button and enter your password. Click the Add button. On the opening dialog, choose the path of the folder and the name by which the folder will be exposed. Make sure that you selected Share through: Windows networks (SMB) and that you unchecked the Readonly checkbox. Click Ok and close the Shared Folders dialog.

Now, edit the /etc/samba/smb.conf file as root to change the authentication method:

sudo gedit /etc/samba/smb.conf

Go to the Authentication section and uncomment the security=user line. (You uncomment the line by removing the preceding semicolon). Make it look like this:

####### Authentication #######

# "security = user" is always a good idea. This will require a Unix account
# in this server for every user accessing the server. See
# /usr/share/doc/samba-doc/htmldocs/Samba3-HOWTO/ServerType.html
# in the samba-doc package for details.
security = user

# You may wish to use password encryption. See the section on
# 'encrypt passwords' in the smb.conf(5) manpage before enabling.
encrypt passwords = true


Now, you have to setup a password for the user that will have remote access to your shared foders. Run this command:

# smbpasswd your-username
New SMB password: *******
Retype new SMB password: *******
#


Now go to the other computer and open Nautilus. At the location type:

smb://your-username@host/folder-name

Replace your username, host name (or IP) and the folder's name (make sure you use the share name as it may differ from the folder's real name). You should be able to browse and modify the contents of the remote folder by now.

search engine friendly URLs in JSP

Friday, September 21st, 2007
This article describes how to achieve search engine friendly URLs in a JSP-based website. I don't know if what is described here is the best you can do, because I couldn't find much information on the web, and this is what I personally came up with.

Let's say that you have a servlet that requests an article from a database and displays it. A classic URL pattern for this purpopse could be something like:

http://www.mywebsite.com/article.jsp?id=1234

This works but it is not what people call a search engine friendly or search engine optimized URL. Most search engine bots usually ignore pages which contain the '?' character in the URL. A search engine rather likes URLs of the form:

http://www.mywebsite.com/article.jsp/1234

or even better:

http://www.mywebsite.com/article.jsp/title-of-my-article

We will now try to improve the article servlet, so that it supports these friendly URLs.

First, you have to tell Tomcat that your servlet should be also accessed by the /article.jsp/* URL pattern. Go in your web.xml file and find the <servlet-mapping> tag for your servlet. It should look like this:

<servlet-mapping>
<servlet-name>ArticleServlet</servlet-name>
<url-pattern>/article.jsp</url-pattern>
</servlet-mapping>


Add one more tag that will match the new URL pattern, like this:

<servlet-mapping>
<servlet-name>ArticleServlet</servlet-name>
<url-pattern>/article.jsp/*</url-pattern>
</servlet-mapping>


Then, you should add some code in your servlet's doGet method to allow it to know whether the servlet was invoked using a friendly URL:

import java.util.regex.Matcher;
import java.util.regex.Pattern;
String servletPath = request.getServletPath();
String requestURI = request.getRequestURI();
Pattern pattern = Pattern.compile(".*"+servletPath+"/(.*)");
Matcher matcher = pattern.matcher(requestURI);
if (matcher.matches())
{
String param = matcher.group(1);
// do stuff with param here..
}


This way param contains the portion of the URL that follows the /article.jsp/ and you can do whatever you want with that.

However, there is one more thing you have to take care of. By introducing additional slashes in the URL you influence the way your browser determines the URLs for relative links and references. For example, if you have a css stylesheet reference in your page, like this:

<link href="style.css" rel="stylesheet" type="text/css"/>

it may not be found when you use friendly URLs. This happens because the current page's URL may end with /article.jsp/my-title, and the browser will look for the style.css file at /article.jsp/style.css, which does not exist.

To overcome this problem you have two choices. One, you can switch all your links from relative to absolute. But that's not a wise thing to do. Relative links are good, for several reasons. The other thing to do, is to use the <base> tag:

<head>
<base href="http://www.mywebsite.com/"/>
...
</head>


You set the base URL of your website and all your relative paths will be searched from there. If you do not want to hard code any part of the URL in your page, you can use this code inside your JSP page:

<%
String baseUrl = request.getRequestURL().
substring(0,request.getRequestURL().
indexOf(request.getServletPath()))+"/";
%>
<base href="<%=baseUrl%>"/>


I hope this helps.

prevent JSP pages or servlets from being cached

Friday, September 21st, 2007
You can prevent the output from your dynamic JSP pages or servlets from being cached by browsers and proxy servers, simply by adding the following few lines of code at the beginning of your JSP page or servlet:

<%
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
response.setDateHeader("Expires", 0);
%>


apache tomcat to compile java 5 JSP's

Wednesday, September 19th, 2007
When it comes for a JSP page to be compiled, Tomcat defaults to Java 1.3. Thus, if you are using any Java 5 feaures in your JSP pages, you will get an exception like this:

org.apache.jasper.JasperException: Unable to compile class for JSP

A common case is trying to use for-each loop, which is a Java 5 feature. This would generate an error message like this:

for-each loops are not supported in -source 1.3
(use -source 5 or higher to enable for-each loops)


To fix the problem you have to tell Tomcat that you want to use Java 5 as the source level for JSP compilation. Go to Tomcat's configuration directory, and edit the web.xml file. Find the "The JSP page compiler and execution servlet" section, it should look like this:

<servlet>
<servlet-name>jsp</servlet>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>


Edit it so that it looks like this one (insert the text in bold letters):

<servlet>
<servlet-name>jsp</servlet>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>compilerSourceVM</param-name>
<param-value>1.5</param-value>
</init-param>
<init-param>
<param-name>compilerTargetVM</param-name>
<param-value>1.5</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>


Save the web.xml file and restart Tomcat. It should be fixed by now.

Servlet Forwarding and Redirecting

Tuesday, September 18th, 2007
To achieve separation between business logic and presentation in a servlet-based web application, it is generally considered a good idea to have a Servlet that carries out the necessary work and a separate JSP page that will simply display the results. A developer can choose between servlet forwarding or request redirection, based on several criteria.

A request redirection is achieved using the following code from the Servlet:

response.sendRedirect("results-page.jsp");

This will send a 302 Moved Temporarily response to the browser, which will afterwards load the new page with another request. Any data that should be passed from the Servlet to the page should be stored temporarily on the server, in a place that will not be destroyed between the two requests. Such place is the session. Any data should be stored as a session attribute, like this:

request.getSession().setAttribute("mySharedData", mySharedData );

The shared data would then be retrieved from the JSP page using a useBean tag:

<jsp:useBean id="mySharedData" class="..." scope="session"/>

Although this method works, it causes the browser to send a brand new HTTP request for the JSP page. As a result:

  • the URL on the browser's location is changed.

  • reloading current page will reload the JSP page, not the original Servlet.

  • the total loading time will be greater because the browser will have to send two separate HTTP requests.


In addition, shared data will be stored in the session scope, and will be available to all other servlets that will be called within this session, and this may not be what you want.

On the other hand, in some cases it would be more useful to choose forwarding instead of redirecting:

RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher("/results-page.jsp");
dispatcher.forward(request,response);


This will forward the request to the JSP page. The forwarding is performed internally within the servlet container, so no additional HTTP requests are sent by the browser. As a result:

  • the location URL stays unchanged.

  • reloading the page will cause the original servlet to be requested.

  • the page will load faster because there will be only one HTTP request.


Additionally, you don't have to store any shared data in the session any more, as you can simply store them in the request scope. For example, you can store the data from the servlet like this:

request.setAttribute("mySharedData", mySharedData );

And then access them from the JSP page, like this:

<jsp:useBean id="mySharedData" class="..." scope="request"/>

It has to be clear that none of the two methods is better or worse than the other. Sometimes you do want the browser's URL to change. Sometimes you do want the page reload not to cause the original servlet to be executed again (you wouldn't want that when charging a credit card!) Also, some of your data may be necessary to be shared between requests, thus storing them in the session scope is exactly what you should do. The conclusion is, that you have to examine each case, decide which one of the two methods suits best, and use it.

Farewell, Alex...

Thursday, September 13th, 2007

Alex (1976-2007), the African grey parrot

how to clear bash history and what to watch out for

Thursday, September 13th, 2007
In a pinch, you can clear all your bash shell's command history by typing this command:

history -c

However, there are a few things about how bash shell's history that worth a closer look.

The bash shell stores the command history in a file, this is typically ~/.bash_history. It is a simple text file with one command per line. Whenever an interactive instance of the bash shell is created, the bash shell loads the history into the memory. As long as the shell is running all new typed commands are appended in the history, but they only exist in memory. The history will be written to ~/.bash_history when the shell is terminated (or if you issue the history -w command, whichever comes first).

There is nothing wrong with that, as long as you use only one instance of the bash shell at a time. Consider this: you log into your computer and open two terminal windows. You do some work on the first shell, then you do some other work on the second shell. When done, you want to clear all recorded history and exit. You go to the first shell and type history -c to clear the history, and then exit. Then you go to the second shell and simply type exit, thinking you already have cleared the history. You think you have cleaned up everything, but no, if you check the contents of your ~/.bash_history all the history from the second bash instance will be there, looking at you right in the eyes.

One thing you can do is to scrupulously make sure that you execute history -c before exiting every bash instance you are running. But this is kind of stressful, plus you may always run into the case of forgetting to clear the history, because people simply forget.

Another thing you may try is to add the history -c command in your ./bash_logout script, but you have to keep in mind that it works only with login shells, like the shell you are given from the console, or when running bash with the --login parameter. This will NOT work with the shells opened by terminal emulators (like the GNOME Terminal, for example).

A more effective approach would be to simply add a crontab entry that will empty the ~/.bash_history file in a reasonable frequency. This will do:

*/1 * * * * cat /dev/null > ~/.bash_history

This command in your crontab will cause the bash shell's history file to be emptied every one minute. Please not that you cannot run history -c from crontab, because history is in fact an internal bash shell's command, not a real program that can be executed from crontab.