Tuesday, April 12, 2011

Get image width & height with Javascript

Ever needed to get the real dimensions of an image with javascript that works on all browsers, even when the width and height hasn't been explicitly set (either on the img tag or with css) ? Here's how to do it

Include JQuery on your page

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js" type="text/javascript"></script>

Give your image an explicit id:

<img id="someId" src="mypicture.jpg" />

Use this JQuery snippet to get the width and height:

// Our vars holding the width and height
var pic_width, pic_height;

// Load an image into memory, to prevent any css affecting it
var img = $('<img />');

// Bind the image to an onload event
img.bind('load', function() {
  pic_width = this.width;
  pic_height = this.height;
});

// Load the image, onload will fire and store width and height
$(img).attr('src', $('#someId).attr('src'));

The onload event needs to be bound before loading the actual image to make sure it fires.

Sunday, March 27, 2011

Working with JQuery UI icons

First of all, JQuery is total awesomeness. 'nuff said.

Using the icons is not as straightforward as you might think. Basically to use an icon on a page, you need to have the CSS included. Google hosts the themes so you can link to these to save your bandwidth, which is nice. For example if you wanted to use the 'darkness' theme, you need to add this to the <head> part of your page:

<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/themes/ui-darkness/jquery-ui.css" rel="stylesheet" type="text/css" />

The themes contain a lot of nice icons. You can see all of the themes and icons at the JQuery UI Themeroller. To see the class of an icon on the page, simpy mouse over it.

To add an icon on a page (a trashcan in this example), you need to add a <span> element as follows:

<span class="ui-icon ui-icon-trash ui-state-default" title="Whatever mouseover text you want"></span>

This creates the icon surrounded by a rectangle. If you want to use a different icon, simply replace the 'ui-icon-trash' class with the class of the icon you want. If you do not wish to see the rectangle surrounding it, remove the 'ui-state-default' class from it.

First thing you need to know that the icons are block level elements. That means any text or elements following the icon will be placed on a newline. To counter this, you can either place the icon and the following text/whatnot in a table in separate cells, or add an inline float style to the <span>:

<span class="ui-icon ui-icon-trash ui-state-default" title="Whatever mouseover text you want" style="float:left;"></span>

Make it a link

To  make the icon act as a link, you need to bind it to a click event with JQuery. Include the JQuery libs (again from Google) in your header:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js" type="text/javascript"></script>

Now, place the following code to your page's header:

<script type="text/javascript">
  $(function() {
    $('.makeMeALink').click(function() {
      document.location.href = 'someUrl';
    });

  }
</script>

Here we bind the 'makeMeALink' selector to a click event, and make it open the URL 'someUrl' in the current browser window. Replace 'someUrl' with the address you want the link to point to. Now, add the 'makeMeALink' selector to the icon as a class and the icon will function like a link:

<span class="ui-icon ui-icon-trash ui-state-default makeMeALink" title="Whatever mouseover text you want" style="float:left;"></span>

Why do we do it like this, and not just wrap the <span> element in a link tag ? Sure, we could do this also:

<a href="someurl"><span class="ui-icon ui-icon-trash ui-state-default" title="Whatever mouseover text you want" style="float:left;"></span></a>

It pretty much does the same thing, but in case you wanted to reuse the click binding on some other element, or expand the functionality to for example showing a modal confirmation dialog, you need to use the click event binding.

Make it appear as a link

The thing is that users won't actually realize its a link, as putting the cursor over it still shows the default cursor, and the icon does not animate/highhlight or the such to indicate its clickable. We can use JQuery to bind a mouseover event to 'highlight' the icon and change the cursor. Modify the JQuery in the header to look as follows:

<script type="text/javascript">
  $(function() {
    $('.makeMeALink').click(function() {
      document.location.href = 'someUrl';
    });


     $('.hoverAnimation').hover(function() {
      $(this).addClass('ui-state-hover');
    }, function() {
      $(this).removeClass('ui-state-hover');
    });


    $('.changeCursor').hover(function() {
      $(this).css('cursor', 'pointer');
    });

  }
</script>

Basically, we define two hover bindings for the 'hoverAnimation' and 'changeCursor' selectors. The 'hoverAnimation' selector when placed on an element will add the 'ui-state-hover' CSS class to the element when the user puts his/her mouse over it, and removes the class when the mouse moves outside the element. The 'ui-state-hover' class is built in to the JQuery UI themes and will work with any theme.

The 'changeCursor' binding will change the cursor to a pointer when the mouse is placed over the icon, the same way it does when you place your mouse over a link.

Now, add these two selectors to the icon:

<span class="ui-icon ui-icon-trash ui-state-default makeMeALink hoverAnimation changeCursor" title="Whatever mouseover text you want" style="float:left;"></span>

Now you have an icon that acts as a link, changes cursor like a link, and when pointed with a mouse will be highlighted.

Saturday, March 26, 2011

Implementing a visitor counter in Java

If you're running a Java-based site, here's how you can track the number of concurrent visitors on your site. The code can be easily extended to support a variety of functions, for example tracking who of your visitors is currently logged in.

Add this to each of your JSP/JSF files:

 SessionTracker tracker = SessionTracker.getInstance();
 String agent = request.getHeader("user-agent");

 if (agent != null) {

  // Check the user-agent from the request, we don't want to track crawlers. Add as many agents as you like to exclude.
  agent = agent.toLowerCase();
  if (agent.indexOf("googlebot") == -1 && agent.indexOf("msnbot") == -1 && agent.indexOf("slurp") == -1) {

   // Current version of Opera has a bug that causes it to make two requests to a page; the other one does not have a 'cookie' header set, so only regard the 'real' request

   if (agent.toLowerCase().indexOf("opera") != -1) {
    if (request.getHeader("cookie") != null) {
     tracker.trackSession(session);
    }
   } else {
    tracker.trackSession(session);
   }
  }
 } 


And on the page(s) where you wish to print the number of visitors, add:

<%=tracker.getNumberOfSessions()%>

The actual tracking class:

import java.util.*;
import javax.servlet.http.HttpSession;

public class SessionTracker extends Thread {
 private static SessionTracker instance = null;
 private static Hashtable<String, HttpSession> data = null;

 // How long to wait between visitor checks
 private static final int sleep = 60 * 1000;
 // How long a session can be idle until it is not counted
 private static final int reapTime = 10 * 60 * 1000;

 private SessionTracker() {
  data = new Hashtable<String, HttpSession>();
 }

 public static synchronized SessionTracker getInstance() {
  if (instance == null) {
   instance = new SessionTracker();
   instance.start();
  }

  return instance;
 }

 public void trackSession(HttpSession session) {
  data.put(session.getId(), session);
 }

 public int getNumberOfSessions() {
  return data.size();
 }

 public void run() {
  while (true) {
   instance = this;

   Enumeration<String> enu = data.keys();

   while (enu.hasMoreElements()) { 
    String key = enu.nextElement();
    HttpSession session = data.get(key);
 
    long diff = System.currentTimeMillis() - session.getLastAccessedTime();
 
    if (diff > reapTime) {
     data.remove(key);
    }
   }

   synchronized(this) {
    try {
     this.wait(sleep);
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  }
 }
}

Running Apache as front-end to JBoss with virtual hosts

I run several websites on JBoss on my home computer and use Apache as a front-end to redirect requests to the correct sites. Basically if you want your site to be accessible from www.yourdomain.com as is without appending the web app context (e.g., www.yourdomain.com/yourapp) you need to do this. This is also more secure as you can bind JBoss to localhost only and hide the jmx-console.

First of all, you should have defined your web-apps' contexts in their WEB-INF/jboss-web.xml files:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>

  <context-root>/mywebapp</context-root>
</jboss-web>


Thats all what is needed from JBoss.

Next, you need to add the virtual host configs to Apache httpd.conf file. Example for a single website:

<VirtualHost *:80>
  ServerAdmin john@doe.com
  ServerName www.mysite.com
  ServerAlias mysite.com
  ProxyPass / http://localhost:8080/mywebapp/
  ProxyPassReverse / http://localhost:8080/mywebapp/
  ProxyPreserveHost On
  ProxyPassReverseCookiePath / /
  ErrorLog logs/mysite-error_log
  CustomLog logs/mysite-access_log common
</VirtualHost>

The thing with the proxypass and proxypassreverse directives is that it preserves the domain so you can handle cookies as is on JBoss side without any problems, and that sessions are tracked correctly.

JBoss and property files

I needed to use Java Properties in JBoss and found it somewhat difficult to find any decent documentation or examples how to do this, so here's how I got it working. It might not be the correct way, but it works.

Create your .properties file (key/value pairs) and place it in for example the WEB-INF dir. Load the props as follows:

Properties props = new Properties();
props.load(application.getResourceAsStream("/WEB-INF/mypropertiesfile.properties"));

Then load whatever you need.

Ratcliff/Obershelp pattern recognition in Java

I needed a way to compare the similarity of two strings and return value as a percentage in a project, so I implemented a Java version of the Ratcliff/Obershelp pattern regocnition algorithm and thought I'd share it here. The definition of the algorithm is as follows:

"Compute the similarity of two strings as the doubled number of matching characters divided by the total number of characters in the two strings. Matching characters are those in the longest common subsequence plus, recursively, matching characters in the unmatched region on either side of the longest common subsequence."

The returned value ranges from 0..1f. Below is the source, enjoy :)

public class Simil {

 public Simil() {};
 
 private static float tcnt;
 
 private void findSubstr(String s1, int s1len, String s2, int s2len, Struct ss) {
  int size = 1;
  
  ss.setO2(-1);
  
  for (int i = 0; i < (s1len - size); i++) {
   for (int j = 0; j < (s2len - size); j++) {
    int test_size = size;
    
    while (true) {
     if ((test_size <= (s1len - i)) && (test_size <= (s2len - j))) {
      if (s1.regionMatches(i, s2, j, test_size)) {
       if (test_size > size || ss.getO2() < 0) {
        ss.setO1(i);
        ss.setO2(j);
        size = test_size;
       }
       test_size++;
      } else {
       break;
      }
     } else {
      break;
     }
    }
   }
  }
  
  if (ss.getO2() < 0) {
   ss.setLen(0);   
  } else {
   ss.setLen(size);
  }
 }
 
 private void rsimil(String s1, int s1len, String s2, int s2len) {
  Struct ss = new Struct();
  
  if (s1len == 0 || s2len == 0) return;
  
  findSubstr(s1, s1len, s2, s2len, ss);
  
  if (ss.getLen() > 0) {
   int delta1, delta2;
   tcnt += ss.getLen() << 1;
   rsimil(s1, ss.getO1(), s2, ss.getO2());
   
   delta1 = ss.getO1() + ss.getLen();
   delta2 = ss.getO2() + ss.getLen();
   
   if (delta1 < s1len && delta2 < s2len) {
    rsimil(s1.substring(delta1, s1len), s1len - delta1, s2.substring(delta2, s2len), s2len - delta2);
   }
  }
  
 }
 
 public float ratcliff(String s1, String s2) {
  int s1len, s2len;
  float tlen;
  
  if (s1 == null || s2 == null) {
   return 0;
  } else if (s1.equals(s2)) {
   return 1;
  }
  
  s1 = s1.toLowerCase();
  s2 = s2.toLowerCase();
  
  s1len = s1.length();
  s2len = s2.length();
  
  tcnt = 0;
  tlen = s1len + s2len;
  
  rsimil(s1, s1len, s2, s2len);
  
  return tcnt / tlen;
 }
 
 class Struct {
  Struct() {};
  
  int o1, o2, len;

  public int getLen() {
   return len;
  }

  public void setLen(int len) {
   this.len = len;
  }

  public int getO1() {
   return o1;
  }

  public void setO1(int o1) {
   this.o1 = o1;
  }

  public int getO2() {
   return o2;
  }

  public void setO2(int o2) {
   this.o2 = o2;
  }  
 }
}

Enabling URL rewriting in JBoss

This isn't particularly difficult, but the information contained in JBoss docs is pretty vague. Basically to enable URL rewrites, you need to create a "context.xml" file and place it inside the WEB-INF -directory of your web app. In the context file, enable the rewrite valve as follows:

<context cookies="true" crosscontext="true">
    <valve classname="org.jboss.web.rewrite.RewriteValve">
</context>

Next, create a "rewrite.propreties" file and place it in the same directory. Add your rewrite rules there.
Nothing more to it really. The syntax is the same as in Apache's mod_rewrite, but JBoss doesn't support every feature there, at least I found that the RewriteLog directive is not supported.

Note that when you add or edit a rule, you need to restart your web app for it to take effect.

If you find that your rules are not working, its propably because your rule is wrong, not that the rewrites are not enabled. If you specify a rule with incorrect syntax you will get an exception in the JBoss console/server log when you (re)start your web app. Make very simple test rule and verify that it works, then start making it more complex and building up from that.