Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

Yeah. jQuery form validation is proving to be very nice. If you have been following this blog, you have seen how to set-up the standard validations and even create your own custom validation. One problem I had to solve was that the validation message broke my UI. I still needed the message, but I didn’t need it to display in the default location which is to the right of the field. That turn out to be very easy. First define an area where you want your validation messages to be displayed.

<form name="myForm" id="myForm" action="">
     <div id="myErrorLabelContainer"></div>
     <input class="required date dateRange" type="text" id="myField" name="myField">
</form>
<input type="submit" value="Go Validate"/>

The next step is to tell the jQuery Validation plugin that you want to use this for the error messages. This is accomplished with the errorLabelContainer option.

<script type="text/javascript">
    $(document).ready(function() {
        $('#executiveConsoleForm').validate({
            errorLabelContainer: "#myErrorLabelContainer"
        });
    });
</script>

This is just the beginning of error place. There is also the errorPlacement option that can be used to define logic to indicate where you want error messages to be displayed. A smal example of this can be found in the groups documentation

December 15th, 2010

Posted In: javascript, JQuery

Tags: , , ,

One Comment

My previous blog entry showed how to quickly add Jquery Validation. One that was not there was the ability to compare two fields that contain dates and validate that the field that should hold the older date was in-fact older. Here is how I created the custom validation.

First I defined the custom validation called dateRange and it’s error message. This allows me to dateRange as a CSS class name for validation purposes.

<script type="text/javascript">
     $(document).ready(function() {
        $.validator.addMethod("dateRange", function() {
            return new Date($("#olderDate").val()) < new Date($("#newerDate").val());
        }, "Please specify a correct date range<br/>The older date must be before the newer date.");

Then I set-up the form for validation. I added the groups option so that the plugin knows that the fields should be validated together. Without this validation, each field will be validated and if the validation failed, both fields would have error messages.

          $('#myForm').validate({
            groups: {
                dateRange: "olderDate newerDate"
            });
    });
</script>

All that is left is the HTML of the actual form. Here I create a form that has two input fields. I indicate that both fields are required, they must be dates and they should be in the correct chronological order.

<form name="myForm" id="myForm" action="">
     <input class="required date dateRange" type="text" id="olderDate" name="olderDate">
     <input class="required date dateRange" type="text" id="newerDate" name="newerDate">
     <input type="submit" value="Let's date validate"/>
</form>

December 15th, 2010

Posted In: javascript, JQuery

Tags: , , ,

One Comment

jQuery makes it pretty easy to create form validation. All it takes it first setting the form up to validate when it submits.

<script type="text/javascript">
     $(document).ready(function() {
          $('#myForm').validate();
     });
</script>

Then you indicate the type of validations that should occur. There are a couple of ways to do this. The easiest for me is to add the validations as if they are CSS classes for the individual fields. In this example, I indicate that I want the field to be required and the value should be a valid date. Some of the other validations that are available are email, minlength, maxlength, min, max. The entire list is available here

<form name="myForm" id="myForm" action="">
        <input class="required date" type="text" id="myId" name="myDate" size="10" value="${yesterday}">
</form>

Error display is handled for you automatically. Standard validation messages are already set-up and the messages appear in red to the right of any invalid field.

By default, the validation is not triggered until the field is submitted, but any fields flagged by invalid are re-checked when they are changed.

December 15th, 2010

Posted In: javascript, JQuery

One Comment

There are two date pickers. jQuery has one, but it is simplified. The one that I like to use is by Keith Wood. His datepicker plugin formed the basis of the jQuery datepicker plugin. Keith’s plugin is available here.

Here is an example of the calendar.  The calendar will have the following features:

  • default date (defaultDate)
  • maximum date (maxDate)
  • triggering icon

Here is the script for the calendar

$(document).ready(function() {
     $('#recentDate').datepick({
          defaultDate: -1,
          maxDate: -1,
          showTrigger: '#recentDateImg'
     });
});

Here is what the html looks like:

<label for="recentDate">
     Recent <input type="text" id="recentDate" name="recentDate" size="10" value="${yesterday}">
     <div style="display:none">
          <img id="recentDateImg"
               src="/intranet-templating/bhsi/js/images/calendar.gif"
               alt="Recent Date"
               class="trigger">
     </div>
</label>

Notice that the triggering icon is surrounded by a DIV that is set to not display. If this is not done, then 2 icons will be displayed.

This is what the screen will look like:

Here is what the calendar looks like when it is open.  Notice that the dates after yesterday are greyed-out and are not selectable.  This is the maxDate at work.

 

In this case, maxDate was specified as -1.  That means today’s date minus 1 day or yesterday.  You can specify a date that is relative to today by using d for days, w for weeks, m for months, y for years or just specify a date as a string or as javascript.  If you are using a relative date, you can string them together.  -1d -1m is a month from yesterday.  Positive and negative numbers are allowed.

December 8th, 2010

Posted In: javascript, JQuery

Leave a Comment

A needed feature of logging is to be able to identify which user caused the line of logging in the log file. Logback implements SLF4j and allows for tagging each log entry with information that the developer deems useful. Create a filter class to add the value to the MDC:

package com.bhsi;


import com.bhsi.dao.user.UserUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.MDC;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;


/** @author Norris Shelton */
public class UserLoggingFilter implements Filter {

    private final String -- USER_KEY = "userId";

    /**
     * Called by the web container to indicate to a filter that it is being placed into service. The servlet container
     * calls the init method exactly once after instantiating the filter. The init method must complete successfully before
     * the filter is asked to do any filtering work. <br><br>
     * <p/>
     * The web container cannot place the filter into service if the init method either<br> 1.Throws a ServletException
     * <br> 2.Does not return within a time period defined by the web container
     */
    public void init(FilterConfig filterConfig) throws ServletException {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    /**
     * The <code>doFilter</code> method of the Filter is called by the container each time a request/response pair is
     * passed through the chain due to a client request for a resource at the end of the chain. The FilterChain passed in
     * to this method allows the Filter to pass on the request and response to the next entity in the chain.<p> A typical
     * implementation of this method would follow the following pattern:- <br> 1. Examine the request<br> 2. Optionally
     * wrap the request object with a custom implementation to filter content or headers for input filtering <br> 3.
     * Optionally wrap the response object with a custom implementation to filter content or headers for output filtering
     * <br> 4. a) <strong>Either</strong> invoke the next entity in the chain using the FilterChain object
     * (<code>chain.doFilter()</code>), <br> * 4. b) <strong>or</strong> not pass on the request/response pair to the next
     * entity in the filter chain to block the request processing<br> * 5. Directly set headers on the response after
     * invocation of the next entity in the filter chain.
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    throws IOException, ServletException {
        boolean successfulRegistration = false;

        HttpServletRequest req = (HttpServletRequest) request;

        successfulRegistration = registerUsername(req.getRemoteUser());

        try {
            chain.doFilter(request, response);
        } finally {
            if (successfulRegistration) {
                MDC.remove(-- USER_KEY);
            }
        }

    }

    /**
     * Register the user in the MDC under -- USER_KEY.
     * @param userId the id of the user
     * @return true id the user was successfully registered
     */
    private boolean registerUsername(String userId) {
        boolean isRegisterUser = false;
        if (StringUtils.isNotBlank(userId)) {
            MDC.put(-- USER_KEY, UserUtil.getSimpleUserName(userId));
            isRegisterUser = true;
        }
        return isRegisterUser;
    }


    /**
     * Called by the web container to indicate to a filter that it is being taken out of service. This method is only
     * called once all threads within the filter's doFilter method have exited or after a timeout period has passed. After
     * the web container calls this method, it will not call the doFilter method again on this instance of the filter.
     * <br><br>
     * <p/>
     * This method gives the filter an opportunity to clean up any resources that are being held (for example, memory, file
     * handles, threads) and make sure that any persistent state is synchronized with the filter's current state in
     * memory.
     */
    public void destroy() {
        //To change body of implemented methods use File | Settings | File Templates.
    }
}

Add the filter class to the web.xml

    <filter>
        <filter-name>UserLoggingFilter</filter-name>
        <filter-class>com.bhsi.UserLoggingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>UserLoggingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

Modify the logback pattern to use the value added by the filter to the current logging thread.

<configuration>
    <!--
        WARN or higher goes to stdout (catalina.out)
    -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>WARN</level>
        </filter>
        <encoder>
            <Pattern>%d{yyyy-MM-dd HH:mm:ss} intranet-templating:%X{userId}|%-5level-%msg %class.%method:%line %xException{full} %n</Pattern>
        </encoder>
    </appender>
    <!--
        INFO or higher goes to the log file that is in the tomcat logs directory.
        The files are rolled daily to the tomcat/logs/intranet-templating. 
    -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>/opt/vignette/software/tomcat/logs/intranet-templating.log</file>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <if condition='property("HOSTNAME").contains("309")'>
                <then>
                    <level>DEBUG</level>
                </then>
                <else>
                    <level>INFO</level>
                </else>
            </if>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>/opt/vignette/software/tomcat/logs/intranet-templating/intranet-templating.%d{yyyy-MM-dd}.log</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <Pattern>%d{yyyy-MM-dd HH:mm:ss}|%X{userId}|%-5level-%msg %class.%method:%line %xException{full} %n</Pattern>
        </encoder>
    </appender>

    <logger name="org.hibernate" level="WARN"/>
    <!--<logger name="org.springframework" level="INFO"/>-->
    <logger name="org.apache.commons" level="INFO"/>
    <logger name="org.apache.velocity" level="INFO"/>
    <logger name="org.displaytag" level="INFO"/>
    <logger name="org.apache.axis" level="INFO"/>
    <root level="DEBUG">
        <appender-ref ref="FILE"/>
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

December 6th, 2010

Posted In: logback

Leave a Comment

This is such a common problem. You want to have one file that you deploy everywhere, but you want it to behave differently based upon where you deploy it. An example is you want logback to log debug in dev, but info in production. This is easy to do with the conditional processing. Check out logback conditional processing for other options.

<configuration>
    <!--
        WARN or higher goes to stdout (catalina.out)
    -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>WARN</level>
        </filter>
        <encoder>
            <Pattern>%d{yyyy-MM-dd HH:mm:ss} intranet-templating:%X{userId}|%-5level-%msg %class.%method:%line %xException{full} %n</Pattern>
        </encoder>
    </appender>
    <!--
        INFO or higher goes to the log file that is in the tomcat logs directory.
        The files are rolled daily to the tomcat/logs/intranet-templating. 
    -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>/opt/vignette/software/tomcat/logs/intranet-templating.log</file>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <if condition='property("HOSTNAME").contains("309")'>
                <then>
                    <level>DEBUG</level>
                </then>
                <else>
                    <level>INFO</level>
                </else>
            </if>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>/opt/vignette/software/tomcat/logs/intranet-templating/intranet-templating.%d{yyyy-MM-dd}.log</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <Pattern>%d{yyyy-MM-dd HH:mm:ss}|%X{userId}|%-5level-%msg %class.%method:%line %xException{full} %n</Pattern>
        </encoder>
    </appender>

    <logger name="org.hibernate" level="WARN"/>
    <!--<logger name="org.springframework" level="INFO"/>-->
    <logger name="org.apache.commons" level="INFO"/>
    <logger name="org.apache.velocity" level="INFO"/>
    <logger name="org.displaytag" level="INFO"/>
    <logger name="org.apache.axis" level="INFO"/>
    <root level="DEBUG">
        <appender-ref ref="FILE"/>
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

December 6th, 2010

Posted In: logback

Leave a Comment

Maven has two places for configuration files that need to be deployed to the classpath. You need to place a logback configuration file in both.

The main logback configuration file is named logback.xml and should be in src/main/resources of your maven project.

<configuration>
    <!--
        WARN or higher goes to stdout (catalina.out)
    -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>WARN</level>
        </filter>
        <encoder>
            <Pattern>%d{yyyy-MM-dd HH:mm:ss} intranet-templating:%X{userId}|%-5level-%msg %class.%method:%line %xException{full} %n</Pattern>
        </encoder>
    </appender>
    <!--
        INFO or higher goes to the log file that is in the tomcat logs directory.
        The files are rolled daily to the tomcat/logs/intranet-templating. 
    -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>/opt/vignette/software/tomcat/logs/intranet-templating.log</file>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <if condition='property("HOSTNAME").contains("309")'>
                <then>
                    <level>DEBUG</level>
                </then>
                <else>
                    <level>INFO</level>
                </else>
            </if>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>/opt/vignette/software/tomcat/logs/intranet-templating/intranet-templating.%d{yyyy-MM-dd}.log</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <Pattern>%d{yyyy-MM-dd HH:mm:ss}|%X{userId}|%-5level-%msg %class.%method:%line %xException{full} %n</Pattern>
        </encoder>
    </appender>

    <logger name="org.hibernate" level="WARN"/>
    <!--<logger name="org.springframework" level="INFO"/>-->
    <logger name="org.apache.commons" level="INFO"/>
    <logger name="org.apache.velocity" level="INFO"/>
    <logger name="org.displaytag" level="INFO"/>
    <logger name="org.apache.axis" level="INFO"/>
    <root level="DEBUG">
        <appender-ref ref="FILE"/>
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="NORRIS-EMAIL"/>
    </root>
</configuration>

The test logback configuration file is named logback-test.xml and should be in src/test/resources of your maven project. If logback sees both files (e.g. test build), then the -test file will be the logback configurations.

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{yyyy-MM-dd HH:mm:ss} %X{userId} %-5level - %msg %class.%method:%line %xException{full} %n </Pattern>
        </encoder>
    </appender>

    <!--default to logging info-->
    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

December 6th, 2010

Posted In: logback, Maven

Leave a Comment

LinkedIn Auto Publish Powered By : XYZScripts.com