Tuesday, December 13, 2011

CSS3 Decoration for Internet Explorer 6 - 9

I recently discovered a javascript library named CSS3 PIE. PIE makes Internet Explorer 6-9 capable of rendering several of the most useful CSS3 decoration features. The list currently includes border-radius, box-shadow, border-image, multiple background images, and linear-gradient as background image. The property that interests me most though is border-radius, since I hate having to create new images every time I want rounded corners with a different radius.

To get started with PIE download the files from their website (css3pie.com). The download includes multiple files but in most cases all you really need is the PIE.htc file. Copy the PIE.htc file into your web project and then reference it using the CSS behavior property. The behavior property is proprietary to Internet Explorer so all other browsers will ignore it. PIE uses the standard CSS3 border-radius property so you will need to add that too, as well as the -moz and -webkit versions for Firefox, Chrome, and Safari. Below is an example:

<html>
<head>

<style>
.rounded
{
 behavior: url(pie.htc);
 border-radius: 10px;
 -moz-border-radius: 10px;
 -webkit-border-radius: 10px;
 background-color: red;
 color: white;
}
</style>

</head>

<body>

<div class="rounded">
 TESTING
</div>

</body>
</html>

After adding PIE you should have CSS3 decoration support for all the major browsers with the exception of Opera although personally I never really consider Opera much anyways.

Note: I've noticed that PIE's rendering of rounded corners is quite slow in Internet Explorer. Because of this, I've decided NOT to use PIE on my blog, so anyone who is unfortunate enough to use Internet Explorer version 8 or lower will see squared corners instead of rounded corners. Upgrade your browser or switch to a better one.

Friday, November 4, 2011

Generic Method For Converting From DBNull

public static T FromDB<T>(object o)
{
   return o is DBNull ? default(T) : (T)o;
}

The method above is written in C# using generics. This method is used to cast weakly typed objects returned from a DataRow to strongly typed objects and it will automatically handle the conversion of DBNull. This method can also be used with nullable types which is convenient since capturing null values is often important when querying databases.

Below is a full example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            object i1 = 7;
            object i2 = DBNull.Value;
            object i3 = 3;
            object i4 = DBNull.Value;
            object i5 = "TEST";
            object i6 = DBNull.Value;

            int o1 = FromDB<int>(i1);
            int o2 = FromDB<int>(i2);
            int? o3 = FromDB<int?>(i3);
            int? o4 = FromDB<int?>(i4);
            string o5 = FromDB<string>(i5);
            string o6 = FromDB<string>(i6);

            Console.WriteLine("o1 = {0}", o1); //can't be null since its value type
            Console.WriteLine("o2 = {0}", o2); //can't be null since its value type
            Console.WriteLine("o3 = {0} {1}", o3, o3 == null ? "(NULL)" : "");
            Console.WriteLine("o4 = {0} {1}", o4, o4 == null ? "(NULL)" : "");
            Console.WriteLine("o5 = {0} {1}", o5, o5 == null ? "(NULL)" : "");
            Console.WriteLine("o6 = {0} {1}", o6, o6 == null ? "(NULL)" : "");
        }

        public static T FromDB<T>(object o)
        {
            return o is DBNull ? default(T) : (T)o;
        }
    }
}

The output would be:

o1 = 7
o2 = 0
o3 = 3
o4 = (NULL)
o5 = TEST
o6 = (NULL)

Saturday, September 24, 2011

Configuring Apache HTTP Server for PHP

First install Apache HTTP Server and then install PHP.

Next you must edit the httpd.conf file located in the conf directory of your Apache Install Directory. Add the follow lines to the end of the file (the lines may already exist; if so then verify they are correct and make any required changes):

#BEGIN PHP INSTALLER EDITS - REMOVE ONLY ON UNINSTALL
PHPIniDir "<PHP_INSTALL_DIRECTORY>"
LoadModule php5_module "<PHP_INSTALL_DIRECTORY>\php5apache2_2.dll"
<FilesMatch \.php$>
 SetHandler application/x-httpd-php
</FilesMatch>
#END PHP INSTALLER EDITS - REMOVE ONLY ON UNINSTALL

Replace the placeholder for the PHP Install Directory with a valid value and restart the Apache server. This example is specific to Apache 2.2 installed on Windows, so you may need to make slight tweaks if using a different version or operating system. See the following link for more information:

http://www.php.net/manual/en/install.php

Monday, September 19, 2011

How to Connect to DB2 with .NET

First you must install either the IBM Data Server Client or the IBM Data Server Runtime Client. The IBM Data Server Client has some additional developer tools but they are optional, so if you are searching for the most lightweight install then choose the IBM Data Server Runtime Client.

Next you must determine if a license is required. If you are connecting through a DB2 Connect Gateway then a license is not required, but if you are connecting directly to the DB2 Database then a license must be activated on the client computer.

To activate the license you must locate the db2conpe.lic file on your DB2 / DB2 Connect install CD. Once you have located this file, copy it to the client computer in the following directory: "C:\Program Files\IBM\SQLLIB\BIN" (location where your DB2 Client was installed). Now open a command prompt and change the directory to "C:\Program Files\IBM\SQLLIB\BIN" and execute this command: "db2licm -a db2conpe.lic". It should say that your license was successfully activated. You can verify this by typing "db2licm -l".

Now you are ready to start programming. Open Visual Studio and start a new console project. Before you start add a new reference (Project -> Add Reference) and browse to "C:\Program Files\IBM\SQLLIB\BIN\netf20\IBM.Data.DB2.dll".

Now copy and paste this code into your class file:

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using IBM.Data.DB2;

namespace ConnectToDB2
{
    class Program
    {
        static void Main(string[] args)
        {
            string sql = "SELECT * FROM SYSIBM.SYSDUMMY1";
            DB2Connection con = new DB2Connection("Database=<DATABASE>;UserID=<USER_ID>;Password=<PASSWORD>;Server=<SERVER>:<PORT>");
            con.Open();

            DB2Command cmd = new DB2Command(sql, con);
            DB2DataReader reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                Console.WriteLine(reader.GetString(0));
            }
        }
    }
}

Obviously replace the placeholders in the connection string with valid values.

Saturday, September 17, 2011

Client-Side Caching of Dynamic Content with Java

To achieve optimum performance and results when caching content you should try to set both the Expires header and the Last-Modified header.

The Expires should be set to a date in the future. It instructs the browser to cache the content until it expires when the Expires date is surpassed. If the content is very volatile (changes frequently) then the Expires date should be set to a lower value (near in the future) otherwise it should be set to a higher value (far in the future). This type of caching is referred to as "hard" caching because the browser never reconnects to the server again until the appointed time. Because of this, this type of caching is relatively fast.

The Last-Modified header should be set to a date in the past. It instructs the browser to cache the content unless it has been modified since the Last-Modified date was last set. If the content has since been modified then the Last-Modified date should be updated to a new value (the date the content was modified) to reflect this. This type of caching is referred to as "soft" caching because the browser always reconnects to the server again to check if the content has been modified. Because of this, this type of caching is relatively slow.

The Last-Modified header works in conjunction with the If-Modified-Since header. The first time the content is requested the server sets the Last-Modified date in the response. The browser then receives this response and caches the content along with the Last-Modified date. In subsequent requests the browser sets the If-Modified-Since date equal to the Last-Modified date that was previously cached. The server then receives the request and gets the If-Modified-Since date for the purpose of comparing it to the content's Last-Modified date.

The server is responsible for comparing the If-Modified-Since date and the Last-Modified date to determine if the browser has the most recent version of the content. If the dates are equal then browser already has the most recent version of the content and the server responds with an HTTP status code of 304 (Not Modified) which is the signal for the browser to reload the content from its cache. If the dates are not equal then the browser does not already have the most recent version of the content and the server responds by sending the updated content in its entirety along with the updated Last-Modified date.

When you combine the Expires header and the Last-Modified header the resulting behavior will be a hybrid of the two types of caches which will be the best in terms of both performance and flexibility.

Below is sample code that demonstrates how to set both the Expires header and the Last-Modified header in a Java Servlet. This Servlet makes use of the getLastModified method which automatically sets the Last-Modified date to the method's return value which is then compared to the If-Modified-Since date. Please note that the order in which the Expires header is set and the getLastModified method is called is important. The Expires header must always be set first which is why the service method is overridden for this purpose.

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.util.*;

public class CacheTestServlet extends HttpServlet
{
 private static long hits = 0;
 private static Date date;
 
 //This method sets the Expires date 15 seconds in the future
 //Typically the Expires date would be set to a higher value
 public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
 {
  response.setDateHeader("Expires", new Date().getTime() + 15000);
  super.service(request, response);
 }
 
 //This method updates the Last-Modified date on every other request
 //This is meant to simulate content that is modified occasionally
 //Typically the Last-Modified date would be retrieved from a file or database
 public long getLastModified(HttpServletRequest request)
 {
  hits++;
  if (hits % 2 == 1)
  {
   date = new Date();
   System.out.println("FULL HIT");
  }
  else
  {
   System.out.println("PARTIAL HIT");
  }
  
  return date.getTime() / 1000 * 1000;
 }
 
 public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
 {
  response.getWriter().println("The current date & time is " + new Date());
 }
}

Below is a summary of the Servlet's output:

  1. The first time you load the page you will see the current date & time and the phrase "FULL HIT" will be printed.
  2. If you immediately reload the page, then the page will be reloaded from the browser's cache without reconnecting to the server. The date & time will not change and neither the phrase "FULL HIT" nor the phrase "PARTIAL HIT" will be printed because the server does not actually receive any requests.
  3. If you wait at least 15 seconds before reloading the page, then the browser will reconnect to the server to determine if the content has been modified but since the Last-Modified date has not changed it will reload the page from the browser's cache as opposed to reloading it from the server. The the date & time will not change but the phrase "PARTIAL HIT" will be printed.
  4. If you immediately reload the page, then the page will be reloaded from the browser's cache without reconnecting to the server. The date & time will not change and neither the phrase "FULL HIT" nor the phrase "PARTIAL HIT" will be printed because the server does not actually receive any requests.
  5. If you wait at least 15 seconds before reloading the page, then the browser will reconnect to the server to determine if the content has been modified and since the Last-Modified date has changed it will reload the page from the server as opposed to reloading it from the browser's cache. The date & time will change and the phrase "FULL HIT" will be printed.
  6. And so forth...

Tip: Pressing F5 in your browser will cause the browser to ignore any "soft" caches and reload the page. Pressing CTRL+F5 in your browser will cause the browser to ignore any "hard" caches and reload the page.

Here is a good link regarding caching:

http://code.google.com/speed/page-speed/docs/caching.html

Monday, July 25, 2011

X11 Forwarding

X11 forwarding enables the execution of a GUI (Graphic User Interface) program on a Linux/Unix server, even if the server is normally only available remotely via command line. This is accomplished by forwarding the display environment of the server to your localhost through an X11 tunnel.

Below is an example of how to enable and configure X11 forwarding on a Windows client:

  1. Download and install PuTTY. It is freely available for download here.
  2. Download and install Xming. It is freely available for download here.
  3. Start Xming if it is not already running.
  4. Start PuTTY and enter the Host Name or IP address of the server but do not connect yet. On the left, expand on the "Connection" node, expand the "SSH" node, and select the "X11" node. Check the box labelled "Enable X11 forwarding". Finally connect to the server by clicking the "Open" button.
  5. Once logged into the server, verify that the XAuth package is installed. The command to check the package will vary by Linux/Unix distribution. On Red Hat the command is "rpm -qa | grep xauth". The XAuth package is usually required for X11 forwarding.
  6. Install the XAuth package if it isn't already installed. Again the command to install the package will vary by Linux/Unix distribution. On Red Hat the command is "yum -y install xorg-x11-xauth". Root privileges are required to install the package.
  7. Verify that X11 forwarding is enabled in the file "/etc/ssh/sshd_config". Open the file and search for a line that reads "X11Forwarding yes". If the line is missing then add it; if the value is "no" then change it to "yes". Root privileges are required to open the file.
  8. Finally, execute the command that requires a GUI interface. After you execute the command Xming should launch the GUI program in a new window.

Monday, June 6, 2011

Javascript "this" Keyword

In Javascript the "this" always refers the "owner" of the function being executed, or rather, to the object that a function is a method of. Below are a few different examples:

In this first example "this" refers to the global "window" object. If you do not reference a specific object then "this" refers to the global "window" object by default.

function doSomething()
{
  alert(this == window); //the result will be true
}
doSomething();

In this second example "this" refers to the HTML/DOM object that was retrieved using the getElementById method.

var element = document.getElementById('something');
function doSomething()
{
  alert(this == element); //the result will be true
}
element.onclick = doSomething;

In this third example "this" refers to the object that was instantiated using the "new" keyword. This is very similar to the previous example.

var object = new Object();
object.doSomething = function()
{
  alert(this == object); //the result will be true
}
object.doSomething();

Please be aware that you must pass "this" along as a parameter if you reference another function from an HTML event attribute such as onclick.

Click Here
function doSomething(reference)
{
  var element = document.getElementById('something');
  alert(reference == element); //the result will be true
  alert(this == element); //the result will be false
  alert(this == window); //the result will be true 
}

JSF 2.0 Overview

7/12/2014: I've not used JSF since I wrote this post years ago, but I've come to the conclusion that a complicated, abstracted lifecycle is a bad thing for a web framework. Therefore I would not recommend using JSF.

I have been learning JSF 2.0 (Java Server Faces 2.0) over the last few days. I never used the original JSF 1.0 implementation so I was slightly intimidated when I read mostly horrendous reviews regarding it. However, my understanding is that the second implementation is much improved and most of the problems have been corrected. I still have a few reservations about the complexity of the application lifecycle, but hopefully my concerns will diminish as I continue to learn the framework.

JSF is a Java web framework. Defined in greater detail, it is essentially a MVC framework, a GUI controls and handlers framework, and an AJAX framework. It competes with other frameworks like Servlet/JSP, Seam, Spring, Struts, Tapestry, Wicket, etc. (although in some cases two frameworks can be used together collaboratively i.e. JSF+Seam, JSF+Spring, etc). The original version of JSF attempted to collaborate with JSP but it quickly became clear that JSF potential was being burdened by JSP limitations. As a result, newer versions of JSF do not make use of JSP at all! Instead it uses a new technology called Facelets. That's a large paradigm shift for many of us who have been using JSP since we first learned Java web development. The current version of JSF is 2.0. JSF 1.0 had some noteable problems, but JSF 2.0 addresses many of them. JSF 2.0 also adds new features like AJAX support. With JSF 2.0 it is possible to add AJAX support with 100% Java code without writing any JavaScript code!

JSF is an officially supported framework. This may be perceived as an advantage compared to other 3rd party frameworks like Struts. There are many different flavors of JSF: Mojarra (basic Sun/Oracle implementation), MyFaces (basic Apache implementation), IceFaces (extended Sun/Oracle implementation), Tomahawk (extended Apache implementation), RichFaces (extended JBoss implementation), etc. Anyone is free to implement their own version of JSF so long as they adhere to the JSR specification. Following the JSR guidelines guarantees that all implementations will have the same basic functionality and features. However, implementors are allowed to go above and beyond the specification. Therefore, some implementations may have additional functionality and features that is vendor specific and not officially supported. This is both an advantage and a disadvantage. If you use an extended JSF implementation with fuller features and functionality you may eventually suffer from vendor lock-in.

To run JSF 2.0 the minimum requirements are Java 5.0 or greater, and an application server that supports Servlet spec 2.5 or greater. Unfortunately, this is a fairly stiff requirement since it eliminates the majority of older application servers. Supported servers include Tomcat 6+, Glassfish 3+, Weblogic 11+, JBoss 5.2+, etc. Newer versions of J2EE compliant servers like Glassfish, Weblogic, and JBoss will have automatic support for JSF. Since Tomcat is only a servlet container and is not J2EE compliant, you must manually install JSF (include 2 jar files). Although there are many different implementations of JSF created by many different vendors, they should run on any application server as long as the minimum requirements are met regardless of the vendor. So, for example, the RichFaces (JBoss) implementation should work ok on the Tomcat (Apache) application server.

Since JSF 2.0 is relatively new the documentation is still a little sparse. I recommend these tutorials for starting:

http://www.coreservlets.com/JSF-Tutorial/jsf2/

I found these tutorials to be excellent overall, except the AJAX tutorial was a little difficult to follow.

Sunday, June 5, 2011

Javascript Classes

The Javascript syntax is very loose, so it it possible to define a Javascript class using a variety of techniques. I prefer the following method because it is easiest to comprehend and most closely resembles the traditional syntax used in other programming languages. First, define a normal function to serve as the class definition (Javascript does not actually have a "class" keyword, instead it uses functions to simulate classes). Second, define properties and methods inside the function by using the "this" keyword. Last, instantiate an object from the function by using the "new" keyword. Pass in any arguments the same as you would with a normal constructor. Below is an example:

function Apple(type)
{
 this.type = type;
 this.color = 'red';

 this.getInfo = function()
 {
  return this.color + ' ' + this.type + ' apple';
 };
}

var apple = new Apple('macintosh');
apple.color = 'reddish';
alert(apple.getInfo());

Note: Some people prefer to use the "prototype" keyword to define Javascript classes because it is more memory efficient. You can read more about this alternative method by following the link at the bottom of this post.

I copied and paraphrased most of the information in this post from the following link:

http://www.phpied.com/3-ways-to-define-a-javascript-class/

Cloud Computing (and Google App Engine)

There's a lot of buzz about cloud computing lately, but often the term is used in a vague or ambiguous way (such as Microsoft's "Take it to the Cloud!" commercials). All the hype may leave you scratching your head and asking the question, "what exactly does cloud computing mean and why is it so popular?" The simplest definition of cloud computing refers to "the on-demand provision of computational resources (data, software) via a computer network, rather than from a local computer" (Wikipedia). Recently, Google has taken this definition to an extreme with the introduction of their Chromebooks; these are computers but all of the applications and data are stored on the web instead of on the harddrive.

So basically cloud computing is a movement to host more applications on the web instead of your computer. This definition alone is very loose, not particularly extraordinary, and does not fully explain the mystique of cloud computing. Actually, there are a few other qualifiers often attributed to cloud computing that contribute to its popularity especially regarding web development. A cloud service usually is elastic, is fully managed by the provider, and is sold on demand. I will attempt to explain these attributes in more detail in the following paragraphs.

A cloud service is elastic - "a user can have as much or as little of a service as they want at any given time". A cloud application is automatically scaled and load balanced as traffic increases; this is accomplished by automatically spinning up additional servers and distributing requests across these servers to meet demand. The obvious advantage here is that you do not have to manage these details yourself in the case that your application is growing larger and requires more resources (this leads into the next point).

A could service is fully managed by the provider - "the consumer needs nothing but a personal computer and Internet access". Cloud applications tend to run on a complex distributed network of virtualized machines that are both efficient and highly available. If one server goes down the burden will be shifted and another server will instantly replace it (guaranteeing nearly 100% up-time). This sophisticated architecture is fully supplied by the provider and mostly runs in the background; it does not require any physical resources from or direct administration by the user.

A cloud service is sold on demand - in other words you "pay for only for what you use" measured as combination of bandwidth usage, storage usage, number of requests, number of web service/api calls, etc. As a result, a user can take full advantage of the cloud services for a minimal investment. This can mean significant cost savings for businesses, especially small to medium sized businesses. Because of this cloud computing has become increasingly popular during this weak economy.

A few of the most prominent cloud providers are Amazon, Rackspace, Microsoft Azure, and Google. Although I believe Amazon is probably the most popular of these offerings, I have only experimented with Google App Engine, and it is my favorite so far because it supports a Java development environment and... it's free! (within limits, see below).

Google App Engine generously allows a free quota of 500MB of storage and 5 million page views per month. As a result I have used Google App Engine to host my Java applications for the past couple of years without paying a dime. If you want to host simple applications for personal use then I would highly recommend Google App Engine. However, there are some limitations associated with Google App Engine that can be frustrating. Therefore, if you want to host complex applications for commercial use then I would probably recommend a different provider such as Amazon.

I copied, quoted, and paraphrased much of the information in this post from the following link:

http://searchcloudcomputing.techtarget.com/definition/cloud-computing

Monday, May 2, 2011

Recursively Search Files Containing Text in Unix

find . -exec grep -H -n -I 'hello' {} \;

The above command will search all files in the current directory and any sub directories for the text 'hello'. Replace 'hello' with whatever text you are trying to find.

Saturday, April 2, 2011

Query Month to Date, Year to Date, Rolling 12 Months, & Prior Year Sales

Synopsis:

If using Oracle use the trunc and numtoyminterval functions; if using SQL Server use the datediff function.


Oracle Month to Date:

SELECT sum(TRANSACTION_AMOUNT)
FROM TRANSACTIONS
WHERE TRANSACTION_DATE BETWEEN trunc(sysdate, 'MONTH') and sysdate

Oracle Year to Date:

SELECT sum(TRANSACTION_AMOUNT)
FROM TRANSACTIONS
WHERE TRANSACTION_DATE BETWEEN trunc(sysdate, 'YEAR') and sysdate

Oracle Rolling 12 Months:

select sum(TRANSACTION_AMOUNT)
FROM TRANSACTIONS
WHERE TRANSACTION_DATE between trunc(sysdate - numtoyminterval(12, 'MONTH'), 'MONTH') and sysdate

Oracle Prior Year:

SELECT sum(TRANSACTION_AMOUNT)
FROM TRANSACTIONS
WHERE trunc(TRANSACTION_DATE, 'YEAR') = trunc(sysdate - numtoyminterval(1, 'YEAR'), 'YEAR')

SQL Server Month to Date:

SELECT sum(TRANSACTION_AMOUNT)
FROM TRANSACTIONS
WHERE datediff(month, TRANSACTION_DATE, getdate()) = 0
AND TRANSACTION_DATE <= getdate()

SQL Server Year to Date:

SELECT sum(TRANSACTION_AMOUNT)
FROM TRANSACTIONS
WHERE datediff(year, TRANSACTION_DATE, getdate()) = 0
AND TRANSACTION_DATE <= getdate()

SQL Server Rolling 12 Months:

SELECT sum(TRANSACTION_AMOUNT)
FROM TRANSACTIONS
WHERE datediff(month, TRANSACTION_DATE, getdate()) <= 12
AND TRANSACTION_DATE <= getdate()

SQL Server Prior Year:

SELECT sum(TRANSACTION_AMOUNT)
FROM TRANSACTIONS
WHERE datediff(year, TRANSACTION_DATE, getdate()) = 1

Friday, March 11, 2011

Pivot Tables

Suppose you have the following table named TRANSACTIONS, which has two columns, ITEM_ID and PRICE. Below is an example of the table:

ITEM_ID PRICE
1 $5.00
1 $6.00
2 $5.00
3 $7.00
3 $2.00
4 $3.00

A user would like to see this data pivoted, where each distinct ITEM_ID becomes a column header, and the data becomes the sum of PRICE grouped by ITEM_ID. Below is the desired result:

1 2 3 4
$11.00 $5.00 $9.00 $3.00

You could probably achieve this result by writing four separate queries then joining the individual results together but there is perhaps a better way to do it. The trick is to use the CASE keyword in combination with the SUM aggregate function. Here’s how to do it:

SELECT
sum(case when ITEM_ID = 1 then PRICE else 0 end) AS [1],
sum(case when ITEM_ID = 2 then PRICE else 0 end) AS [2],
sum(case when ITEM_ID = 3 then PRICE else 0 end) AS [3],
sum(case when ITEM_ID = 4 then PRICE else 0 end) AS [4]
FROM TRANSACTIONS

Prevent SQL Injection Attacks in Java

To prevent hackers from exploiting your Java website:

NEVER do this (manually concatenate SQL):

String sql = "select 1 from user where userId='" + userId + "' and password='" + password + "'";

Instead do this (use prepared statements):

String sql = "select 1 from user where userId = ? and password = ?";
PreparedStatement prepStmt = con.prepareStatement(sql);
prepStmt.setString(1, userId);
prepStmt.setString(2, password);

When you use prepared statements it passes the parameters directly to the database independent of the SQL statement so that the hacker never has a chance to alter them.

Clean your JSP Code with JSTL & JSP EL

Note: After writing this blog I realized 3rd party templating engines like Velocity or FreeMarker are viable alternatives to JSTL & JSP EL. However JSTL & JSP EL are the standard and have official support while the others do not. I may write a couple follow up blogs in the future detailing how to use Velocity or FreeMarker.

Below is an example of mixing HTML with JSP scriptlets and expressions:

<% if (user.getRole().equals("member")) { %>
    <p>Welcome, <%=user.getName() %>!</p>
<% } else { %>
    <p>Welcome, guest!</p>
<% } %>

The mixing and HTML's syntax and Java's syntax makes the code ugly and hard to read and understand. It can also encourage bad coding practices; it is sometimes tempting to add additional business logic in your JSP files. JSTL and JSP EL were created to remedy this situation.

JSTL (JSP Standard Tag Library) is a standardized tag library that can be used to replace JSP scriptlet tags (<% %>) inside of JSP files. It has tags for all the most common operations necessary to create your JSP file (conditional tags, looping tags, formatting tags, etc).

JSP EL (JSP Expression Language) is an expression language that can be used to replace JSP expression tags (<%= %>) inside your JSP files. JSP EL has many convenient shortcuts and allows for a much simpler syntax to manipulate application data.

JSTL has integrated support for JSP EL; JSP EL can be used inside of the JSTL tag attributes. If your application server supports JSP 2.0 specification or greater then JSP EL can also be used outside of the JSTL tag attributes; otherwise you will need to wrap your expression using the JSTL out tag (see example below). Using JSTL combined with JSP EL the above code becomes:

<c:choose>
<c:when test="${user.role == 'member'}">
    <p>Welcome, <c:out value="${user.name}"/>!</p>
</c:when>
<c:otherwise>
    <p>Welcome, guest!</p>
</c:otherwise>
</c:choose>

As you can see the code is much improved compared to its original state. Finally, you can rid yourself of all the ugly JSP tags.

JSTL may or may not be included with your application server. If it is not included you can download the JAR files and add them to your project's WEB-INF/lib folder or to your application server's shared library folder. The JSTL version you need to download will vary based on which JSP specification version your application server supports. Below is a table that maps the JSTL version to the JSP specification version:

Servlet VersionJSP VersionJSTL VersionJava EE Version
2.52.11.25
2.42.01.11.4
2.31.21.01.2

Note: I am having great difficulty trying to find downloads for the older versions of JSTL. The download links on the Jakarta site are broken. I have not found a solution to this problem yet.

For more information see the following links:

Portal Breadcrumbs

In a portal application all the navigation is theoretically pre-defined, since the structure of the portal application is defined in a hierarchal way. For example, to the right is the structure of the portal file created using Weblogic Portal 8.1.

To create the breadcrumbs for this portal application we simply have to iterate through the structure of the portal file, starting with the current page and working upwards towards the root.

The code to accomplish this is below (slight tweaks may be required for your own use). This code is specific to Weblogic Portal 8.1 but the basic concept should be applicable to all portal platforms. In this particular example all the code is saved in a single JSP file. (Sorry, I know the code is ugly):

<%@ page import="com.bea.netuix.servlets.controls.page.PagePresentationContext,
     com.bea.netuix.servlets.controls.page.BookPresentationContext,
     com.bea.netuix.servlets.controls.application.DesktopPresentationContext
     com.bea.netuix.servlets.controls.PresentationContext,
     com.bea.portlet.PageURL,
     java.util.List" %>
<%

ArrayList breadcrumbs = new ArrayList();

PagePresentationContext pageCtx = PagePresentationContext.getPagePresentationContext(request);

do
{
 PagePresentationContext parentPageCtx = pageCtx.getParentPagePresentationContext();

 String title;
 String url; 

 if (pageCtx instanceof BookPresentationContext)
 {
  title = pageCtx.getTitle();
  url = PageURL.createPageURL(request, response, ((BookPresentationContext)pageCtx).getDefaultPage()).toString();
 }
 else
 {
  title = pageCtx.getTitle();
  url = PageURL.createPageURL(request, response, pageCtx.getDefinitionLabel()).toString();
 }

 if (parentPageCtx == null)
 {
  title = "Home";
 }

 if (!(
   parentPageCtx != null &&
   parentPageCtx instanceof BookPresentationContext &&
   ((BookPresentationContext)parentPageCtx).getDefaultPage().equals(pageCtx.getDefinitionLabel())
  ))
 {
  breadcrumbs.add(new String[] {title, url});
 }

 pageCtx = parentPageCtx;
}
while (pageCtx != null);

%>

<p class="x-small bold">

<%

for (int i = breadcrumbs.size() - 1; i >= 0; i--)
{
 String title = ((String[])breadcrumbs.get(i))[0];
 String url = ((String[])breadcrumbs.get(i))[1];

 if (i > 0)
 {
 %>
  <a class="breadcrumb-hyperlink" href="<%=url%>"><%=title%></a> >
 <%
 }
 else
 {
 %>
  <%=title%>
 <%
 }
}

%>

</p>

Javascript Obfuscator

Have some sensitive javascript code?

In general this is a bad idea since javascript code is client-side and therefore can easily be manipulated or hacked by the user. If you are worried about your javascript code being tampered with you should probably move it to the server-side.

In some rare cases though it may be helpful to scramble your javascript source code so that it is much more difficult to hack. Again, we can never make javascript code 100% secure (the process of scrambling your javascript code is reversible), but you can at least make it difficult for the user to access it. This is enough to deter the average computer-nerd-wannabe. The process of scrambling the code is called obfuscation. There is a free javascript obfuscator available at the following link:

http://www.javascriptobfuscator.com/default.aspx

Integrate Java with Microsoft SQL Server Reporting Services 2005/2008

The best way to accomplish this is through the use of the ReportExecution2005 web service that is provided out of the box by Microsoft SQL Server Reporting Services.

  1. Start Eclipse and create a new workspace named ssrsClient

  2. Create a new Java project called ssrsClient

  3. Configure the advanced Axis settings so that "Generate code for all elements, even unreferenced ones" is checked, and so that "Timeout in seconds" is set to -1. (See my previous post, Configure Advanced Axis Settings from Eclipse, for more details)

  4. Create a web service client proxy for the ReportExecution2005 web service; the URL for the WSDL definition will be http://<HOST>/reportserver/ReportExecution2005.asmx?wsdl. (See my previous post, Consume Any Web Service Using Eclipse + Axis, for more details)

  5. Enable NTLM Authentication in Axis by adding the Jakarta Commons HTTPClient and Codec JAR files to the classpath. (See my previous post, Enable NTLM Authentication in Axis, for more details)

  6. Create a new Java Class named Test.java

  7. Copy and paste the following code into Test.java (overwrite the existing code)
    import com.microsoft.schemas.sqlserver._2005._06._30.reporting.reportingservices.*;
    import com.microsoft.schemas.sqlserver._2005._06._30.reporting.reportingservices.holders.*;
    import java.net.URL;
    import javax.xml.rpc.holders.ByteArrayHolder;
    import javax.xml.rpc.holders.StringHolder;
    import javax.xml.soap.SOAPException;
    import org.apache.axis.message.SOAPHeaderElement;
    
    public class Test
    {
     public static void main(String[] arg)
     {
      ReportExecutionServiceSoapStub service = getService();
      ParameterValue[] parameters = new ParameterValue[1];
      parameters[0] = new ParameterValue();
      parameters[0].setName("<PARAMETER_1_NAME>");
      parameters[0].setValue("<PARAMETER_1_VALUE>");
      
      try
      {
       ExecutionInfo info = service.loadReport("/<FOLDER_NAME>/<REPORT_NAME>", null); //Load report
       setExecutionId(service, info.getExecutionID()); //You must set the session id before continuing
       service.setExecutionParameters(parameters, "en-us"); //Set report parameters
       
       String format = "HTML4.0"; //Valid options are HTML4.0, MHTML, EXCEL, CSV, PDF, etc
       String deviceInfo = "<DeviceInfo><Toolbar>False</Toolbar><HTMLFragment>True</HTMLFragment></DeviceInfo>"; //Only generate an HTML fragment
       ByteArrayHolder result = new ByteArrayHolder();
       StringHolder extension = new StringHolder();
       StringHolder mimeType = new StringHolder();
       StringHolder encoding = new StringHolder();
       ArrayOfWarningHolder warnings = new ArrayOfWarningHolder();
       ArrayOfStringHolder streamIDs = new ArrayOfStringHolder();   
       service.render(format, deviceInfo, result, extension, mimeType, encoding, warnings, streamIDs); //Render report to HTML
       
       System.out.println(new String(result.value)); //Prints the report HTML; this could be embedded in a JSP
      }
      catch (Exception e)
      {
       e.printStackTrace();
      }
      
     }
     
     public static void setExecutionId(ReportExecutionServiceSoapStub service, String id) throws SOAPException
     {
      SOAPHeaderElement sessionHeader = new SOAPHeaderElement("http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices", "ExecutionHeader");
      sessionHeader.addChildElement("ExecutionID").addTextNode(id);
      service.setHeader(sessionHeader);
     }
     
     public static ReportExecutionServiceSoapStub getService()
     {
      try
      {
       String endpoint = "http://<HOST>/reportserver/ReportExecution2005.asmx";   
       ReportExecutionServiceSoapStub service = (ReportExecutionServiceSoapStub)new ReportExecutionServiceLocator(getEngineConfiguration()).getReportExecutionServiceSoap(new URL(endpoint));
       service.setUsername("<DOMAIN>\\<USER_NAME>");
       service.setPassword("<PASSWORD>");
       return service;
      }
      catch (Exception e)
      {
       e.printStackTrace();
      }
      
      return null;
     }
     
     public static org.apache.axis.EngineConfiguration getEngineConfiguration()
     {
      java.lang.StringBuffer sb = new java.lang.StringBuffer();
      
      sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
      sb.append("<deployment name=\"defaultClientConfig\"\r\n");
      sb.append("xmlns=\"http://xml.apache.org/axis/wsdd/\"\r\n");
      sb.append("xmlns:java=\"http://xml.apache.org/axis/wsdd/providers/java\">\r\n");
      sb.append("<globalConfiguration>\r\n");
      sb.append("<parameter name=\"disablePrettyXML\" value=\"true\"/>\r\n");
      sb.append("<parameter name=\"enableNamespacePrefixOptimization\" value=\"true\"/>\r\n");
      sb.append("</globalConfiguration>\r\n");
      sb.append("<transport name=\"http\" pivot=\"java:org.apache.axis.transport.http.CommonsHTTPSender\"/>\r\n");
      sb.append("<transport name=\"local\" pivot=\"java:org.apache.axis.transport.local.LocalSender\"/>\r\n");
      sb.append("<transport name=\"java\" pivot=\"java:org.apache.axis.transport.java.JavaSender\"/>\r\n");
      sb.append("</deployment>\r\n");
      
      return new org.apache.axis.configuration.XMLStringProvider(sb.toString());
     }
    }
    

  8. Replace all the placeholders with actual values:
    Lines 13-17
    Replace the report parameter names/values with your own report parameter names/values. Increase the size of the array if you have more than one parameter.

    Line 21
    Replace the report path with the path to your own report. Do NOT include the .RDL extension in this path.

    Line 55
    Replace the report host with your own report host. This is the endpoint for the ReportExecution2005 web service.

    Lines 57-58
    Replace the domain, username, and password with your own. These are the Windows credentials that will be used to access the report.

  9. Execute the code. You should see the report HTML printed as output. If you face an authentication error (401) then verify NTLM is enabled and also try adding
    
    3
    
    
    
    
    in your rsreportserver.config under reportserver for basic authentication with SSRS (Thanks Sridhar Iyer).

    If you still receive an authentication error (401) then it may be that SSRS and/or Windows is using NTMLv2 (verified for Windows 7). See JB's comment near the bottom of this page and also visit the following link for more information: http://devsac.blogspot.com/2010/10/supoprt-for-ntlmv2-with-apache.html. (Thanks JB!)

  10. Package all the classes into a JAR file and copy it into the WEB-INF/lib folder of your web app. Use the same technique as above to embed the rendered report HTML in a JSP file.

  11. Build a nice user interface that accepts the appropriate report parameters and passes them through to the web service. Add an "Export" drop down list on the report page that allows users to export the report to different formats like Excel, PDF, CSV, etc. You do not have to completely reload the report every time you export it to a different format; once you initially obtain the Report Execution ID you can save it and re-use for rendering to other formats.

Enable NTLM Authentication in Axis

By default Axis is not configured to support NTLM Authentication. To enable NTLM Authentication Axis must be configured to use the Jakarta Commons HTTPClient library. NTLM Authentication is often required to use Windows based web services.

There are a few different methods for accomplishing this, but this is probably the quickest and simplest technique:

  1. Download and copy both the Jakarta Commons HTTPClient and Codec JAR files into your project and add them to the classpath.

  2. Copy and paste the following method into your own class; append it to the end of your pre-existing class or create a separate utility class:
     public static org.apache.axis.EngineConfiguration getEngineConfiguration()
     {
      java.lang.StringBuffer sb = new java.lang.StringBuffer();
      
      sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
      sb.append("<deployment name=\"defaultClientConfig\"\r\n");
      sb.append("xmlns=\"http://xml.apache.org/axis/wsdd/\"\r\n");
      sb.append("xmlns:java=\"http://xml.apache.org/axis/wsdd/providers/java\">\r\n");
      sb.append("<globalConfiguration>\r\n");
      sb.append("<parameter name=\"disablePrettyXML\" value=\"true\"/>\r\n");
      sb.append("<parameter name=\"enableNamespacePrefixOptimization\" value=\"true\"/>\r\n");
      sb.append("</globalConfiguration>\r\n");
      sb.append("<transport name=\"http\" pivot=\"java:org.apache.axis.transport.http.CommonsHTTPSender\"/>\r\n");
      sb.append("<transport name=\"local\" pivot=\"java:org.apache.axis.transport.local.LocalSender\"/>\r\n");
      sb.append("<transport name=\"java\" pivot=\"java:org.apache.axis.transport.java.JavaSender\"/>\r\n");
      sb.append("</deployment>\r\n");
      
      return new org.apache.axis.configuration.XMLStringProvider(sb.toString());
     }

    Note: It's probably a good idea to separate the XML markup from the Java code (move XML markup to separate file). I just left the two joined together for the sake of simplicity / laziness since it eliminated one extra step from this blog posting.

  3. When you create an instance of your web service locator class pass the getEngineConfiguration() method as an argument in the constructor like this:
    MyWebServiceStub stub = (MyWebServiceStub)new MyWebServiceLocator(getEngineConfiguration());

  4. Set your user name and password like this:
    stub.setUsername("<DOMAIN>\\<USER_NAME>"); //Must use this format
    stub.setPassword("<PASSWORD>");

For more information see the following links:

Monday, March 7, 2011

Configure Advanced Axis Settings from Eclipse

Occasionally you may need to configure advanced Axis settings from Eclipse. Some common reasons for this are:
  • You need to increase or disable the Axis timeout if you are trying to consume a very large or complex web service.

  • You need to generate code for all elements, even unreferenced ones.

To access these settings, follow these instructions:

  1. Click Window -> Preferences from the Eclipse menu bar.

  2. Expand the Web Services node and then select Axis Emitter in the tree view located in the left pane.

You should see the Axis Emitter screen which contains a variety of options for both Wsdl2Java and Java2Wsdl. These settings are workspace specific so you will need to redefine them again if you switch workspaces. From this screen you can check the "Generate code for all elements, even unreferenced ones" checkbox, and you can set the "Timeout in seconds" to -1 to disable it (see screenshot below).

At the time of writing this tutorial I am using Eclipse Helios with the J2EE extensions installed; options may vary slightly if using a different version.

Sunday, March 6, 2011

Consume Any Web Service Using Eclipse + Axis

  1. Start Eclipse and create a new workspace named wsTest (click File -> Switch Workspace -> Other…)



  2. Create a new Java Project named wsTest (click File -> New -> Java Project)



  3. Create a new Web Service Client Proxy (click File -> New -> Other -> Web Services -> Web Service Client). In this case we are consuming a free, public web service that returns weather information for the United States. The URL for the WSDL definition is http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl.



  4. Create a new Java Class named Test.java (click File -> New -> Class)



  5. Copy and paste the following code into Test.java (overwrite the existing code):
    import com.cdyne.ws.WeatherWS.*;
    import java.net.URL;
    
    public class Test
    {
     public static void main(String[] arg)
     {
      try
      {
       WeatherSoapStub service = (WeatherSoapStub)new WeatherLocator().getWeatherSoap(new URL("http://ws.cdyne.com/WeatherWS/Weather.asmx"));
       WeatherReturn weather = service.getCityWeatherByZIP("47710");
       System.out.println("Location: " + weather.getCity() + ", " + weather.getState());
       System.out.println("Description: " + weather.getDescription());
       System.out.println("Temperature: " + weather.getTemperature() + " degrees");
      }
      catch (Exception e)
      {
       e.printStackTrace();
      }
     }
    }
    

    Note that we set the endpoint URL on line 10. The endpoint URL is typically the same as the WSDL definition URL except the endpoint URL does not include the ?WSDL query string parameter.

  6. Execute the code (click Run -> Run)

    You should see something resembling the following output:

    Location: Evansville, IN
    Description: Sunny
    Temperature: 49 degrees

At the time of writing this post I am using Eclipse Helios with the J2EE extensions installed; options may vary slightly if using a different version.




How It Works

Eclipse is executing the Axis Wsdl2Java process which parses the WSDL file and translates it into a set of Java client files that you can then use in your own application. It is possible to accomplish the same thing outside of Eclipse by directly executing the Axis Wsdl2Java process yourself.