Wednesday, September 22, 2010

Use JSTL's "c:out" instead of ${} for display

JSTL has a tag called "c:out" which allows variables to be dumped to the screen. Here is an exmaple:

<c:out value="${aUrl}" />

But many people often ask why not use the less verbose method as follows:

${aUrl}

Although ${} is much simpler, there are many reasons for using c:out instead. One of the main reasons is escaping of HTML characters. If the variable holds a string that contains tags such as
<div> , then the browser will read it as a tag and screw up the layout of your page.

For a list of what gets escaped click here.

Escaping of user input is very important for security reasons. Recently, there has been an article on the net about how Twitter was hacked by "Javascript Injection". Here is one of the articles:

http://blog.trendmicro.com/twitter-mouseover-flaw-allows-script-injection/

Bascially, the problem for Twitter was that they were not escaping user input when displaying links. Had they used something similar to JSTL's c:out tag, then they would have been protected.

Tuesday, September 14, 2010

spring 3 mvc annotation-driven with DWR annotations

I am currently working on a new project that uses Spring 3 MVC Annotation-driven model. I had used DWR on previous projects successfully, but without using annotations, and relying on XML configuration.

After having played around with Spring's annotation driven model, I found it much easier than it's XML counterpart, and so I was determined to get DWR working in the same manner.

mvc-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"
    
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
       http://www.directwebremoting.org/schema/spring-dwr
       http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd">


    
    <!-- ================================== DWR configurations ===================================== -->    
    <dwr:configuration>
        <dwr:convert type="bean" class="podd.apn.tab.FacsImportStatus" />    
    </dwr:configuration>
    <dwr:annotation-config />
    <dwr:url-mapping />
    <dwr:controller id="dwrController" debug="true" />    
    
    <!-- Configures the @Controller programming model -->
    <mvc:annotation-driven />

    <!-- Forwards requests to the "/" resource to the "welcome" view -->
    <mvc:view-controller path="/" view-name="welcome"/>
    <!-- 
    <mvc:view-controller path="/*" />
     -->    

    <!-- Configures Handler Interceptors -->    
    <mvc:interceptors>
        <!-- Changes the locale when a 'locale' request parameter is sent; e.g. /?locale=de -->
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
    </mvc:interceptors>

    <!-- Saves a locale change using a cookie -->
    <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" />

    <!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>



    

</beans>


web.xml
  <!-- =============
      SERVLETS
   ============  -->
  <servlet>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
                /WEB-INF/spring/app-config.xml
            </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  
    <servlet>
        <servlet-name>uploadServlet</servlet-name>
        <servlet-class>podd.apn.servlet.UploadServlet</servlet-class>
    </servlet>

    <!-- =================
        SERVLET MAPPINGS
     ================  -->
  <servlet-mapping>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <url-pattern>/spring/*</url-pattern>
  </servlet-mapping>
  
  <!--  DWR -->
  <servlet-mapping>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <url-pattern>/dwr/*</url-pattern>
  </servlet-mapping>


And then to verify that it DWR is integrated correctly you can visit:

http://localhost:8989/podd-apn/dwr/engine.js

Referneces:

http://www.codercorp.com/blog/spring/configuring-dwr-30-with-spring-using-annotations.html

Sunday, August 15, 2010

Caused by: java.lang.Error: This version of SLF4J requires log4j version 1.2.12 or later.

I recently synched up to a project to make a new build and upon deployment I encountered a frustrating error:

Caused by: java.lang.Error: This version of SLF4J requires log4j version 1.2.12 or later.

This issue was a real pain, because the error message was very misleading. Basically, the error message is complaining that I don't have a log4j version 1.2.12 or greater.

I checked my classpath, performed a cleaned build, cleared my tomcat cache and restarted tomcat, and none of them fixed the issue. Indeed, my log4j version 1.2.14!!

Bah, I started to dig deeper into the issue and it boiled down to this:

I had replace

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.5.0</version>
        </dependency>


With:

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.5.6</version>
    </dependency>     
                        
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.5.6</version>
    </dependency>   

I hope this saves somebody else hours of pain

Tuesday, August 10, 2010

Customizing swfupload

After playing around with swfupload, there were a few customizations I needed to make.

1) I wanted to add the files to the user's session.
2) After uploading has completed, by default, swfupload will remove all the items. I wanted to keep the listed items so that the user can review which files were uploaded if they needed to.

Adding to the user session

Since swfupload uses Flash as the underlying mechanism for uploads, the behaviour for executing flash is different for each browser. It turns out Firefox opens a new process and a new cookie for performing the upload as noted in this article:

http://www.thanksmister.com/index.php/archive/firefox-flex-urlrequest-and-sessions-issue/ 

So to work around the issue, the jsessionid was explicity passed into the URL of the upload. With the jsessionid in the URL, Tomcat was able to attach the session to the request.

Here's another article the describes the problem in more detail:
http://blogs.bigfish.tv/adam/2008/04/01/cakephp-12-sessions-and-swfupload/

Below is the code for adding the jsessionid:


function createSwfUpload(fieldName, sessionId,swfUploadUrl, swfButtonUrl, swfButtonPlaceHolderId, swfFlashUrl, progressTarget, buttonCancelId) {
    
    var uploadUrlSession = swfUploadUrl+";jsessionid="+sessionId;
    
    var swfUpload = new SWFUpload({
        
        // The name of the field name that the files are attached to
        file_post_name : fieldName,
        
        // Backend Settings
        upload_url: uploadUrlSession,
        post_params: {"JSESSIONID" : sessionId},

        // File Upload Settings
        file_size_limit : "102400",    // 100MB
        file_types : "*.*",
        file_types_description : "All Files",
        file_upload_limit : "100",
        file_queue_limit : "0",

        // Event Handler Settings (all my handlers are in the Handler.js file)
        file_dialog_start_handler : fileDialogStart,
        file_queued_handler : fileQueued,
        file_queue_error_handler : fileQueueError,
        file_dialog_complete_handler : fileDialogComplete,
        upload_start_handler : uploadStart,
        upload_progress_handler : uploadProgress,
        upload_error_handler : uploadError,
        upload_success_handler : uploadSuccess,
        upload_complete_handler : uploadComplete,

        // Button Settings
        button_image_url : swfButtonUrl,
        button_placeholder_id : swfButtonPlaceHolderId,
        button_width: 61,
        button_height: 22,
        
        // Flash Settings
        flash_url : swfFlashUrl,
        

        custom_settings : {
            progressTarget : progressTarget,
            cancelButtonId : buttonCancelId
        },
        
        // Debug Settings
        debug: false
    });    
    
    return swfUpload;
    
}

Keep list of Uploaded Items

After the upload completes, swfupload automatically hides the progress results. I wanted our users to review which files got uploaded if they needed to. Surprisingly, there was no easy way to configure this. This is what I meant in my other post that swfupload was a bit clunky, but at least it works compared to the "uploadify" alternative. To make the change I commented out some of the code in the fileprogress.js file:

FileProgress.prototype.setError = function () {
    this.fileProgressElement.className = "progressContainer red";
    this.fileProgressElement.childNodes[3].className = "progressBarError";
    this.fileProgressElement.childNodes[3].style.width = "";

    // COMMENT OUT TO STOP REMOVING UPLOAD RESULT
    //var oSelf = this;
    //this.setTimer(setTimeout(function () {
    //    oSelf.disappear();
    //}, 5000));};

Reference: http://www.swfupload.org/forum/generaldiscussion/2123

Multiple file uploads

I've recently been faced with a project where a client needs to be able to upload multiple files in a form submission. I've faced this problem before and there have been many solutions:

One of the older solutions was to expect that the user would ZIP up all the files so that we effectively convert a multiple file problem to a single file. While this did work, it relied on the user to know how to ZIP up files and expect them to perform an extra step of zipping up the files. Not so elegant.

Another solution, is to use a Java applet. The con of using this implementation is that users are expected to have Java already installed on their system. This is a barrier since not all computers will have them installed. The advantage is that once it is installed, then works regardless of what browser is being used.

Flash uploader has recently been popularized by several websites which include Youtube, Flickr and Facebook. Because of this websites, many users will already have flash installed and therefore is less of a barrier. One of the disadvantages is that behaviour of Flash can be different across browsers and different versions of Flash can behave differently as we will soon see.

Many of my users are not very comfortable with using computers, and many of them will only use a computer when they have to. That being said, having to install something on their computer would seem to be a daunting task. Therefore I decided to go with Flash because most people will already have it installed.

At first I went with a utility called "Uploadify" which can be found here:

http://www.uploadify.com/

What I liked about this solution was that it was very elegant and easy to use. But I learned very quickly, that it just didn't work. It was broken for the latest flash version (version 10) and had very little support. It's been noted on their bug list from so many people, but none of the developers acknowledged any plans to fix it.

http://www.uploadify.com/forum/viewtopic.php?f=4&t=5627

I went to look for another solution that was actively being maintained. I stumbled upon "SwfUpload" found here:

http://code.google.com/p/swfupload/

The coding wasn't as elegant as Uploadify, but at least it worked, and it worked across all major browsers. The Javascript coding is a bit clunky, but once you have it up and running, it works great.

For those of you looking at comparing other solutions heres a good reference website:

http://qubit-toolkit.org/wiki/index.php?title=Multiple_file_upload

Wednesday, July 28, 2010

Cygwin: less reports WARNING: terminal is not fully functional

I have been using the "less" command Cygwin without problems for almost a year. For a new project I needed to have perl installed so I downloaed "Strawberry Perl" and installed it.

Afterwards, in cygwin everytime I tried to issue the "less" command it complained that the "terminal is not fully functional".

Turns out Strawberry perl was adding the environment variable TERM with a value of dumb.
Deleting the TERM fixed the issue.

Tuesday, July 27, 2010

inline elements and background-images

This dreaded issue has been looked at to death in so many forums, but in all my research I haven't found a working solution. In here, I wil describe a few solutions that worked for me but let's start with the basics first.

The issue that we're facing be described in detail here: http://www.maxdesign.com.au/articles/inline/

We are attaching a background-image to all elements that have the 'icon' attribute set. The advantage of doing this is that if we wanted to change a commonly used image, we'd only have to change it in one spot. Here's some of the code:


[icon] {
    padding-right: 20px;
    background: no-repeat center right;
}

[icon='required'] {
    background-image: url(../images/required.png);
}
[icon='toggle'] {
    background-image: url(../images/toggle.png);
}
[icon='addField'] {
    background-image: url(../images/add.png);
}
[icon='first'] {
    background-image: url(../images/btn_first.png);
}
[icon='last'] {
    background-image: url(../images/btn_last.png);
}
[icon='next'] {
    background-image: url(../images/btn_next.png);
}
[icon='prev'] {
    background-image: url(../images/btn_prev.png);
}

The image icon is visible in firefox, but not in IE 7. It's not at fault of IE (for once), because inline elements with padding on them has undefined behaviour and the CSS spec gives no details.


[icon] {
    padding-right: 20px;
    background: no-repeat center right;
}

We we're applying the icon attribute to Anchor elements as follows:

<a href="javascript:animatedcollapse.toggle('details')" icon="toggle" title="View Details"></a>


Solutions:

1) Adding a space

I stumbled upon this accidently while trying other possible solutions, and I haven't seen it documented anywhere else so it is worth mentioning. It's quite simple. If we add   inside the anchor element, then IE7 will display the icon correctly. The added side effect is that there will be a space. It works but then that means you have to add a silly   to all your elements.

2) Javascript/jQuery

The idea is to inspect all elements that have the icon attribute, and pull out the URL for the background-image and create a new element and assign the src attribute as follows:
<!--[if IE 7]>
    <script type="text/javascript">
    
        $(document).ready(function() 
        { 
        
            $("a[icon]").each(function() 
                    { 
                var iconUrl = $(this).css("background-image");
                iconUrl = iconUrl.replace(/"/g,"").replace(/url\(|\)$/ig, "");
                
                
                var imgEl = document.createElement('img');
                imgEl.src = iconUrl;
    
                $(this).css('icon','');
                this.removeAttribute("icon");
                
                $(this).append(imgEl);
                $(this).hover();
            }); 
        });
            
    </script>
<![endif]-->

It's not pretty, but if your project is already using jQuery and you have a template page, then you can add this to your template.

3)  Switching the CSS display property
 This is the best solution with the least amount code and less invasive. The idea is to trick IE 7 into using a display property of inline-block but then switching it back inline as follows:

[icon] {
    *display: inline-block;
}
[icon] {
    *display: inline;
    background: no-repeat right center;
    *position: absolute;
    padding-right: 20px;
}

The asteriks are IE 7 specific as mentioned here: http://css-tricks.com/how-to-create-an-ie-only-stylesheet/