Category Archives: English

Reorder JQuery event handlers

I was little bit suprised when I didn’t find in JQuery an ability to bind event’s handler before than already binded event’s handlers list. Yes, it is possible to first attach our handler rather than others, but this may be very difficult sometimes. So I spent some time looking through JQuery sources and found what I need:

/*
 * A number of helper functions used for managing events.
 * Many of the ideas behind this code originated from
 * Dean Edwards' addEvent library.
 */
jQuery.event = {
 
    // Bind an event to an element
    // Original by Dean Edwards
    add: function( elem, types, handler, data ) {
        ...
 
        // Init the element's event structure
        var elemData = jQuery.data( elem );
 
        // If no elemData is found then we must be trying to bind to one of the
        // banned noData elements
        if ( !elemData ) {
            return;
        }
 
        // Use a key less likely to result in collisions for plain JS objects.
        // Fixes bug #7150.
        var eventKey = elem.nodeType ? "events" : "__events__",
            events = elemData[ eventKey ],
            eventHandle = elemData.handle;
 
        ...
 
        while ( (type = types[ i++ ]) ) {
            ...
 
            // Get the current list of functions bound to this event
            var handlers = events[ type ],
                special = jQuery.event.special[ type ] || {};
 
            ...
 
            // Add the function to the element's handler list
            handlers.push( handleObj );
 
            ...
        }
 
        // Nullify elem to prevent memory leaks in IE
        elem = null;
    }
 
    ...
}

As we can see from this code all we need to do is get “handlers” array (for “click” event in this example) from target element. Then we can do anything we need with event’s handlers. Code to do this is quite simple:

var
elementData = jQuery.data(targetElementDom),
events = (elementData.events ? elementData.events : elementData.__events__),
handlers = events['click'];
 
// Only one handler. Nothing to change.
if (handlers.length == 1) {
    return;
}
 
// Insert last handler at first index.
handlers.splice(0, 0, handlers.pop());

I used previous code to attach confirm window to elements which already have (or not) “click” event handlers.

Little demo.

Jersey: how to get temporary file

I use Jersey with flash uploader and the problem I met is that I need to determine “file partialy uploaded” situation ’cause user has an opportunity to cancel it at any time. All solutions that I found for this problem were on PHP (look for The uploaded file was only partially uploaded text). I didn’t find any standart technics how to get size of uploaded file (uploaded file’s input stream doesn’t has such information) to compare it with actual file size. So I used a “little reflection magic” to get it. ’cause classes that we’ll use to get information is private for org.jvnet.mimepull package we need to create out util class in exactly the same package. Then we can use reflection to get any infomation that we need.

Continue reading

Fix for Jersey’s russian files names bug

In our project we use Sun/Oracle implementation of JAX-RS — Jersey ’cause it’s greate framework for build REST-services. But there are some troubles with uploading files feature. When you uploading file with latin chars in file name everything is fine, you read this file name on server and it’s exactly the same as on client computer. But when you trying to upload file with russian chars in file name you get “abracadabra” instead of them. For example:

Original file name Received file name
Test123.txt Test123.txt
Тест123.txt Тест123.txt

Continue reading

Sharing JSESSIONID cookie across subdomains on JBoss

The problem with sharing cookie with JSESSIONID value arises when we start use subdomains system in our application. For example: images.portal.com, security.portal.com, etc.

Respectively a cookie with unique JSESSIONID value will be created for each domain address and you can get some problems. For example, with autorization if it stores credentials in session. So for our example we will have three diffrent cookies with three different session ids.

# Domain Value
1 portal.com JSESSIONID1
2 images.portal.com JSESSIONID2
3 security.portal.com JSESSIONID3

Not very good, really?) Our cookie must have “.portal.com” domain to starts sharing across all subdomains (and there also will be only one session cookie instead of three). I didn’t find any standart solution for this problem. Possible solutions are:

  1. hardcode domain name in TomCat source files and recompile them (heh, I think this is the most popular solution for this problem over the Internet, but it isn’t our way);
  2. use custom valve to set domain name (very flexible solution, so we will used it);
  3. write cookie with true domain from application. But this will make your application logic more complicated and you will have two cookie with identical JSESSIONID value and different domains. “.portal.com” — from your application, “portal.com” — from TomCat.

Valve is the great software development company and it is also a filter that can do some transformation with request. In our case the valve must takes session cookie from request and rewrites its’ domain to some that we setup in config file. It’s very easy, ’cause problem is already solved. From previous link we saw how to work with valve and now we can go here.

Step-by-step guide (for JBoss 4.2.3):

  1. download customvalve2.zip file;
  2. put customvalve.jar file from archive to “JBOSS_HOME/server/YOUR_CONFIGURATION/lib” folder;
  3. add string “<Valve className=”com.redhat.jboss.support.ConfigureSessionCookieValve” cookieDomain=”.portal.com” />” to your host in “JBOSS_HOME/server/YOUR_CONFIGURATION/jboss-web.deployer/server.xml” file. Looks like:
    <Host name="localhost"
        autoDeploy="false" deployOnStartup="false" deployXML="false"
        configClass="org.jboss.web.tomcat.security.config.JBossContextConfig"
        >
        ...
        <Valve className="com.redhat.jboss.support.ConfigureSessionCookieValve"
            cookieDomain=".portal.com" />
        ...
    </Host>

And at last let us see the method that does all work (located in ResponseWrapper.java):

// Called from addCookie() and addCookieInternal() methods.
protected void configureSessionCookie(Cookie cookie) {
    if (Globals.SESSION_COOKIE_NAME.equals(cookie.getName())) {
        if (cookiePath != null) {
            cookie.setPath(cookiePath);
        }
        if (cookieDomain != null) {
            cookie.setDomain(cookieDomain);
        }
        if (cookieSecure != null) {
            if (cookieSecure.equalsIgnoreCase("true")) {
                cookie.setSecure(true);
            } else if (cookieSecure.equalsIgnoreCase("false")) {
                cookie.setSecure(false);
            }
        }
    }
}

That’s all!) Valve sources lie in downloaded archive so they can be easily modificated for your purposes.

Redirect to “No IE6 page”

Many online services have stopped supporting Internet Explorer 6 and when a user tries to access them with the browser sent him to the information page, where the offer to upgrade IE to latest version or choose another browser. Here is my easiest solution for this:

<html>
    <head>
        <!--[if lt IE 7]>
            <script type="text/javascript" charset="utf-8">
                window.location = 'location_of_your_no_ie6_page';
            </script>
        <![endif]-->
        ...
    </head>
    ...
</html>

It used nothing, but IE conditional comments, so it’s very compact and fast ’cause every browser except IE6 and lower just ignores this code.

ImageMagick “convert: Non-conforming drawing primitive definition `image” problem

ImageMagick is the great set of image processing utilities. But there are some problems to interact with it from your programs (java program in my case). About one of them I would like to talk. In one of our latest projects we used ImageMagick to resize images and put a watermark on them. Everything was fine on developers machines with OS Windows, but when we put project on Unix server… Agrrr. WTF?! We got this error: “convert: Non-conforming drawing primitive definition `image”. Magic… ImageMagick! Here is the best article that I have founded about this problem. It doesn’t help me ’cause it describes a little different problem, but it may be helpful for you) Ok, let us see the code that throws the error (in this example I removed resize parameter ’cause it works fine and the problem only in draw):

public void convertImage() {
    // List of commands that we want to execute
    List commands = new ArrayList();
 
    // Executable file
    commands.add("convert");
 
    // Executable file parameters
    commands.add("-gravity");
    commands.add("South-East");
    commands.add("-draw");
    commands.add(""image Over 0,0 0,0 'im-watermark.png'"");
    commands.add("im-image.png");
    commands.add("im-new.png");
 
    try {
        // I also tried to use Runtime.getRuntime().exec(...), but got the same result and it doesn't wonder
        // 'cause it use ProcessBuilder
        ProcessBuilder processBuilder = new ProcessBuilder();
        processBuilder.command(commands);
        Process process = processBuilder.start();
 
        BufferedReader error = new BufferedReader(new InputStreamReader(process.getErrorStream()));
 
        // Check if we have an error...
        if (error.ready()) {
            // ...then print them
            String line;
 
            while ((line = error.readLine()) != null) {
                System.out.println("error: " + line);
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

The process builder that we use in our code example must generate such command:

convert -gravity South-East -draw "image Over 0,0 0,0 'im-watermark.png'" im-image.png im-new.jpeg

Looks correct, but doesn’t work. Ok, let’s try to run this command from Unix shell. I can’t belive it! It works! In shell, but not from our program( I think that something happens with convert command parameters when JVM run it or may be it is some kind of Unix feature. I don’t know. So, I did this trick:

  1. create shell script “im-convert-proxy.sh” (don’t forget to execute “chmod +x im-convert-proxy.sh” command. It allows you to execute this script) with code:

    eval 'convert '$@

    How you can see it just runs convert command with all parmeters that we passed to script from our java program.

  2. replace executable file from “convert” to “im-convert-proxy.sh”:

    commands.add("im-convert-proxy.sh"); // was commands.add("convert");

That’s all! Everything works, everyone is happy)

P.S.: if you have found a better solution, please write me.