Wednesday, December 15, 2010

jQuery Template Markup and JSP Expression Language (EL)

Maybe it is "great minds think alike"; both JSP Expression Language (EL) and jQuery Template use the
${}

as variable placeholders and evaluate it. Since JSP will be complied at server side first, any ${} in JSP file will be evaluated first, even it means for jQuery template. When your result page return to user's browser and jQuery template energy try to complie the template, you will find your ${} had been changed to variable value you store in Page, Session or Application context in your sever side.

Therefore, we need to escape ${} in JSP page which means for jQuery template or turn off Expression Language evaluate. There are two options:

1. escapse ${} in JSP page


In EL, you can use character ${'${'}} to be escapted as ${}

for example,
<script id="clientTemplate" type="text/html">
<li><a href="clients/${id}">${name}</a></li>
</script>

need to be escaped as:


<script id="clientTemplate" type="text/html">
<li><a href="clients/${'${'}id}">${'${'}name}</a></li>
</script>

This approach is good when your template is simple.

2. save jQuery template as separated file and disable its EL evaluation


if you have a lot of jQuery templates, it's better to extract them out to a seperated file.
<%@ page isELIgnored="true" %>
<script id="clientTemplate" type="text/html">
<li><a href="clients/${id}">${name}</a></li>
</script>
<script id="anotherTemplate" type="text/html">
<li><a href="clients/${id}">${name}</a></li>
</script>
Then include this file in your JSP pages need template:
<jsp:include page="jqTemplate.jsp"></jsp:include>

Tuesday, December 14, 2010

Find and Kill Running Windows Processes in Java

One of my friends asked me if it is possible to check a programming is running or not in Windows using Java. And close it if it is running. After a little bit research, I found the Java solution for his requirement.

The key is Runtime.getRuntime().exec(), you can run commands available in this platform. In Windows, the "tasklist" command will show you all the processes running (In Linux, you might want to look at "ps").
tasklist

The result of this command looks like this:

Image Name             PID Session Name Session#    Mem Usage
========================== ===================== ============
System Idle Process      0 Services            0         24 K
System                   4 Services            0      1,260 K
svchost.exe            896 Services            0      7,060 K
taskmgr.exe            868 Console             2     13,300 K
WINWORD.EXE           5412 Console             2     39,860 K
iexplore.exe          5256 Console             2     69,104 K
eclipse.exe           1112 Console             2      1,788 K
javaw.exe             4380 Console             2    555,552 K
cmd.exe               1500 Console             2      3,264 K
conhost.exe           3120 Console             2      7,188 K
bash.exe              3360 Console             2      7,840 K
sh.exe                3412 Console             2      7,456 K
java.exe               824 Console             2    317,116 K
Acrobat.exe           5484 Console             2     49,784 K

Here is the code to iterate and find running process:

 private static final String TASKLIST = "tasklist";

 public static boolean isProcessRunging(String serviceName) throws Exception {

  Process p = Runtime.getRuntime().exec(TASKLIST);
  BufferedReader reader = new BufferedReader(new InputStreamReader(
    p.getInputStream()));
  String line;
  while ((line = reader.readLine()) != null) {

   System.out.println(line);
   if (line.contains(serviceName)) {
    return true;
   }
  }

  return false;

 }

When you make sure the enemy process is runing, you can use "taskkill /IM xxx.exe" to kill it. For example, let's kill MS Word:

taskkill -IM WINWORD.EXE
Below is the code to kill process by name:
 private static final String KILL = "taskkill /IM ";
public static void killProcess(String serviceName) throws Exception {

  Runtime.getRuntime().exec(KILL + serviceName);

 }

Let's have a look how to use this process helper:
 public static void main(String args[]) throws Exception {
  String processName = "WINWORD.EXE";
  
  //System.out.print(isProcessRunging(processName));

  if (isProcessRunging(processName)) {

   killProcess(processName);
  }
 }

Friday, December 10, 2010

Dynamically Load Sidebar for Different Page in SiteMesh

It is often the case that your page need to load different sidebar, according to its content. After few tries, I finally figure it out in Sitemesh through "meta" tag.

1. In my project, I prepare two side bars, sidebar.jsp and postsidebar.jsp and place them in the "decorator" directory.




2. In the decorator, default.jsp, get decorator property meta.sidebar and set it to "sidebar" variable. then use jsp:include page to load specific sidebar.

<!-- sidebar -->
  <div id ="sidebar" class="span-7 last">
    
 <c:set var="sidebar" scope="request">
     <decorator:getProperty property="meta.sidebar"/>
 </c:set>
 
  <!-- if no sidebar setted, use default -->
  <c:if test="${empty sidebar}">
   <c:set var="sidebar" scope="request">sidebar</c:set>
  </c:if>
  
  <jsp:include page="${sidebar}.jsp"/>

  </div>

So in your result page, you can specific postsidebar by add the meta tag:
<meta name="sidebar" content="postsidebar" />

and the decorator will be translated into:
<jsp:include page="postsidebar.jsp"/>

Wednesday, December 8, 2010

File Upload with Uplodify and Spring MVC

It provides user better experience if you can provide a progress indicator when they upload file to server. But this leave you not too many choices but flash in the client. Here is a quick note when I use Uplodify , a jQuery plugin that employ flash to upload file to the server powered by Spring MVC.

Client Side


1. include necessary library
<script type="text/javascript" src="<c:url value='/scripts/jquery-1.4.4.min.js'/>"></script>
<link href="<c:url value='/components/uploadify/uploadify.css'/>" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="<c:url value='/components/uploadify/swfobject.js'/>"></script>
<script type="text/javascript" src="<c:url value='/components/uploadify/jquery.uploadify.v2.1.4.min.js'/>"></script>


2. leave a place holder for the input field
<input id="file_upload" name="file" type="file" />
You don't have to create a form for this filed. uplodify will take care of it for you.

3. initialize uploadify
$('#file_upload').uploadify({
   
       'uploader'  : '',
       'multi': false,
  
       'script'    : 'http://localhost:8080/myapp/file/upload/;jessionid=${pageContext.session.id}',
       'scriptData'  : {},
  
       'cancelImg' : '', 
       
       'sizeLimit'   : 5000000,
       'removeCompleted' : true,
       'auto'      : true,
      
      'fileDataName' : 'file',
       'onComplete' : function(event,ID,fileObj,response,data) {
      
        }

  
     });

1. I add sessionid in script, so in your server side you can get it since uploadify is flash, it won't keep sessionid.

2. 'fileDataName' : 'file', This parameter is very important, it must be matched with your Spring MVC Controller's parameter name, in my case, is @RequestParam MultipartFile file. Otherwise, you will get an MissingServletRequestParameterException, "Required MultifartFile parameter 'file' is not present.

Server Side


4. add apache's commons-fileupload dependency
<dependency>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
   <version>1.2.1</version>
  </dependency>

5. decalare multipartResolver in your dispatch-serverlet.xml
<bean id="multipartResolver"
  class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

6. Create FileUploadController
@Controller
@RequestMapping("/file")
public class FileUploadController {
 private static Log log = LogFactory.getLog(FileUploadController.class);
 @Autowired
 protected UploadService uploadService;

 @RequestMapping(value = "upload", method = RequestMethod.POST)
 public String processUpload(@RequestParam MultipartFile file,
   ModelMap modelMap, HttpServletRequest request) throws Exception {

  log.debug("========= upload file:" + file.getOriginalFilename());
                 //you can do something with the uploaded file
  //UploadedFile uploaded = uploadService.save(file);

  modelMap.addAttribute("file", uploaded);

  return "file";
 }
}

Monday, December 6, 2010

Create Mobile Decorator with Sitemesh and jQuery Mobile

In my previous post,Mobilize Your Java Web Application, I mentioned to provide a separate decorator for mobile user. In this post I will demonstrate how to achieve this:

1. automatically apply mobile decorator if the request came from mobile browser

2. leave it to user, if user choose the mobile version in their request parameter, such as "document/list?version=mobile".




First of all, let me show you the mobile decorator I developed using jQuery Mobile:



<!DOCTYPE html>
<html>
   <head>
   <meta charset="utf-8" />
   <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
   
   <decorator:title default="${title}" /> 
   
    <link rel="apple-touch-icon" href="img/myTouchIcon.png" />
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a2/jquery.mobile-1.0a2.min.css" />
 <script type="text/javascript" src="<c:url value='/scripts/jquery-1.4.4.min.js'/>"></script>
    <script src="http://code.jquery.com/jquery-1.4.4.min.js"></script>
 <script src="http://code.jquery.com/mobile/1.0a2/jquery.mobile-1.0a2.min.js"></script>
 </head>
<body>
 <div data-role="page">

   <header data-role="header">
  <h1>
    <img alt="logo" src="<c:url value='/images/logo.png'/>"></img>
  </h1>
   </header>

   <div data-role="content">
   <decorator:body />
   </div>

   <footer data-role="footer">
 <h4> www.ke-cai.net.com </h4>
   </footer>

 </div>

</body>
</html>

Create a sitemesh.xml and put it in "WEB-INF" folder, we're going to add two decorator mapping.

1.Mobile AgentDecoratorMapper

In Sitemesh, there is a AgentDecoratorMapper which will select decorator by user's agent string.
<mapper class="com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper">
   <param name="match.iPhone" value="mobile" />
   <param name="match.Android" value="mobile" />
   <param name="match.webos" value="mobile" />
   <param name="match.palm" value="mobile" />
   <param name="match.blackberry" value="mobile" />
   <param name="match.opera mini" value="mobile" />
  </mapper>

AgentDecoratorMapper will check user's agent string, if it contains "iphone","andorid" or others in our configuration, it will try to find the decorator end with "-mobile.jsp".

2. Mobile Version ParameterDecoratorMapper

<mapper
   class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
   <param name="decorator.parameter" value="version" />   
  </mapper>

We have to config another decorator in decorators.xml for this mapping:
<decorators defaultdir="/WEB-INF/decorators">
 <excludes>
  <pattern>/resources/*</pattern>
  <pattern>/file/upload**</pattern>
 </excludes>

 <decorator name="default" page="default.jsp">
  <pattern>**</pattern>
 </decorator>
 
 <decorator name="mobile" page="default-mobile.jsp">
 </decorator>

</decorators>

Now your mobile decorator will apply to request with parameter"?version=mobile".

Mobilize Your Java Web Application

Mobile web access is growing by 30% every year, so do consider to make your Java web application work well on a small screen. In this post, I'm going to analyze a typical java web application and make it mobile access ready.

Usually, a Java web application consist two parts:

  • 1. the layout template framework, such as Tiles, or Sitemesh.

  • 2. a web framework to handle request and return JSP result page, such as Struts, Spring MVC.

Take my favorite combination, Sitemesh for layout template engine and Spring MVC as web framework for example, there will be two (or three) step for a Sitemesh + Spring MVC web application to go:


for example, in my project, the default.jsp is the default decartor for PC browser. I personally use BlueprintCSS framework, jQuery and jQuery UI to tackle some cross browser problem.

The default-mobile.jsp is for mobile browser and jQuery Mobile can handle browser compatablity too.

For the result page, I also provide two version. Therefore, when user is using mobile phone, Spring MVC will intercept request and return the mobile version result page. Sitemesh will render the mobile version result with mobile decorator. So the mobile user will get tidy, fast mobile view.

In addition, if you intend to develop a mobile application for your web application, Phonegap might be your best choice since you can leverage your css, html and javascript skill and multi-mobile platform supported. Because of the cross domain restriction, JSONP supported will be very helpful for developer.