Saturday, August 30, 2008

MyEclipse Ajax Tools

MyEclipse Ajax Workbench™

The MyEclipse Ajax Workbench™ is a special Eclipse workbench which provides MyEclipse Ajax tools in a single window.  When a MyEclipse Ajax Web Browser is created or a JavaScript debug session is launched, the MyEclipse Ajax Workbench™ window is activated and the web page and information describing the web page is displayed in the browser and support views.

The MyEclipse Ajax Workbench™ consists of the following features:

  • MyEclipse Ajax Workbench Window
  • MyEclipse Ajax Perspective
  • MyEclipse Ajax Web Browser
  • DOM Inspector View
  • DOM Source View
  • JavaScript Console View
  • JavaScript Scripts Inspector View
  • Ajax Monitor View
  • Instant-on JavaScript Debugging

The following figure depicts the typical layout of the MyEclipse Ajax Workbench™.  The highlighted elements are described in further detail in subsequent sections of this document.


The MyEclipse Ajax Workbench™




MyEclipse Ajax Perspective

The MyEclipse Ajax Perspective is a user customizable layout of user-interface views, editors, menus and toolbar actions.  The perspective's default layout can be seen in the figure above. The MyEclipse Ajax Perspective is opened by default when the MyEclipse Ajax Workbench™ is created, but can be accessed via the perspective shortcut pulldown.


Perspective shortcut





MyEclipse Ajax Web Browser

The MyEclipse Ajax Workbench™ provides an integrated version of the Mozilla browser called the MyEclipse Ajax Web Browser which provides standard web browser capabilities as well as support for the all of the related Ajax views that are discussed in the Ajax Related Views section.

In addition, the MyEclipse Ajax Web Browser provides JavaScript debugging facilities.  When a JavaScript debug session is launched the MyEclipse Ajax Workbench™ will open and the MyEclipse Ajax Web Browser will display the JavaScript application that is being debugged.  The JavaScript scripts that are loaded will be displayed in the JavaScript Scripts Inspector.

The MyEclipse Ajax Web Browser provides standard web browser facilities as well as the DOM Selection tool which enables you to determine the DOM nodes which correspond with selected HTML elements in the browser.  


MyEclipse Ajax Browser


The MyEclipse Ajax Web Browser also provides a source view page that displays the HTML source of the current page in the browser as shown.


Ajax Web Browser Source View

How to use the MyEclipse Ajax Web Browser

The easiest method for launching the Ajax Web Browser from the MyEclipse Ajax Perspective is to use the Launch MyEclipse Ajax Web Browser action the main toolbar (see the figure below).  This action can be found in many of the MyEclipse development perspectives.


Launch Ajax Web Browser action

An alternative method for launching the Ajax Web Browser is from the New File Wizard in eclipse as depicted ( File->New->MyEclipse->Web->Ajax Web Browser).


Launching a new MyEclipse Ajax Web Browser from File->New

MyEclipse Ajax Web Browser Actions

The Ajax Web Browser provides standard web browser actions including forward, back, open URL, refresh, and stop loading.  In addition to the standard actions it provides two non-standard actions. The first, Clear browser cache, removes all saved data from the browser's cache. The second, the DOM selection action, allows you to select regions within the browser and have the corresponding DOM elements selected in the DOM inspector. This is an easy way to determine how changes in your document are affecting the structure of your document and vice versa.


Ajax Web Browser Actions

To use DOM selection, click the DOM selection button and then use Ctrl+Click in the browser as shown.


Using the DOM Selection Tool to quickly navigate the DOM




Ajax Related Views

The MyEclipse Ajax Web Browser allows you to preview your web applications from within MyEclipse, however it's true power lies in the supporting views that surround it. 

  • The DOM Inspector allows you to view the structure of the document currently loaded in the browser. 
  • The DOM Source allows you to view the dynamic HTML source of the DOM nodes currently selected in the DOM Inspector. 
  • The DOM Watcher can monitor the changes that happen over a period of time for a particular element.
  • The JavaScript view can evaluation DOM nodes and execute JavaScript on the current DOM document.
  • The CSS View shows extended design information for CSS and allows for dynamic update of CSS attributes on DOM node.
  • The Ajax Request Monitor allows you to inspect your asynchronous calls and is much easier than using a TCP/IP monitor. 
  • The JavaScript Console displays the errors that arise during the execution of your JavaScript application. 
  • The JavaScript Scripts Inspector allows you to see all of the JavaScript scripts that are loaded by web pages both local and remote.

The MyEclipse Ajax Perspective includes all of these views by default. If you have closed a view and wish to re-open it you can access these views from the Ajax Perspective via the Window->Show View submenu as is depicted.


Opening Ajax Related Views via Window->Show View

DOM Inspector

The DOM Inspector displays a real-time view of the current browser's document object model (DOM).  The DOM Inspector displays the DOM using a tree of document nodes and an attributes editor which displays detailed information for the selected node.  In the figure below, the Ajax Web Browser has loaded the Google home page and the corresponding DOM is depicted by the DOM Inspector.

Notice that the DOM Inspector allows you to inspect the box model, DOM attributes, and computed styles of each node. The box model allows you to inspect how each node will be displayed, the DOM attributes allows you to inspect the HTML attributes of the selected node, and the computed style allows you to introspect the CSS style that was computed by the browser for the selected node.

As you select nodes in the DOM Inspector, the corresponding objects in the browser will temporarily flash to reveal their location.  


DOM Inspector

Using the DOM Inspector you can dynamically change the attributes of some tags. In the next figure, the width and height attributes of the IMG node have been adjusted dramatically for effect using the Attributes Editor as shown.


Using the DOM Attributes Editor to dynamically change DOM element attributes

The DOM Inspector has a Search Filter capability that allows searching nodes by 3 different search criteria.

  1. Name Filter
  2. ID Filter
  3. Class Filter

In the following, the Name filter has been activated and the search criteria is "DIV".  Notice how only the DIV elements are shown in the DOM Inspector.


DOM Inspector Search

Each node in the DOM Inspector has several actions that can be performed on it through the context-menu.  The figure below shows all of the DOM node related actions that are available for any node in the DOM Inspector.


DOM Node Actions

DOM Source View

The DOM Source view displays the dynamic source for the element selected in the DOM Inspector View.  This is useful if any Ajax routines in your application are modifying the DOM on the page because the DOM Source view allows you to see the dynamic source that is no longer available in the Browser source page.

There are several actions available on the DOM Source view that are used to interact with the corresponding DOM node.  There is also a Source Status field that displays the current status of the DOM source with respect to the Node in the browser.

DOM Source view actions

  1. Update Browser source with changes
  2. Refresh source from browser
  3. Validate DOM Source


    DOM Source actions

The following figure illustrates the potential of the DOM Source View.  If the example below, a chat application uses a DIV element to add new chat messages.  In this figure, the chat DIV has been selected and in the DOM Source you can see the DIV element is initially empty.  


Using the DOM Source to view dynamic DOM elements

In the next figure, a new chat message has appeared via an Ajax request and the DOM Source view indicates that there have been changes to this node in the DOM Source.


DOM Source status changes to show that selected element has changed

Now that the DOM Source has changed the "Refresh" action can be used to update the DOM Source with the latest version of the Node source as shown.


Refreshing the changes to the DOM Node

DOM Watcher

The DOM Watcher can monitor the events or changes that are associated with any selected or referenced node in the browser.  In the figure below, a DIV element in the browser page has been selected and the "Start Watching" action has been used to monitor any events that fire off of that element.


DOM Watcher view starts watch on a DIV element

If any events fire from this DIV element, those events and their changes will be listed in the DOM Watcher.  In this figure, the DIV element which was hidden has now been made visible through javascript and you can see the style attribute change.


DOM Watcher shows the attribute change to the element that is being watched

By default all events will be logged in the DOM Watcher.  However, you can modify the list of events that are "watched" through the "Settings..." menu action as shown.


Settings for supported events in the DOM Watcher view

JavaScript View

The JavaScript view allows evaluation of any DOM node as a JavaScript object.  Simply right-click on any DOM node and choose "Evaluate Node" for it to be shown in the JavaScript view as shown.


Evaluation of DOM Node in JavaScript view

The JavaScript expression field can handle general evaluation of JavaScript code as shown.


General evaluation of JavaScript code

CSS View

The CSS View shows extended information for elements that are selected in the DOM Inspector.  The CSS View shows the following 4 types of extended CSS information:

  • Style Rules
  • Computed Styles
  • Box Model
  • Diffs

CSS properties can be added or edited using the actions as shown.


CSS Styles

The Box Model for a particular element can be displayed in the CSS View as shown.  Modification of the box model is possible by using the Navigation Controls.


Box Model in CSS View

Ajax Request Monitor

The Ajax Request Monitor allows you to inspect the requests and responses your JavaScript application sends and receives. It displays each request/response pair in a table. Selecting an entry in this table displays the headers for each request/response. The body tab allows you to see the body of each request.


The Ajax Request Monitor


JavaScript Console

The JavaScript Console displays messages that the browser produces while loading pages and style sheets, as well as JavaScript warnings and errors. The view can be filtered to display only messages of a certain type.


The JavaScript Console displaying CSS warnings.

JavaScript errors and exceptions are also shown in the JavaScript Console as shown.


JavaScript error shown in JavaScript console

JavaScript Scripts Inspector

The JavaScript Scripts Inspector displays all of the scripts that are loaded during the rendering of a web page. In order for the scripts view to populate with scripts you must be running a JavaScript debug session. The easiest way to do this is to select the Instant-on JavaScript Debugging action located in the toolbar next to the New Ajax Web Browser action.


The JavaScript Scripts Inspector when no JavaScript Debug Session is active.

Once the JavaScript Scripts Inspector has been populated you can double click on a URL or function in the scripts view to open an editor to display the source of that URL or function. The editor opened will be read only, but it will allow you to set breakpoints and debug the JavaScript application.

For more information on JavaScript debugging in MyEclipse see the JavaScript Development and Debugging Tutorial.


The JavaScript Scripts Inspector displaying URLs and functions.




JavaScript Editor

The MyEclipse JavaScript Editor provides advanced language specific editing features such as:

Code-Assist

The JavaScript editor provides code-assist proposals for your current context whenever you press the Ctrl+Space key combination.  Each proposal includes a small graphic indicator of whether the JavaScript proposal is supported by IE and Netscape/Mozilla/Firefox. If a browser compatibility indicator is grayed out then the proposal is not supported by that browser.


JavaScript content-assist example

Local JavaScript variables and functions are also made available in the code-assist proposals.


Local JavaScript Function completion

Syntax Checking

The JavaScript editor provides "as-you-type" syntax checking and shows syntax errors in multiple locations to make it easy to see where errors are in your JavaScript code.


"As-you-type" Syntax checking

Validation

Validation problems are indicated as warning markers in the JavaScript Editor, Problems view and in the Package Explorer view. To view problem details, in the JavaScript fly-over a warning marker in the left margin as shown.


Viewing JavaScript validation warnings

Outline View

The outline view depicts a structured view of the functions and variables of a JavaScript Editor. The variables in the list may be filtered using the "Show Variables" action from the view's menubar.


Outline view with activated menu

Source Actions: Formatting/Quick Comment

The JavaScript editor can quickly format either highlighted sections or the entire JavaScript file.  This action is available in the Source menu, editor Context-menu, or using the Ctrl+F shortcut.


Format action

To toggle on or off one or more single line comments select the region to comment and enter Ctrl+Shift+C .



Commented region after Ctrl+Shift+C
 

Editor Preferences

The JavaScript editor has several source related preference pages that allow you configure different aspects of editing JavaScript.


JavaScript Preference page

The JavaScript Source page configures options for formatting source and content-assist.  Validation options are also available.


JavaScript Source preference page

JavaScript styles preference page allows customization of syntax highlighting.


JavaScript Styles preference page

The JavaScript validator can be enabled/disabled by configuring the options in the main validation preference page.




--
ఇట్లు మీ,
చంద్రశేఖర్.

Replace special charecters with '-' in the given string using JavaScript


 <script language="JavaScript">
    var temp1;
    var temp = new String('Thi\'s is a te!!!!s$t st>ri9ng... S"o??? What#...');
    document.write(temp + '<br>');
    temp =  temp.replace(/[^a-zA-Z 0-9]+/g,'-');
    document.write(temp + '<br>');
    temp1=temp.replace(/\s/g,'-');
    document.write(temp1 + '<br>');
    </script>
--
ఇట్లు మీ,
చంద్రశేఖర్.

Friday, August 29, 2008

Log4J

Logging within the context of program development constitutes inserting statements into the program that provide some kind of output information that is useful to the developer. Examples of logging are trace statements, dumping of structures and the familiar System.out.println or printf debug statements. log4j offers a hierarchical way to insert logging statements within a Java program. Multiple output formats and multiple levels of logging information are available.

By using a dedicated logging package, the overhead of maintaining thousands of System.out.println statements is alleviated as the logging may be controlled at runtime from configuration scripts. log4j maintains the log statements in the shipped code. By formalising the process of logging, some feel that one is encouraged to use logging more and with higher degree of usefulness.

In order to use the tools we are about to install it is necessary to setup the operating environment so that the tools know where to find stuff they need and the operating system knows where to find the tools. A understanding of how to do this is essential as you will be asked to change the operating environment. I have comprehensively covered this in documents entitled Configuring A Windows Working Environment and Configuring A Unix Working Environment.

  1. Download the log4j distribution from http://jakarta.apache.org/log4j/docs/download.html.

  2. Extract the archived files to some suitable directory.

  3. Add the file dist/lib/log4j-1.2.6.jar to your CLASSPATH environment variable.

  4. Download http://apache.rmplc.co.uk/dist/xml/xerces-j/Xerces-J-bin.2.6.0.zip and unzip it to a temporary directory. Copy the files xercesImpl.jar and xmlParserAPIs.jar to some permanent location and append their paths to the CLASSPATH environment variable.

The use of log4j revolves around 3 main things:

  1. public class Logger

    Logger is responsible for handling the majority of log operations.

  2. public interface Appender

    Appender is responsible for controlling the output of log operations.

  3. public abstract class Layout

    Layout is responsible for formatting the output for Appender.

The logger is the core component of the logging process. In log4j, there are 5 normal levels Levels of logger available (not including custom Levels), the following is borrowed from the log4j API (http://jakarta.apache.org/log4j/docs/api/index.html):

  • static Level DEBUG

    The DEBUG Level designates fine-grained informational events that are most useful to debug an application.

  • static Level INFO

    The INFO level designates informational messages that highlight the progress of the application at coarse-grained level.

  • static Level WARN

    The WARN level designates potentially harmful situations.

  • static Level ERROR

    The ERROR level designates error events that might still allow the application to continue running.

  • static Level FATAL

    The FATAL level designates very severe error events that will presumably lead the application to abort.

In addition, there are two special levels of logging available: (descriptions borrowed from the log4j API http://jakarta.apache.org/log4j/docs/api/index.html):

  • static Level ALL

    The ALL Level has the lowest possible rank and is intended to turn on all logging.

  • static Level OFF

    The OFF Level has the highest possible rank and is intended to turn off logging.

The behaviour of loggers is hierarchical. The following table illustrates this:

A logger will only output messages that are of a level greater than or equal to it. If the level of a logger is not set it will inherit the level of the closest ancestor. So if a logger is created in the package com.foo.bar and no level is set for it, it will inherit the level of the logger created in com.foo. If no logger was created in com.foo, the logger created in com.foo.bar will inherit the level of the root logger, the root logger is always instantiated and available, the root logger is assigned the level DEBUG.

There are a number of ways to create a logger, one can retrieve the root logger:

Logger logger = Logger.getRootLogger();

One can create a new logger:

Logger logger = Logger.getLogger("MyLogger");

More usually, one instantiates a static logger globally, based on the name of the class:

static Logger logger = Logger.getLogger(test.class);

All these create a logger called "logger", one can set the level with:

logger.setLevel((Level)Level.WARN);

You can use any of 7 levels; Level.DEBUG, Level.INFO, Level.WARN, Level.ERROR, Level.FATAL, Level.ALL and Level.OFF.

The Appender controls how the logging is output. The Appenders available are (descriptions borrowed from the log4j API http://jakarta.apache.org/log4j/docs/api/index.html):

  1. ConsoleAppender: appends log events to System.out or System.err using a layout specified by the user. The default target is System.out.

  2. DailyRollingFileAppender extends FileAppender so that the underlying file is rolled over at a user chosen frequency.

  3. FileAppender appends log events to a file.

  4. RollingFileAppender extends FileAppender to backup the log files when they reach a certain size.

  5. WriterAppender appends log events to a Writer or an OutputStream depending on the user's choice.

  6. SMTPAppender sends an e-mail when a specific logging event occurs, typically on errors or fatal errors.

  7. SocketAppender sends LoggingEvent objects to a remote a log server, usually a SocketNode.

  8. SocketHubAppender sends LoggingEvent objects to a set of remote log servers, usually a SocketNodes

  9. SyslogAppendersends messages to a remote syslog daemon.

  10. TelnetAppender is a log4j appender that specializes in writing to a read-only socket.

One may also implement the Appender interface to create ones own ways of outputting log statements.

A ConsoleAppender can be created like this:

ConsoleAppender appender = new ConsoleAppender(new PatternLayout());

Which creates a console appender, with a default PatternLayout. The default output of System.out is used.

A FileAppender can be created like this:

          FileAppender appender = null;           try {              appender = new FileAppender(new PatternLayout(),"filename");           } catch(Exception e) {}         

The constructor in use above is:

FileAppender(Layout layout, String filename)            Instantiate a FileAppender and open the file designated by filename.         

Another useful constructor is:

FileAppender(Layout layout, String filename, boolean append)            Instantiate a FileAppender and open the file designated by filename.          

So that one may choose whether or not to append the file specified or not. If this is not specified, the default is to append.

A WriterAppender can be created like this:

          WriterAppender appender = null;           try {             appender = new WriterAppender(new PatternLayout(),new FileOutputStream("filename"));           } catch(Exception e) {}         

This WriterAppender uses the constructor that takes a PatternLayout and an OutputStream as arguments, in this case a FileOutputStream is used to output to a file, there are other constructors available.

The Appender must have have an associated Layout so it knows how to format the output. There are three types of Layout available:

  1. HTMLLayout formats the output as a HTML table.

  2. PatternLayout formats the output based on a conversion pattern specified, or if none is specified, the default conversion pattern.

  3. SimpleLayout formats the output in a very simple manner, it prints the Level, then a dash '-' and then the log message.

Here is a very simplistic example of a program implementing a SimpleLayout and FileAppender:

import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.SimpleLayout; import org.apache.log4j.FileAppender; public class simpandfile {    static Logger logger = Logger.getLogger(simpandfile.class);    public static void main(String args[]) {       SimpleLayout layout = new SimpleLayout();        FileAppender appender = null;       try {          appender = new FileAppender(layout,"output1.txt",false);       } catch(Exception e) {}        logger.addAppender(appender);       logger.setLevel((Level) Level.DEBUG);        logger.debug("Here is some DEBUG");       logger.info("Here is some INFO");       logger.warn("Here is some WARN");       logger.error("Here is some ERROR");       logger.fatal("Here is some FATAL");    } }         

You can download it: simpandfile.java. And checkout the output produced: output1.txt.

Here is a very simplistic example of a program implementing a HTMLLayout and WriterAppender:

import java.io.*; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.HTMLLayout; import org.apache.log4j.WriterAppender; public class htmlandwrite {    static Logger logger = Logger.getLogger(htmlandwrite.class);    public static void main(String args[]) {       HTMLLayout layout = new HTMLLayout();        WriterAppender appender = null;       try {          FileOutputStream output = new FileOutputStream("output2.html");          appender = new WriterAppender(layout,output);       } catch(Exception e) {}        logger.addAppender(appender);       logger.setLevel((Level) Level.DEBUG);        logger.debug("Here is some DEBUG");       logger.info("Here is some INFO");       logger.warn("Here is some WARN");       logger.error("Here is some ERROR");       logger.fatal("Here is some FATAL");    } }         

You can download it: htmlandwrite.java. And checkout the output produced: output2.html.

Here is a very simplistic example of a program implementing a PatternLayout and ConsoleAppender:

import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; import org.apache.log4j.ConsoleAppender; public class consandpatt {    static Logger logger = Logger.getLogger(consandpatt.class);    public static void main(String args[]) {        // Note, %n is newline       String pattern =  "Milliseconds since program start: %r %n";              pattern += "Classname of caller: %C %n";              pattern += "Date in ISO8601 format: %d{ISO8601} %n";              pattern += "Location of log event: %l %n";              pattern += "Message: %m %n %n";               PatternLayout layout = new PatternLayout(pattern);       ConsoleAppender appender = new ConsoleAppender(layout);        logger.addAppender(appender);       logger.setLevel((Level) Level.DEBUG);        logger.debug("Here is some DEBUG");       logger.info("Here is some INFO");       logger.warn("Here is some WARN");       logger.error("Here is some ERROR");       logger.fatal("Here is some FATAL");    } }         

You can download it: consandpatt.java. And checkout the output produced: output2.txt.

Log4j is usually used in conjunction with external configuration files so that options do not have to be hard-coded within the software. The advantage of using an external configuration file is that changes can be made to the options without having to recompile the software. A disadvantage could be, that due to the io instructions used, it is slightly slower.

There are two ways in which one can specify the external configuration file: a plain text file or an XML file. Since everything is written in XML these days, this tutorial will focus on the XML approach but will also include relevant plain text examples. To begin with, examine the sample XML config file shown below:

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">  <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">            <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">     <layout class="org.apache.log4j.SimpleLayout"/>   </appender>    <root>     <priority value ="debug" />     <appender-ref ref="ConsoleAppender"/>   </root>  </log4j:configuration>      

The file starts with a standard XML declaration followed by a DOCTYPE declaration which indicates the DTD(Document Type Definition), this defines the structure of the XML file, what elements may be nested within other elements etc. This file is provided in the log4j distribution under src/java/org/apache/log4j/xml. Next comes the all-encapsulating log4j:configuration element, which was specified as the root element in the DOCTYPE declaration. Nested within the root element are two structures:

  <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">     <layout class="org.apache.log4j.SimpleLayout"/>   </appender>           

Here an Appender is created and called "ConsoleAppender", note that any name could have been chosen, it is because of the contrivity of examples that this name was chosen. The class for the appender is then specified in full, when referring to classes, one always uses the fully qualified class name. An Appender must always have a name and a class specified. Nested within Appender is the layout element which defines the layout to be a SimpleLayout. Layout must always have the class attribute.

  <root>     <priority value ="debug" />     <appender-ref ref="ConsoleAppender"/>   </root>           

The root element always exists and cannot be sub-classed. The example shows the priority being set to "debug" and the appender setup by including an appender-ref element, of which, more that one may be specified. See the file src/java/org/apache/log4j/xml/log4j.dtd in your log4j distribution for more information about the structure of an XML configuration file. The configuration file is pulled into the Java program like this:

DOMConfigurator.configure("configurationfile.xml");     

The DOMConfigurator is used to initialise the log4j environment using a DOM tree. Here is the example xml configuration file: plainlog4jconfig.xml. Here is a program which implements this configuration file: files/externalxmltest.java:

import org.apache.log4j.Logger; import org.apache.log4j.xml.DOMConfigurator; public class externalxmltest {    static Logger logger = Logger.getLogger(externalxmltest.class);    public static void main(String args[]) {       DOMConfigurator.configure("xmllog4jconfig.xml");       logger.debug("Here is some DEBUG");       logger.info("Here is some INFO");       logger.warn("Here is some WARN");       logger.error("Here is some ERROR");       logger.fatal("Here is some FATAL");    } }     

Here is an XML configuration file for a Logger implementing a FileAppender using a PatternLayout:

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">  <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">            <appender name="appender" class="org.apache.log4j.FileAppender">     <param name="File" value="Indentify-Log.txt"/>     <param name="Append" value="false"/>     <layout class="org.apache.log4j.PatternLayout">       <param name="ConversionPattern" value="%d [%t] %p - %m%n"/>     </layout>   </appender>    <root>     <priority value ="debug"/>     <appender-ref ref="appender"/>   </root>  </log4j:configuration>     

You can download this example from here: xmllog4jconfig2.xml. For more examples of using xml files to configure a log4j environment, see the src/java/org/apache/log4j/xml/examples/ directory in the log4j distribution.

Here is the configuration file discussed above, expressed in the form of a plain text file:

# initialise root logger with level DEBUG and call it BLAH log4j.rootLogger=DEBUG, BLAH # add a ConsoleAppender to the logger BLAH log4j.appender.BLAH=org.apache.log4j.ConsoleAppender # set set that layout to be SimpleLayout log4j.appender.BLAH.layout=org.apache.log4j.SimpleLayout     

You can download it here: plainlog4jconfig.txt. Here is a program implementing this:

import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; public class externalplaintest {    static Logger logger = Logger.getLogger(externalplaintest.class);    public static void main(String args[]) {       PropertyConfigurator.configure("plainlog4jconfig.xml");       logger.debug("Here is some DEBUG");       logger.info("Here is some INFO");       logger.warn("Here is some WARN");       logger.error("Here is some ERROR");       logger.fatal("Here is some FATAL");    } }     

You can download an example program that uses this configuration file here: files/externalplaintest.java. For more examples of using plain text files to configure a log4j environment, see the examples directory in the log4j distribution.

The use of external example files has only been briefly discussed here, it is assumed that you have the capacity to learn more by yourself by studying the examples provided with the log4j distribution and experimenting.


--
ఇట్లు మీ,
చంద్రశేఖర్.

Spring Web application


find this attachment.
--
ఇట్లు మీ,
చంద్రశేఖర్.

JSTL: another for each and status

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%
String[] movies = {"Sholay", "Maine Pyar kiya", "Jai Santoshi Maa", "Kaho Na Pyaar Hai", "Krish", "Rang De Basanti"};
pageContext.setAttribute("movies", movies, pageContext.PAGE_SCOPE);
%>
<html>
<head>
<title>forEach and status</title>
</head>
<body>
The forEach has one scoped variable called 'count', it tells the 
current position of the element within the collection. <br>
<c:forEach var="movieName" items="${pageScope.movies}" varStatus="status">
Movie Number : <c:out value="${status.count}" /> is
<c:out value="${movieName}" /> <br />
</c:forEach>
</body>
</html>


--
ఇట్లు మీ,
చంద్రశేఖర్.

Wednesday, August 27, 2008

Showing Multiple Images in J2ME through servlet call


J2ME code portion
---------------------
public int integerFromByteArray(byte [] byteArray) {
System.out.println("integer conversion from byte array ---------------------------------");
int k = 0;
int tempRes = 0;
int res=0;
for (int i=byteArray.length -1 ; i>=0; i--) {
tempRes = (int) byteArray[i];
int tempForAnding = tempRes;
System.out.println("byteArray = " + (3-i));
int j = 0;
do{
k = (3-i)*8 + j;
int temp = tempForAnding & 1;
if (temp == 1){
//if (k==0)// since 2 to the power 0 = 1
// res = 1;
//else {
res += 1 << k; // 2 to the power 2 = do a plus 4 = left shift 2
System.out.print("1");
//}
} else
System.out.print("0");
j++;
tempForAnding = tempRes >> j;
//System.out.println("after shifting " + j + " times " + tempRes);

}while (j < 8);
System.out.println(" ");
}
return res;
}
// reza 18.2.2008
public void copyBytes(byte [] dest, byte [] src, int stIndex, int len) {
int k = 0;
for (int i = stIndex; i < stIndex + len; i++) {
dest[k] = src[i];
System.out.println("byte["+ k + "] == " + dest[k] );
k++;
}
}
// reza 18.2.2008

public void preparingImage(byte [] result){
int noOfImages = -1;
int byteArrayIndex = 0;
int imageSize = -1;
byte [] temp = null;
byte [] imageArray = new byte[5000];
temp = new byte[4];
copyBytes(temp, result, 0, 4);
byteArrayIndex += 4;
noOfImages = integerFromByteArray(temp);
System.out.println("noOfImages =========================== " + noOfImages);
get_testForm();
if ( noOfImages > 0) {
for(int n = 0; n < noOfImages; n++) {
copyBytes(temp,result,byteArrayIndex,4);
byteArrayIndex += 4;
imageSize = integerFromByteArray(temp);
System.out.println(n + " image size " + " is ================== " + imageSize);
copyBytes(imageArray, result, byteArrayIndex, imageSize);
byteArrayIndex += imageSize;
try{

Image image = Image.createImage(imageArray,0,imageSize);
testform.append(image);
} catch (Exception ex) {
System.out.println(ex);
}
}
}
System.out.println("byteArrayIndex ====== " + byteArrayIndex);

}
// reza 18.2.2008 // this form shows the image the command action code is not given
// the callFileServlet command calls the servlet using http connection in response receives the // the byte array

Form testform;
Command callFileServlet;
public Form get_testForm() {
if (testform == null){
testform = new Form("testing multiple images");
callFileServlet = new Command("ok", Command.OK, 1);
testform.addCommand(callFileServlet);
testform.setCommandListener(this);
}
return testform;
}

J2EE Servlet code:
--------------------
package image;


import java.io.*;
import java.net.*;


import javax.servlet.*;
import javax.servlet.http.*;


public class FileServlet extends HttpServlet {

/** Processes requests for both HTTP GET and POST methods.
* @param request servlet request
* @param response servlet response
*/
byte [] fileBuffer = new byte[5000];
int Buffer_Size=0;

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");

ServletOutputStream sout = response.getOutputStream();

String FileNames [] = {"e:\\yahooonline.png","e:\\yahooonline.png","e:\\yahooonline.png","e:\\yahooonline.png","e:\\yahooonline.png"};

ProcessFiles(sout, 5, FileNames);

//sout.write(fileBuffer);


}

//
/** Handles the HTTP GET method.
* @param request servlet request
* @param response servlet response
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

/** Handles the HTTP POST method.
* @param request servlet request
* @param response servlet response
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

/** Returns a short description of the servlet.
*/
public String getServletInfo() {
return "Short description";
}
//


public byte [] getByteFromFile(String FileName)
{
byte [] b= null;

try
{
File file = new File(FileName);

b = new byte[(int)file.length()];
FileInputStream fis = new FileInputStream(file);
fis.read(b, 0, (int)file.length());
System.out.println("Writing File of Size :: " + file.length());
}
catch (Exception ex) {

ex.printStackTrace();
}

return b;
}

public void ProcessFiles(ServletOutputStream sout,int no_of_file, String [] fileID)
{

int size = 0;
// get byte for file number...
byte [] file_num = Convert_To_Byte(no_of_file);
try {
//Add file number to file buffer...
//appendToBuffer(file_num);
sout.write(file_num);
System.out.println("No of File :: " + no_of_file);
} catch (Exception ex) {
ex.printStackTrace();
}
//After adding no of file buffer size will increase by 4 byte...
Buffer_Size = Buffer_Size + 4;

for(int i=0; i < no_of_file; i++)
{
String fileName = fileID[i];
size = getFileSize(fileName);
System.out.println("File Size : " + size);
//Add file size to buffer
//appendToBuffer(Convert_To_Byte(size));

try {
//Add file number to file buffer...
//appendToBuffer(file_num);
sout.write(Convert_To_Byte(size));
}
catch (Exception ex) {
ex.printStackTrace();
}
//increase buffer size by 4
Buffer_Size = Buffer_Size + 4;
byte b[] = getByteFromFile(fileName);
//Add content of file to buffer....
//appendToBuffer(b);

try {
//Add file number to file buffer...
//appendToBuffer(file_num);
sout.write(b);
} catch (Exception ex) {
ex.printStackTrace();
}

//increase buffer size by file size
Buffer_Size = Buffer_Size + size;

System.out.println("Total Buffer Size So Far :: " + Buffer_Size);
}



try {

sout.close();
} catch (IOException ex) {
ex.printStackTrace();
}

}// End of Function Process File

public int getFileSize(String FileName)
{
return (int)new File(FileName).length();
}

public byte [] Convert_To_Byte(int value)
{
//value = 255;
byte [] bytes = new byte[4];
int totalValue = 0;
for(int k = 3; k >= 0; k--) {
bytes[k] = new Integer(value).byteValue();
System.out.println(k + " :::::: " + bytes[k]);
value = value >> 8;

int reverse = (int)bytes[k];
int convert = 0;
for(int i = 0; i < 8; i++) {
convert += ((reverse >> i) & 1) << i;
}
totalValue += convert << (3 - k) * 8;
System.out.println("Value of byte " + convert);

}

System.out.println("Total Value of byte " + totalValue);
return bytes;
}


public void appendToBuffer(byte [] data )
{
int j=0;
for(int i= Buffer_Size; i < Buffer_Size + data.length; i++)
{
fileBuffer[i] = data[j++];
}
}

}

--
ఇట్లు మీ,
చంద్రశేఖర్.

Using the Calendar class in J2ME for date and time

Parsing and displaying dates and times is often complicated because of formatting and locale issues. Java 2 Platform, Standard Edition (J2SE) provides several classes to simplify date and time handling -- classes such as java.util.Calendar, java.util.Date, java.util.TimeZone, and java.text.DateFormat. By comparison, the Mobile Information Device Profile (MIDP) defines only subsets of the Calendar, Date and TimeZone classes, and does not include any form of DateFormat. How, then, can your MIDP applications properly handle dates and times?

The answer lies in the javax.microedition.lcdui.DateField class, part of the MIDP high-level user interface API. DateField is an interactive user interface component that displays a date, time, or both. It also allows you to edit the date and time. DateField extends the Item class. This means that DateField components can be placed on Form objects. So the first step in using a DateField is to create a Form and place the DateField on the form:

    Form f = new Form( "A Form" );
f.append( df );

As with any Item, the DateField is displayed only when the form is made active by calling Display.setCurrent.

The DateField class defines two constructors:

    public DateField( String label, int mode );
public DateField( String label, int mode,
java.util.TimeZone zone );

To properly display dates and times, a DateField instance needs to know which time zone to use. The two-argument constructor uses the device's default time zone. The three-argument constructor lets you specify an explicit time zone if the default is inappropriate. Note that you can't change the displayed time zone without creating a new instance of DateField.

The first two arguments are identical in both constructors. The first argument is the label to display alongside the field -- use null if there is no label. The second argument is the input mode of the field. There are three possible modes, these are declared as constants in the DateField class:

    public static final int DATE = 1;
public static final int TIME = 2;
public static final int DATE_TIME = 3;

The input mode controls what the field displays: a date only, a time only, or a combined date and a time. You can change the input mode at any time by calling the setInputMode method.

When you create a new DateField instance, you do not have to set a date or time. The following code, for example, displays an uninitialized date:

    Display display = ....; // initialized elsewhere
Form f = new Form( "An Empty Date" );
DateField df = new DateField( "Date:",
DateField.DATE );
f.append( df );
display.setCurrent( f );

To initialize the field to a particular date or time, call setDate and pass in a java.util.Date object initialized to the correct value:

    Calendar c = Calendar.getInstance();
c.set( Calendar.MONTH, Calendar.OCTOBER );
c.set( Calendar.DAY_OF_MONTH, 18 );
c.set( Calendar.YEAR, 1996 );
c.set( Calendar.HOUR_OF_DAY, 16 );
c.set( Calendar.MINUTE, 39 );
c.set( Calendar.SECOND, 45 );
c.set( Calendar.MILLISECOND, 0 );

Date moment = c.getTime();
DateField df = new DateField( null,
DateField.DATE_TIME );
df.setTime( moment );

A Date object represents a moment in time (in coordinated universal time, or UTC, to be exact) as the number of milliseconds since midnight, January 1, 1970. Use a Calendar instance to create a Date instance, as shown above.

Note that a DateField in TIME input mode requires the date portion to be set to January 1, 1970. Two useful routines for clearing out the date portion of a Date and for combining two Date objects into a single object are as follows:

    // Return a Date with the time intact but the date
// set to January 1, 1970

public static Date clearDate( Date d ){
Calendar c = Calendar.getInstance();
c.setTime( d );
c.set( Calendar.MONTH, Calendar.JANUARY );
c.set( Calendar.DAY_OF_MONTH, 1 );
c.set( Calendar.YEAR, 1970 );
return c.getTime();
}

// Combine a date and time into a single
// Date instance

public static Date combineDateTime(
Date date, Date time ){
Calendar cd = Calendar.getInstance();
Calendar ct = Calendar.getInstance();

cd.setTime( date );
ct.setTime( time );

ct.set( Calendar.MONTH,
cd.get( Calendar.MONTH ) );
ct.set( Calendar.DAY_OF_MONTH,
cd.get( Calendar.DAY_OF_MONTH ) );
ct.set( Calendar.YEAR,
cd.get( Calendar.YEAR ) );

return ct.getTime();
}

Always do your date manipulation using the Calendar class, not using the raw milliseconds value stored in a Date object.

After a DateField is displayed, the system will allow the user to select the object and edit the date, time or both, depending on the input mode. Whenever you need to obtain the new date/time, call the getDate method:

DateField df = ....; Date editedDate = df.getDate();

Here is a simple MIDlet that lets you view and edit dates and times using all three input modes.

import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

/**
* Demonstration of time/date editing using the MIDP
* DateField class.
*/

public class DateFieldTest extends MIDlet {

private Display display;

// Define our Command objects

private Command exitCommand =
new Command( "Exit", Command.EXIT, 1 );
private Command okCommand =
new Command( "OK", Command.OK, 1 );
private Command cancelCommand =
new Command(
"Cancel", Command.CANCEL, 1 );

public DateFieldTest(){
}

protected void destroyApp( boolean unconditional )
throws MIDletStateChangeException {
exitMIDlet();
}

protected void pauseApp(){
}

protected void startApp()
throws MIDletStateChangeException {
if( display == null ){ // first time called...
initMIDlet();
}
}

private void initMIDlet(){
display = Display.getDisplay( this );
testList = new TestList();
display.setCurrent( testList );
}

public void exitMIDlet(){
notifyDestroyed();
}

// Return a Date with the time intact but the date
// set to January 1, 1970

public static Date clearDate( Date d ){
Calendar c = Calendar.getInstance();
c.setTime( d );
c.set( Calendar.MONTH, Calendar.JANUARY );
c.set( Calendar.DAY_OF_MONTH, 1 );
c.set( Calendar.YEAR, 1970 );
return c.getTime();
}

// Combine a date and time into a single
// Date instance

public static Date combineDateTime( Date date,
Date time ){
Calendar cd = Calendar.getInstance();
Calendar ct = Calendar.getInstance();

cd.setTime( date );
ct.setTime( time );

ct.set( Calendar.MONTH,
cd.get( Calendar.MONTH ) );
ct.set( Calendar.DAY_OF_MONTH,
cd.get( Calendar.DAY_OF_MONTH ) );
ct.set( Calendar.YEAR,
cd.get( Calendar.YEAR ) );

return ct.getTime();
}

// The list of tests we can perform, arranged
// in threes so that ( index % 3 ) == one
// of DATE, TIME or DATE_TIME

static final String[] testLabels = {
"Current date",
"Current time",
"Current date/time",
"Edit date",
"Edit time",
"Edit date/time",
};

private TestList testList;
private Date editDate;

//
// Displays the list of actions
//

class TestList extends List
implements CommandListener {
public TestList(){
super( "DateField Tests", IMPLICIT,
testLabels, null );
addCommand( exitCommand );
setCommandListener( this );
}

public void commandAction( Command c,
Displayable d ){
if( c == exitCommand ){
exitMIDlet();
} else if( c == List.SELECT_COMMAND ){

// Figure out which date to display
// and what the input mode is

int which = getSelectedIndex();
String label = getString( which );
int mode = ( which % 3 ) + 1;
boolean save = ( which > 2 );

display.setCurrent(
new Edit( save, label, mode ) );
}
}
}

//
// Edit a date, time or date/time, optionally
// saving the value.
//

class Edit extends Form
implements CommandListener {

public Edit( boolean save, String label,
int mode ){

super( label );
this.save = save;

Date d = editDate;

if( !save ){
d = new Date();
}

dateField = new DateField( null, mode );
append( dateField );

if( d != null ){
if( mode == DateField.TIME ){
d = clearDate( d );
}

dateField.setDate( d );
}

addCommand( okCommand );

if( save ){
addCommand( cancelCommand );
}

setCommandListener( this );
}

public void commandAction( Command c,
Displayable d ){
Alert alert = null;
Date date = dateField.getDate();

if(
save && date != null && c == okCommand ){
if( editDate != null ){
int mode = dateField.getInputMode();
if( mode == DateField.DATE ){
editDate = combineDateTime(
date, editDate );
} else if(
mode == DateField.TIME ){
editDate = combineDateTime(
editDate, date );
} else {
editDate = date;
}
} else {
editDate = date;
}

Calendar cal = Calendar.getInstance();
cal.setTime( editDate );

alert = new Alert( "New date/time" );
alert.setString(
"The saved date/time is now " + cal );
alert.setTimeout( Alert.FOREVER );
}

if( alert != null ){
display.setCurrent( alert, testList );
} else {
display.setCurrent( testList );
}
}

private DateField dateField;
private boolean save;
}
}

--
ఇట్లు మీ,
చంద్రశేఖర్.

Dieting and Losing weight at least 5-6kgs in 7 days

Dieting and Losing weight at least 5-6kgs in 7 days

The menu

The most important element of the program is the 10 tall glasses of water a day. You can also flavor the water with some lemon to make the drink easier. While on the program take only black coffee and never more than one teaspoon of oil. Preferably do not use oil because of high calorific content. No fruit juices before day seven.The effectiveness of this seven day plan is that the foods eaten burn more calories than they give to the body in caloric value.

First day:
All fruits except bananas. Your first day consist of all fruits you want. It is suggested you consume lots of melons the first day especially watermelon and cantaloupe.

Second day:
All vegetables. You are encouraged to eat until you are stuffed with all the raw and cooked vegetables of your choice. There is no limit on the amount or type. Avoid oil and coconut while cooking vegetables. Have large boiled potato for breakfast.

Third day:
Any mixture of fruits and vegetables of your choice. Any amount, any quantity, no bananas yet and no potatoes today.

Fourth day:
Banana and Milk. Today you will eat as many as eight bananas and drink three glasses of milk. You can also have 1 bowl of Vegetable soup.

Fifth day:
Today is feast day. You will eat 1 cup of rice. You also have to eat six whole tomatoes and drink 12 glasses of water today to cleanse your system of the excess uric acid you will be producing.

Sixth day:
Today is another all vegetables day. You must eat 1 cup of rice today and eat all the vegetables you want, cooked or uncooked, in your hearts content.

Seventh day:
Today your food intake will consist of 1 cup of rice, fruit juice and the vegetables you care to consume. Tomorrow morning you will be five to eight Kgs. Lighter than 1 week ago. If you desire further weight loss repeat the program again. Repeat the program as often as you like. However, it is suggested that you rest for three days before every repetition.


How it affects the body

Day One:
You are preparing your system for the upcoming program. Your only source of nutrition is fresh fruits. Fruits are nature's perfect food. They provide everything you can possibly want to sustain life except total balance and variety.

Day Two:
Starts with a fix of complex carbohydrates in the form of a boiled potato. This is taken in the form of a boiled potato and taken in the morning to provide energy and balance. The rest of the day too consists of vegetables, which are virtually calorie free and provide essential nutrients and fiber.

Day Three:
Eliminates the potato because you get your carbohydrates from fruits. Your system is now prepared to start burning excess pounds. You will have cravings, which should start to diminish by day four.

Day Four:
Bananas and milk. You are in for a surprise. You probably will not be able to eat all the bananas allowed. But they are there for the potassium you have lost and sodium you may have missed the last three days. You will notice a definite loss of desire for sweets and you will be surprised at how easy this day will go.

Day Five:
Rice and tomatoes. The rice is for the carbohydrates and the tomatoes are for the digestion and fiber. Lots and lots of water purify you system. You should notice colorless urine today. Do not feel you have to eat one-cup rice, you may eat less. But you may eat six tomatoes.

Day Six:
It is similar to five. Vitamins and fiber from the vegetables and carbohydrates from the rice. By now your system is in a total weight loss inclination. There should be a noticeable difference in the way you look today compared to day one.

Day Seven:
You may celebrate with champagne. You may also have white wine instead of champagne, but in all practical programs, and in all surveys done to measure the success of the program, General Motors employees have always preferred champagne to white wine.


Concluding Remark

You have your system under control now and it will thank you for all the purging and cleansing you just gave it. Even more than a diet program it is good to follow this diet once in a while to clean your digestive system and remove toxic substances that have accumulated in the system.This program was developed in conjunction with the grant from the US Department of Agriculture and the Food and Drug Administration. It was field tested at the Johns Hopkins Research Centre and was approved for distribution by the Board of Directors of General Motors Corporation at a general meeting on August 15, 1995.

--
ఇట్లు మీ,
చంద్రశేఖర్.

Friday, August 8, 2008

Mave Doc

Introduction

Maven is a high-level, intelligent project management, build and
deployment tool from the Apache project. There is nothing that Maven does
that Ant cannot do. Ant gives the ultimate power and flexibility in build
and deployment to the developer. Why do you need Maven then? Maven adds a
layer of abstraction above Ant (and uses Jelly). Maven can be used to
build any Java application, but in this article we will investigate the
applicability of Maven from a J2EE standpoint. J2EE build and deployment
as we know it today is pretty much standardized. Every enterprise has some
variations, but in general it is all the same: deploying EARs, WARs, and
EJB-JARs. Maven captures this intelligence and lets you achieve the build
and deployment in about 5-6 lines of Maven script compared to dozens of
lines in an Ant build script. In other words, Maven simplifies a
developer's life. Everybody loves things to be simple right?

If you think of Ant as a modular language like C, then Maven can be
compared to an object oriented language like C++ or Java. Maven plugins
are like the standard JDK libraries. The C language, albeit a giant leap
from assembly languages, falls short of addressing the complexities of
enterprise projects. Java on the other hand, being object oriented, forces
the developer to program in a certain way and reduces complexities in
large enterprise projects by letting you manage dependencies by breaking
them into chunks via CRC - Class, Responsibility and Collaboration - which
is a big paradigm shift from C. There are some tasks that C alone can do,
but for the majority of enterprise programming Java will suffice.

Every comparison between C and Java listed above applies to Ant and Maven.
Ant lets you do any variations you want, but requires a lot of scripting.
Maven on the other hand mandates certain directories and file names, but
it provides plugins to make life easier. The restriction imposed by Maven
is that only one artifact is generated per project (A project in Maven
terminology is a folder with a project.xml file in it). If you are
thinking "My EAR artifact itself consists of multiple artifacts, I am out
of luck, I cannot use Maven", it is time to take a closer look. A Maven
project can have sub projects. Each sub project can build its own
artifact. The topmost project can aggregate the artifacts into a larger
one. This is synonymous to jars and WARs put together to form an EAR.
Maven also provides inheritance in projects. I will address these topics
in the following sections. At the end of this article you will be able to
build J2EE project artifacts using Maven.
Maven simplifies build enormously by imposing certain fixed file names and
acceptable restrictions like one artifact per project.

First there was make. But make was not cross platform. Then came Ant. Ant
lets you do cross-platform builds in a systematic manner. It is very
elegant compared to make. However as you may have already realized, build
tasks in a project are pretty standard. The tricky part is partitioning,
compiling and packaging classes, resources and descriptors into the right
deployment artifacts like jars, WARs and EARs and managing dependencies on
the right version of libraries - both internal and third party ones. After
a while you will find yourself copying Ant script snippets from one place
to another and modifying them. Then there is the universal problem of
classpath. We all have different versions of different libraries installed
in different locations on the development workstations. Nobody can be sure
if the Ant build copied the right version of the library into the
deployment artifact at all. We all have seen the classic developer shrug -
"It works on my machine"! Ant does little to address this problem. Enter
Maven.

What is it that makes Maven an attractive option for today's enterprises?
The basic tenet of Ant build scripts is copying, renaming and deleting
files under various conditions into various deployable artifacts - which
are again treated as files on your computer by the build script. Maven
hides the fact that everything is a file and forces you to think and
script to create a deployable artifact such as an EAR, that has a
dependency on a particular version of a third party library residing in a
shared remote (or local) enterprise repository, and then publish your
library into the repository as well for others to use. No more classpath
issues. No more mismatch in libraries. This sounds like a very real and
practical solution to our everyday problems. It also gives you the power
to embed Ant scripts within Maven scripts if absolutely essential.

In the words of Jason van Zyl, an important contributor to the Maven
source code base, "the intent of Maven is to make intra-project
development highly manageable in the hopes of providing more time for
cross-project development. You might call it cross-project pollination or
the sharing of project development knowledge; this is what Maven attempts
to encourage".

Maven installation

You can download the 1.0 Release Candidate from
http://maven.apache.org/builds/release/1.0-rc1/.

The version of Maven available at the time of this writing was 1.0-beta
10. Everything in this article refers to the 1.0-beta 10. It is feature
complete for 1.0 pending any defects. Unzip the archive onto your
machine. It creates a directory called maven-1.0-beta-10. Before you go
any further, set the MAVEN_HOME environment variable to this directory.
Also add the MAVEN_HOME/bin to the PATH environment variable. Make sure
you have set the JAVA_HOME appropriately. Go to the command line and type
maven -g. If you see a long list of output, your installation has
succeeded.

Maven basics

The basic concept of Maven is a project. In Maven terms, any directory
that has a project.xml in it is a project. When the sub-directories
underneath have their own project.xml, they are projects on their own too.
Another concept in Maven is that of a repository. The repository holds the
artifacts on which your project depends. There are two kinds of
repository: local and remote. Both of them can be declaratively set.
Unless specified otherwise, the local repository is created in a special
directory called ".maven/repository". In Windows, this directory is
created in C:\Documents And Settings. For example, if your project depends
on commons-logging version 1.0.2, you can specify the dependency in
project.xml and when maven is executed, it will copy the appropriate
commons-logging jar file from the remote repository to the local
repository and then use it to build your project's artifact. The maven
repository folder has subfolders for each library. For instance, there is
a sub folder for commons-logging. Beneath the commons-logging folder there
is another subfolder called jars. This jars folder has the commons logging
jar files suffixed by version number. Jars are not the only type of
artifacts supported in the repository. You can have EARs and WARs too.

The role of the repository is immediately obvious. Instead of each project
having its own copies of third party libraries, the repository helps
developers across projects to share the libraries. Each project can also
in turn generate its artifacts and publish it into the remote repository.
The process of publishing a jar into the repository is called "install" in
Maven lingo. This install process helps organizations to share internal
artifacts across projects in a standard manner. This also holds the basis
for continuous integration among inter-dependent projects. Continuous
Integration is a concept that was developed by Martin Fowler and
developers of Cruise Control. Individual projects can continue to build
and publish the release and snapshot artifacts to corporate repositories.
Daemon processes running on dedicated machines can schedule integration
builds, deploy to execution platforms (application servers) and run
automated tests to verify the build status. Figure 1 shows the role of
project.xml, repository, goals and plugins in Maven build. The grey
colored rectangles are provided by you. The green colored rectangles are
provided by Maven. The pink colored rectangle shaded is the output - the
deployment artifacts from your project. Custom plugins and maven.xml are
optional. The rest of the inputs are mandatory.

Figure 1 Overview of Maven build elements

project.xml details

The project.xml is divided into four main parts namely, Project Management
Section, Project Dependency Section, Project Build Section and Project
Reports Section. Listing 1 shows the outline of a typical project.xml. The
mandatory items are shown in bold.

Listing 1 Outline of project.xml

01 <?xml version="1.0"?>
02 <project>
03 <pomVersion>3</pomVersion>
04 <groupId>Sample-Maven-Project</groupId>
05 <id>sample-project</id>
06 <currentVersion>1.1</currentVersion>
07 <name>Sample Maven Project</name>
08
09 <!-- Project Management section goes here -->
10
11 <!-- Project Dependency section goes here -->
12
13 <!-- Project Build section goes here -->
14
15 <!-- Project Reports section goes here -->
16
17 </project>

* Line 02 - Root element defining the project.
* Line 03 - Project Object Model (POM) Version. This tag is unused but
needed.
* Line 04 - A directory with this name is created in Maven repository
to hold the artifacts of projects sharing the group id.
* Line 05, 06 - The id and version is used to create the artifact name
as <id>-<version>.jar
* Line 07 - Name of the Project

The Project Management Section is shown in detail in Listing 2 and has
general information on the organization, its web site, project web site,
location of SCM, deployment and issue tracking site, developer list,
mailing lists to name a few. Most of the items in this section is
boilerplate and are optional. Maven allows inheritance in the project.xml.
Every organization can have an enterprise wide template which can be
extended for projects. Each subproject will simply fill in the relevant
section of this file. Most of the project management section elements get
defined in the enterprise wide template and top-level project template.
The only mandatory element is the organization name.

Listing 2 Project Management Section in project.xml

01 <organization>
02 <name>Foobar Travels</name>
03 <url>http://www.foobar.com</url>
04 <logo>http://www.foobar.com/logo.jpg</logo>
05 </organization>
06
07 <inceptionYear>2003</inceptionYear>
08 <package>foobar.blah.*</package>
09 <logo>http://www.foobar.com/project-logo.jpg</logo> |
10 <description>Project description goes here</description>
11 <shortDescription>Short Description</shortDescription>
12 <url>http://www.foobar.com</url>
13 <issueTrackingUrl>http://jira.foobar.com</issueTrackingUrl>
14 <siteAddress>http://staging.foobar.com</siteAddress>
15 <siteDirectory>/etc/staging</siteDirectory>
16 <distributionDirectory>/etc/builds</distributionDirectory>
17
18 <repository>
19 <connection>cvs:pserver:anon@foobar.com:/foo</connection>
20 <url>http://scm.foobar.com</url>
21 </repository>
22
23 <mailingLists>
24 <mailingList>
25 <name>Dev List</name>
26 <subscribe>subscribe-dev@foobar.com</subscribe>
27 <unsubscribe>unsubscribe-dev@foobar.com</unsubscribe>
28 </mailingList>
29 ...
30 ...
31 </mailingLists>
32
33 <developers>
34 <developer>
35 <name>Srikanth Shenoy</name>
36 <id>shenoy</id>
37 <email>srikanth@srikanth.org</email>
38 </developer>
39 ...
40 ...
41 </developers>

* Lines 01-05 - Organization details
* Line 08 - Top level package for the project
* Line 09 - Project Logo
* Line 12 - Project web site
* Line 14 - The site where the project is hosted
* Line 15 - Physical location of project deployment
* Line 16 - Physical location where the project distributions are
available
* Lines 18-21 - SCM to access the project source
* Lines 23-31 - Mailing list for the project
* Lines 33-41 - Developers in the project


Figure 2 Sample Maven Project Organization


The Project Build Section describes the location of source, test and
resource files. This section is generally defined at the organization
level to standardize templates for all projects in the organization, or at
the main project level to standardize the templates for all underlying sub
projects respectively. Listing 3 shows the project build section. All the
information about project organization shown in Figure 2 is defined here.
The project organization can be changed and so can the project.xml. All
the elements in this section are optional. However, note that if this
section is not specified, no build ever gets done. Once the build is
complete, Maven automatically runs the tests specified in the unit test
section.

Listing 3 Project Build Section in project.xml

01 <build>
02 <nagEmailAddress>srikanth@srikanth.org</nagEmailAddress>
03 <sourceDirectory>${basedir}/src/java</sourceDirectory>
04 <unitTestSourceDirectory>${basedir}/test/java</unitTestSourceDirectory>
05 <unitTest>
06 <includes>
07 <include>**/*Test.java</include>
08 </includes>
09 </unitTest>
10
11 <resources>
12 <resource>
13 <directory>${basedir}/src/conf</directory>
14 <includes>
15 <include>*.properties</include>
16 </includes>
17 </resource>
18 </resources>
19 </build>

* Line 02 - Email address to send notification about the build status
* Line 03 - Folder containing the source files for the project. The
source can be java, jsp and so on.
* Line 04 - Directory containing the unit test files for the project.
* Lines 05-09 - The test file name pattern to run after the build is
completed
* Lines 11-19 - Resources to be copied in case a jar is created.

Once the build is done, different kinds of reports and documentation can
be generated to report the status of the build/release. The target
audience of the reports can vary from other developers in the same project
to sponsors, stakeholders or users from other projects. For instance, the
javadoc and java cross reference (jsr) reports target the programmers,
jdepend reports are of interest to the architect. File and developer
activity reports might be of interest to the Configuration Manager. The
reports are meant to effectively communicate and collaborate with the team
and the stakeholders about the project's status. Listing 4 shows the
Project Reports Section in the project.xml. Do not worry about the
specifics of each of the entries. You can pick them up as you use Maven.

Listing 4 Project Reports Section in project.xml

<reports>
<report>maven-changes-plugin</report>
<report>maven-jdepend-plugin</report>
<report>maven-checkstyle-plugin</report>
<report>maven-pmd-plugin</report>
<report>maven-junit-report-plugin</report>
<report>maven-clover-plugin</report>
<report>maven-changelog-plugin</report>
<report>maven-file-activity-plugin</report>
<report>maven-developer-activity-plugin</report>
<report>maven-file-activity-plugin</report>
<report>maven-license-plugin</report>
<report>maven-linkcheck-plugin</report>
<report>maven-jxr-plugin</report>
</reports>

The final section covers the Project Dependency and is the key to every
project. Consider Listing 5 that shows the dependencies for the Sample
Maven Project. The first dependency states that this project depends on a
jar file in a folder named BeanUtils. The name of the jar file is
commons-beanutils-1.5.jar [according to the id-version.jar convention
described earlier]. The folder BeanUtils exists in the .maven/repository
folder.

Listing 5 Project dependency Section in project.xml

<dependencies>
<dependency>
<groupId>BeanUtils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.0.3</version>
</dependency>
<dependency>
<groupId>castor</groupId>
<artifactId>castor</artifactId>
<version>0.9.4.3</version>
</dependency>
</dependencies>


Maven Hands-On

Now that we have sufficient understanding of the project.xml file let us
get on try something out. At the time of this writing Maven 1.0 beta 10 -
a feature complete version for the 1.0 release is generally available,
which we will use in the course of this article. After downloading Maven
from maven.apache.org, unzip the archive into your local directory. Set
the JAVA_HOME variable to point to the JDK installation and MAVEN_HOME to
point to the Maven directory. Also add the MAVEN_HOME/bin to the PATH
environment variable. With these settings, you are ready to use Maven.

Create a directory structure as shown in Figure 2. Then create a simple
MyApp.java class without any dependencies outside JDK libraries. Create a
project.xml with the information supplied in Listing 1 through 5. Since
your sample project does not depend on external entities, the only
exceptions is that you will have an empty dependencies section like this:
<dependencies/>. Go to the command line and cd to the Sample-Maven-Project
directory and type in

C:\Sample-Maven-Project> maven java:compile

You will see that all the java files in src and test directory are
compiled. A maven temp directory called target is created directly under
C:\Sample-Maven-Project, which contains all the compiled class files. As I
have stated earlier Maven's power lies in its plugins. You might not know
it, but you have just used one of its plugins. When you typed maven
java:compile you signaled Maven to use the "java" plugin and attain the
"compile" goal. Maven uses the project.xml and the repository to execute a
"goal" on the project. The generic format of the maven command is

maven <plugin name>:<goal name>

A plugin is a logical collection of goals written using Jelly - an XML
based scripting language. The conditional constructs from Jelly control
the execution of ready-made ant scripts for the pre defined tasks. Each
such task is called a Goal. Although I do not cover Jelly in this article
a sample Jelly snippet will make things clear as to how it wraps an Ant
script. This snippet is from the Maven java plugin. The plugin internally
invokes the <ant:javac> to compile the java code.

<j:when test="${sourcesPresent == 'true'}">
<ant:javac destdir="${maven.build.dest}"
excludes="**/package.html"
debug="${maven.compile.debug}"
deprecation="${maven.compile.deprecation}"
target="${maven.compile.target}"
optimize="${maven.compile.optimize}">
<ant:src>
<ant:path refid="maven.compile.src.set"/>
</ant:src>
</j:when>

A plugin may have a default goal. In such a case you just have to type in
maven <plugin name>. In this case the compile goal in java plugin has the
knowledge to go to the src and test folders specified in the project.xml
and recursively compile all the java files. Similarly a jar plugin has a
default goal of "jar" - i.e. to jar the class files after compiling. The
jar plugin invokes java:compile or something to that effect to compile the
java classes first and then creates the jar file from the classes and
automatically generates the manifest. A plugin thus captures the common
practices into a reusable "library" saving you from reinventing the wheel
and cutting and pasting ant scripts. Now let us go ahead and execute the
jar:install goal. Type the following on the command line

C:\Sample-Maven-Proejct>maven jar:install

When the jar:install goal is attained, a jar file with name
sample-project-1.1.jar is created and is copied into the C:/Documents And
Settings/<login-id>/.maven/repository/Sample-Maven-Project/jars folder.
This is how you publish artifacts as mentioned earlier in this section and
is the basis for continuous integration.
You can see all the goals of Maven by typing the command maven -g at the
command line.

Using Maven in J2EE Projects

In the previous section you saw how to use Maven to set up a project
template, compile source files, create a jar and publish the artifact into
the repository. There is much more to Maven than that. We will cover
inheritance in Maven POM, setting up a Sample J2EE project, creating WARs,
EJB-JARs, dependency jars and ultimately creating EARs. However let's
first look at another important concept in Maven.

In Maven, a project can produce only one artifact. The top-level project
can have multiple sub projects and they in turn can have siblings too. But
at the end, each of them can only produce one artifact. This makes a lot
of sense if you consider how the Ant scripts are used to create multiple
artifacts from a project - which gets confusing over time - to say the
least. Typically, projects have a monolithic (or maybe a couple) source
tree(s), from which all the dependency jars, WARs and EARs are created
using different build scripts. At the end, the message of application
partitioning is lost and classes are created in different packages without
consideration to the classloader mechanism, making it even harder to keep
build scripts up to date. Maven discourages this practice at the outset.
Of course Maven gives you flexibility to override this practice. There are
ways to produce multiple artifacts but that goes against the very spirit
of Maven and has to be avoided unless absolutely essential.

Customizing Maven with maven.xml

Until now you saw how to compile java classes in a maven project and
create jar files out of it. What if you wanted to customize Maven
behavior? You can create a file called maven.xml in the same folder where
project.xml resides. In this file, you can customize goals, define and pre
and post goals.

Listing 6 shows a sample maven.xml. We are achieving quite a bit in this
file. Look at the default goal for the project. The default goal is set to
foobar-dist. A goal is equivalent of an Ant target. The default goal is
the same as the default target in Ant. What this means is that the default
goal is executed when you go to the directory containing this file and
simply type maven. The foobar-dist goal is simply a wrapper on top of
another goal called war:install. The "install" goal in the war plugin
creates a war and publishes it into the repository. The "attainGoal"
instructs maven to achieve the goal described by the name attribute.

The preGoal element instructs Maven to execute the defined tasks in the
preGoal before achieving the goal specified in its name attribute. This
can get confusing at times. Note that the preGoal name (java:compile) is
different from the default goal (foobar-dist). The default goal for this
project installs a war file. However the war plugin has to compile the
java files in the project before creating the actual WAR archive. The
preGoal specified is linked to this java:compile goal rather than the
foobar-dist goal. In this case, the pre goal executes a Xdoclet maven plug
in. We will use Xdoclet Maven plugin later in this article to generate
tlds (tag library definitions) from the actual tag classes.

A postGoal can be specified for any of the implicit goals achieved as part
of the default goal or for the default goal itself. In Listing 6, a
postGoal is specified for the war:war goal, which gets executed just
before war:install goal. The postGoal specifies that a certain directory
have to be created after the WAR is built. Notice the use of standard ant
tasks within the postGoal. In fact any of the ant tasks can be embedded
within the goal, preGoal or postGoal. This is what makes Maven flexible.
It is also very easy to abuse this flexibility by compiling and creating
multiple artifacts using Ant tasks within Maven. In other words, you would
have written Ant scripts under the hoods of Maven. That practice is
discouraged and should be used if there is no other option. If you find
yourself repeating the steps of putting ant tasks into Maven goals, what
you need is a custom plugin.

Listing 6 Sample maven.xml

<project default="foobar-dist" xmlns:m="jelly:maven">

<preGoal name="java:compile">
<attainGoal name="xdoclet:webdoclet"/>
</preGoal>

<goal name="foobar-dist">
<attainGoal name="war:install" />
</goal>

<postGoal name="war:war">
<mkdir dir="${test.result.dir}"/>
<echo>Creating directories</echo>
</postGoal>

</project>

A custom plugin is written in a file called plugin.jelly using the Jelly
scripting language and bundled along with project.xml and other files into
a jar and copied into the C:/Documents And
Settings/<login-id>/.maven/plugins directory. This plugin is then
available to all of your processes using Maven. We will customize the war
plugin later in this article since it lacks some of the features we need.

Figure 3 Inter-Project relationships for Foobar Travels


Let us now jump to applying Maven to J2EE projects. The most common J2EE
artifact generated and deployed is the EAR. The EAR itself consists of
dependency jars, ejb jars, wars and third party libraries. In other words,
EAR is an aggregate artifact. For Foobar Travels, we will use the same
project template as shown in Figure 2. Figure 3 shows the inter-project
relationship and hierarchy. The master project template is defined at the
top project level. A simplified master template is shown in Listing 7 only
with the essential elements. A real one will have most of the items
described in the section Maven basics. The key thing to note is that the
dependencies are not declared in this template. This is because the master
project.xml is just that - a template for other sub projects to extend.
The only thing we have not touched upon from Listing 7 is the
${pom.artifactId}. I will explain this shortly in the context of extending
the template. Figure 4 shows the structure of the EAR file generated by
this project. You will find that the EAR content organization closely
resembles the Maven project shown in Figure 3. In most of the J2EE project
you would not deviate from a deployment artifact as in Figure 4. And when
you stick to the usual route, Maven "out-of-the-box" build scripts work as
is.

Figure 4 The EAR structure for Foobar Travels


Listing 7 Master Project Definition Template

<project>
<pomVersion>3</pomVersion>
<id>foobar-online</id>
<groupId>Foobar-Travels</groupId>
<currentVersion>2.0</currentVersion>
<name>Foobar Online Project</name>
<organization>
<name>Foobar Travels</name>
</organization>
<package>foobar.*</package>
<distributionDirectory>
/foobar/dist/${pom.artifactId}/
</distributionDirectory>
<dependencies/>
<build>
<sourceDirectory>${basedir}/src/java</sourceDirectory>
<resources/>
</build>
</project>

To summarize Figure 4, we have to build the following artifacts from the
project shown in Figure 3.

1. foobar-services-2.0.jar - The dependency jar
2. reservationejb-2.0.jar - The Reservation EJB and create its Manifest
file with Manifest Class-path pointing to the services jar file.
3. personejb-2.0.jar - The Person EJB and create its Manifest file with
Manifest Class-path pointing to the services jar file.
4. foobar-web-2.0.jar - The Web application for Foobar Travels and
create its Manifest file with Manifest Class-path pointing to the
personejb, reservationejb and service jars
5. application.xml - the J2EE application deployment descriptor.
6. Build the EAR by including all of the above artifacts and also
including the castor jar file since the services jar depends on it at
runtime.

Building the dependency jars

Listing 8 shows the project definition for Services - a subproject in
Maven. This subproject creates the foobar-services-2.0.jar file - a
dependency library used by both ejbs and the web tier. Note that the
definition extends from the master template in Listing 7. By extending
from the parent, it inherits all the properties. It defines the dependency
elements to indicate the dependencies on the J2EE APIs (not defined in the
parent) and overrides the id, name and description defined in the parent.

Listing 8 Services Sub-Project Definition

<project>
<extend>${basedir}/../project.xml</extend>
<id>foobar-services</id>
<name>Foobar Services Framework</name>
<package>foobar.service.*</package>
<description>Services JAR project.</description>
<dependencies>
<dependency>
<groupId>j2ee</groupId>
<artifactId>j2ee</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
</project>

Now let us get back to the ${pom.artifactId} mentioned earlier (Listing
7). This lets you introduce polymorphism into Maven. At runtime, the value
of ${pom.artifactId} for the Services sub-project is its id -
foobar-services. Hence the value of the distribution directory for the
Services project is /foobar/dist/foobar-services. In other words the pom
can capture the variables and abstract them in a standard manner and
establish a procedural approach instead of the chaotic one.

Now let us introduce you to the maven.xml for the Services Project.
Technically speaking, maven.xml is not needed since you can always go to
this sub project and execute maven jar:install. However as we will see
later, having a maven.xml will help us eliminate manual execution of Maven
from every sub-project. The maven.xml for the Services project looks as
follows.

<project default="foobar-dist" xmlns:m="jelly:maven">
<goal name="foobar-dist">
<attainGoal name="jar:install" />
</goal>
</project>


Building the EJB jars

After having built the dependency jars let us turn our focus to building
the ejb jars. This is no different, since there is already a ejb plugin
and you can use the ejb:install goal to create and publish the ejb jars.
However we would also like to remind you that the ejb jar (loaded by the
EJB class loader) depends on the Services built in the previous step (See
Figure 4). What this means for you is that the ejb manifest classpath
should point to the foobar-services-2.0 jar. Listing 9 shows the
project.xml for the Reservation EJB jar. Other ejb project definitions are
similar.
NOTE: In the downloadable example supplied with this article, no EJBs are
included. The reason is to have even non-ejb developers using Tomcat to
see Maven in action. However this section describes what it takes to build
EJBs with Maven.

As usual the ejb project depends on the J2EE jars. However since it also
depends on the foobar-services-2.0.jar (loaded by the EAR class loader),
it has to add that jar file name to its manifest classpath. You can
achieve this by setting the property ejb.manifest.classpath to be true.
The Maven variable, pom.currentVersion stands for the current version of
the project. In our case, it is 2.0. This setting indicates that the
version of services project on which the ejb project depends is the same
as the current version of the ejb project. This version is set on the
parent project template. For future releases, the version number need not
be changed for every dependency in every project. Just change it in the
Master project template and it takes effect everywhere. Ah, the beauty of
inheritance!

Listing 9 Reservation EJB Project Definition

<project>
<extend>${basedir}/../project.xml</extend>
<id>reservationejb</id>
<name>Foobar Reservation Components</name>
<package>foobar.reservation.*</package>
<description>Reservation Components project</description>
<dependencies>
<dependency>
<groupId>j2ee</groupId>
<artifactId>j2ee</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>Foobar-Travels</groupId>
<artifactId>foobar-services</artifactId>
<version>${pom.currentVersion}</version>
<properties>
<ejb.manifest.classpath>true</ejb.manifest.classpath>
</properties>
</dependency>
</dependencies>
</project>

The discussion of building the ejb jars is incomplete without mentioning
the maven.xml file. This file is not straight forward as in the services
project. Listing 10 shows the maven.xml for the Reservation EJB project.
There are a few things happening here. First, the foobar-dist goal is used
as a wrapper for attaining the goal ejb:install. One of the first goals to
be achieved during the install is init, when the file system and other
resources are initialized and then the ejb classes are compiled. The
compiler expects to find the home, local and remote interfaces, failing
which it will throw a compiler error. This is where XDoclet comes into
play.

Listing 10 maven.xml for the Reservation EJB Project

<project default="foobar-dist" xmlns:m="jelly:maven"
xmlns:ant="jelly:ant">
<goal name="foobar-dist">
<attainGoal name="ejb:install" />
</goal>

<preGoal name="ejb:init">
<attainGoal name="xdoclet:ejbdoclet"/>
</preGoal>

<postGoal name="ejb:install">
<ant:property name="maven.ejb.install.dir"
value="${maven.repo.local}/${pom.artifactDirectory}/ejbs"/>
<ant:mkdir dir="${maven.ejb.install.dir}"/>
<ant:copy file="${maven.build.dir}/${maven.final.name}.jar"
tofile="${maven.ejb.install.dir}/../
jars/${maven.final.name}.jar"/>
</postGoal>
</project>

XDoclet is an open source project hosted on the SourceForge. By using EJB
Doclet specific tags in the Bean class (the implementation class), you
signal the XDoclet to generate the home, local and remote interfaces. You
will also provide the jndi names, and other information using similar
tags. On parsing the file, the XDoclet will also generate appropriate
deployment descriptors. Now let us get back to see how it fits in here.

XDoclet provides Maven plugins for generating the above-mentioned
artifacts. By specifying the ejbdoclet as the preGoal for ejb:init, you
will generate home, local and remote interfaces and xml deployment
descriptors just in time for the compilation.

Now let us look at the postGoal for ejb:install. As you know, the
ejb:install generates the ejb jar as the artifact and puts it in the
repository in the location "C:/Documents And
Settings/<login-id>/.maven/repository/Foobar-Online/jars". Suppose that
you want the ejbs to be in a separate directory called ejbs instead of the
jars, you have to do it after the ejb:install is finished with its
business. That's why it is a postGoal. For those familiar with Ant, the
postGoal is nothing but a collection of Ant tasks. Again, a couple of
Maven specific properties are used. Don't try to remember all of the Maven
defined properties at once. Over time, these will become second nature.

You will notice there are two distinct categories of properties - those
with their name beginning with pom and the rest of them. The properties
with their names beginning with pom are the individual elements in the
project.xml. For instance, the currentVersion element defined in
project.xml has a property with the name pom.currentVersion and so on. The
project.xml is loaded to create the POM model by Maven. POM model
attribute values are evaluated by using the $ sign before the attribute
names. As more plugins are added new properties emerge. This is going to
be a challenge. You may not find adequate documentation of these
properties. The only way to find out is by opening the scripts for each of
these plugins in plugin.jelly file. Luckily there aren't very many
properties that you will have to know.

In your project, if you find yourself writing the same pregoals and
postgoals for every ejb subproject for example, it is time to roll your
own plugin.

Building the WAR

After the ejb jar, it is wartime. We will accomplish quite a bit in this
section. First we will introduce you to the project.xml. Then we will add
a minor missing functionality into the war plugin. Then we will show you
how to use XDoclet to generate tlds for a sample tag. Then we will end the
section with maven.xml.

Listing 11 shows the project.xml for the Foobar web application. The
actual project definition has much more dependencies and is downloadable.
Here we are showing only the relevant portions to illustrate the concepts.
The important part is the dependencies section. The web application
depends on the J2EE APIs provided by the container at runtime as well as
compile time. However there is no need to bundle the J2EE API with the WAR
since it is the servlet container's responsibility. In addition the web
application depends on Struts 1.1 jar file. The property setting
<war.bundle>true</war.bundle> indicates that struts.jar has to be bundled
with the WAR. Whenever the war plugin is instructed to bundle the jars, it
puts them under the WEB-INF/lib directory of the WAR. Compare this to
manually copying the jars into the WEB-INF/lib directory in Ant. The WAR
also depends on the Foobar Services jar file, foobar-services-2.0.jar.
However we do not want to copy this jar into the WEB-INF/lib since it is a
dependency library and shared by both the web tier and the ejbs. (Recall
that any jars and classes residing in WEB-INF/lib and WEB-INF/classes are
loaded by the WAR class loader.) Hence we set the war.bundle property as
false for foobar-services jar file. You get all this functionality out of
the box with Maven war plugin.

Listing 11 maven.xml for the Web Project

<project>
<extend>${basedir}/../project.xml</extend>
<id>foobar-web</id>
<name>Foobar web application</name>
<package>foobar.webapp.*</package>
<description>Foobar Web project.</description>

<dependencies>
<dependency>
<groupId>j2ee</groupId>
<artifactId>j2ee</artifactId>
<version>1.3.1</version>
</dependency>

<dependency>
<groupId>jakarta-struts</groupId>
<artifactId>jakarta-struts</artifactId>
<version>1.0.2</version>
<properties>
<war.bundle>true</war.bundle>
</properties>
</dependency>

<dependency>
<groupId>Foobar-Travels</groupId>
<artifactId>foobar-services</artifactId>
<version>${pom.currentVersion}</version>
<properties>
<war.bundle>false</war.bundle>
<war.manifest.classpath>true</war.manifest.classpath>
</properties>
</dependency>
</dependencies>
</project>

However the Maven war plugin lacks one feature. It does not have the
capability to set the manifest classpath. Without this feature you cannot
expect to use dependency libraries. Hence I decided to add this feature to
the war plugin. Only two simple changes were required to achieve this. I
decided to illustrate this change to show how intuitive and easy it is to
write plugins in Jelly or customize the ones that already exist. Open the
plugin.jelly for the war plugin from C:/Documents And
Settings/<login-id>/.maven/plugins/maven-war-plugin-<version>-[SNAPSHOT].
These changes have to be done in the goal named war (The actual WAR -
deployment archive, is built in a goal named as war in the war plugin).
Add the following code in that goal.

<j:forEach var="dep" items="${pom.dependencies}">
<j:if
test="${dep.getProperty('war.manifest.classpath')=='true'}">
<j:set var="maven.war.classpath"
value="${maven.war.classpath} ${dep.artifact}"/>
</j:if>
</j:forEach>

This code iterates over each of the dependencies listed in the project.xml
(identified by pom.dependencies) and checks if the war.manifest.classpath
property is set to true. If so, then it appends that artifact name to a
property called maven.war.classpath.

The second change is needed when the manifest file is written out. The
manifest file is created by the ant plugin by executing a goal named
manifest. The manifest creation code is shown below. The line in bold is
the line I inserted to set the manifest classpath attribute. This uses the
previously set maven.war.classpath.

<ant:manifest>
<ant:attribute name="Built-By" value="${user.name}" />
<ant:attribute name="Class-Path" value="${maven.war.classpath}"/>
<ant:section name="${pom.package}">
<ant:attribute name="Specification-Title"
value="${pom.artifactId}" />
<ant:attribute name="Specification-Version"
value="${pom.currentVersion}" />
<ant:attribute name="Specification-Vendor"
value="${pom.organization.name}" />
</ant:section>
</ant:manifest>

That was simple wasn't it! Hopefully this will inspire you to write your
own plugins when needed, instead of repetitively adding tasks into
preGoals and postGoals.

Now I will show you how to use the XDoclet plugin to generate the tld
automatically. I will be using XDoclet version 1.2 Beta3. Consider the
declaration in the tld file for a tag say MyTag.

<tag>
<name>mystuff</name>
<tag-class>foobar.webapp.MyTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>locale</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>

It is okay to have a readymade tld for frameworks such as Struts. However
when you are developing your own tags either by customizing the existing
tags or from scratch, it is natural that they change and evolve constantly
during development. It can be time consuming to manually synchronize the
tag code and its declaration in the tld. XDoclet is designed to ease such
burdens. In the source code for the MyAppTag, add @jsp.tag name="myapptag"
body-content="JSP" in its class comments section. For each of the tag
attributes, add a @jsp.attribute on the getter method for that attribute.
For instance, add @jsp.attribute required="false" rtexprvalue="false" to
the comments on the getMyMessage method to represent that myMessage is a
tag attribute. Next you invoke the webdoclet goal from the xdoclet plugin
in maven.xml as shown in Listing 12. XDoclet also gives you provision to
generate the web.xml too. Let us look at the maven.xml for the Web project
in its entirety.

Listing 12 maven.xml for the Web Project

<project default="foobar-dist" xmlns:m="jelly:maven"
xmlns:ant="jelly:ant">
<goal name="foobar-dist">
<attainGoal name="war:install" />
</goal>

<preGoal name="war:init">
<attainGoal name="xdoclet:webdoclet"/>
</preGoal>

</project>

NOTE: You have to add the XDoclet web module in the dependency section for
the project.xml as follows.

<dependency>
<id>xdoclet+web-module</id>
<version>1.2b4</version>
</dependency>


In addition, override the following properties in the plugin.properties
file for XDoclet under the Maven plugins folder

maven.xdoclet.webdoclet.deploymentdescriptor.0=false
maven.xdoclet.webdoclet.jsptaglib.0.destDir=
${maven.build.dir}/${pom.artifactId}/WEB-INF/tld


The first setting disables web.xml generation and the second setting sets
the generated tld file location. In this article you will just be
generating the tld file, but not generating the web.xml, nor the <taglib>
entry for the tld file in web.xml. As a matter of fact, XDoclet does not
seem to have the Maven equivalent for the following Ant script that adds
the <taglib> to web.xml.

<deploymentdescriptor servletspec="2.3" destdir="${WEBINF}" >
<taglib uri="myapptaglibs" location="WEB-INF/tld/myapp.tld" />
</deploymentdescriptor>


Another thing that I noticed in the XDoclet plugin is that the file name
for the tag library definitions (tld) has to be provided in
plugin.properties as follows.

maven.xdoclet.webdoclet.jsptaglib.0.filename=myapp.tld


Otherwise the tld file is generated with the default name of taglib.tld.
This does not seem right. Instead it should be set in the build script.
For instance, in Ant this is done as follows

<jsptaglib jspversion="1.2" destdir="${WEBINF}/tld"
shortname="basic" filename="myapp.tld"/>


Ideally I would like to set this like this:

<dependency>
<id>xdoclet+web-module</id>
<version>1.2b4</version>
<properties>
<jsptaglib.filename>myapp.tld</jsptaglib.filename>
</properties>
</dependency>


This is not a Maven defect. It just is an example showing that it takes
time for third party vendors to catch up.


Building the EAR

Up until now you have seen how to create each of the individual artifacts
that go into the EAR. Finally we have reached the last part - building the
EAR itself. You might imagine that since the EAR is the only artifact from
the project as a whole, it should be built from the project definition at
the top of the hierarchy, i.e. the Foobar-Travels folder. However that is
not the case. The EAR is built as an artifact from a subproject called ear
(See Figure 3). Why this anomaly? First of all, the project.xml at the
Foobar-Travels project level is a template for other subprojects to
extend. If it were to specify the dependencies to build the EAR, then it
would have resulted in a cyclic dependency - a chicken and egg situation -
when the template is extended by other subprojects. If the template were
to be defined elsewhere, probably at the organization level, then the
project.xml in Foobar-Travels folder could have produced the EAR but then
it would not be the template for the rest of the subprojects to extend.

Listing 13 shows the project.xml for the ear project. In the listing, you
will not see every library on which the ear is dependent upon, just a few
relevant ones that need some explanation.

Listing 13 project.xml for the ear project

01 <project>
02 <extend>${basedir}/../project.xml</extend>
03 <id>foobar-travels</id>
04 <name>Foobar EAR</name>
05 <description>Sample EAR project.</description>
06 <shortDescription>Foobar EAR project</shortDescription>
07 <dependencies>
08 <dependency>
09 <groupId>j2ee</groupId>
10 <artifactId>j2ee</artifactId>
11 <version>1.3.1</version>
12 </dependency>
13 <dependency>
14 <groupId>xerces</groupId>
15 <artifactId>xerces</artifactId>
16 <version>1.4.4</version>
17 <properties>
18 <ear.bundle>true</ear.bundle>
19 </properties>
20 </dependency>
21 <dependency>
22 <groupId>${pom.groupId}</groupId>
23 <artifactId>reservationejb</artifactId>
24 <version>${pom.currentVersion}</version>
25 <type>ejb</type>
26 <properties>
27 <ear.bundle>true</ear.bundle>
28 </properties>
29 </dependency>
30 <dependency>
31 <groupId>${pom.groupId}</groupId>
32 <artifactId>foobar-web</artifactId>
33 <version>${pom.currentVersion}</version>
34 <type>war</type>
35 <properties>
36 <ear.bundle>true</ear.bundle>
37 <ear.appxml.ear.context-root>
38 foobar-online
39 </ear.appxml.ear.context-root>
40 </properties>
41 </dependency>
42 </dependencies>
43 </project>

* Line 25 Type = ejb indicates that this is a ejb jar, This is set in
application.xml
* Line 34 Type = war indicates that this is a war, This is set in
application.xml
* Lines 37-39 Sets the context root for the web application, This is
set in application.xml

The first dependency that you will find is on J2EE itself. This library is
not bundled since the container at runtime provides it. The second
dependency is on the xerces xml library - a representative of the
dependency library (including our very own services jar). Libraries such
as these may not be provided by the application server and have to be
bundled with the ear. Then comes the ejb jar itself. The type=ejb sets the
application.xml appropriately. Similarly, the web application is bundled
by specifying the dependency and type=war. The above project definition
automatically creates application.xml for the ear. By using ear:install as
the goal, the ear is also copied into the maven repository. The generated
application.xml is shown in Listing 14. Obviously, setting the type has
had its effect. Also note the web application context-root setting. The
short description from the project.xml is used as the display name for the
EAR. When Maven starts the execution of project.xml for the EAR it sees
the dependencies and then proceeds to create the artifacts for the
dependencies before creating the EAR itself.

Listing 14 Generated application.xml

<application>
<display-name>Foobar EAR project</display-name>
<module>
<java>xerces-logging-1.4.4.jar</java>
</module>
<module>
<ejb>reservationejb-2.0.jar</ejb>
</module>
<module>
<web>
<web-uri>foobar-web-2.0.war</web-uri>
<context-root>foobar-online</context-root>
</web>
</module>
</application>

We haven't looked at the maven.xml for the EAR project yet. It turns out
to be quite trivial in that it just executes the ear:install goal.

<project default="foobar-dist">
<goal name="foobar-dist">
<attainGoal="ear:install"/>
</goal>
</project>

Another file that you need to provide is project.properties. By default
auto-generation of application.xml is turned off. To force
auto-generation, you can set the property in project.properties as
follows:

maven.ear.appxml.generate=true

and place the file in the ear folder under Foobar-Travels directory.

Using the reactor

We have covered all the files in building a J2EE project, except one. This
file that we have been intentionally postponing till the end is the
maven.xml that accompanies the master project template. In the last
subsection on building EAR, I stated "When Maven starts the execution of
project.xml for the EAR it sees the dependencies and then proceeds to
create the artifacts for the dependencies before creating the EAR itself".
I lied! This is not completely true. The project definition for EAR is
just like any other project.xml. For every dependency stated in that file,
it will search the maven repository for the appropriate jar file. What
this means is that you will have to run maven individually from dependency
library projects, ejb projects, web application projects and finally the
ear project in that order to execute jar:install, ejb:install, war:install
and ear:install respectively. Now, that can be too cumbersome if not
impossible in a large project. Maven offers the reactor as a solution to
this problem.

Reactor is a tool for executing dependent multi-project builds. Given a
set of project.xmls, the reactor determines the correct order of execution
based on the dependencies listed in the respective project.xmls. More
news: The reactor can be declared using Jelly scripts in the maven.xml
file itself. This is what we will have in the maven.xml accompanying the
master project template. The maven.xml in the Foobar-Travels folder (See
Figure 3) is shown in Listing 15.

Listing 15 maven.xml using the reactor

<project default="foobar-buildall" xmlns:m="jelly:maven">
<goal name="foobar-buildall">
<m:reactor basedir="${basedir}"
includes="*/project.xml"
goals="foobar-dist"
banner="Building"
ignoreFailures="false"/>
</goal>
</project>

The foobar-buildall goal is written as a reactor. The script for
foobar-buildall in Listing 15 translates to simple English as "Starting
from the base directory from where maven is executed, go to every
subfolder and execute the goal identified by foobar-dist in every
project.xml and stop on failure". When you go to the base directory
(Foobar-Travels) and type in the command maven (since foobar-buildall is
the default goal), the reactor figures out the dependency by reading all
the project.xmls in the subdirectories and creates the artifacts in the
required order.

Conclusion

This article has explained how to use Maven effectively in a J2EE project
instead of plain old Ant scripts and bring about some order and modularity
to the otherwise chaotic world of build and deployment. Maven is something
that you should consider when looking for options to build and deploy in
your project. But I've have only scratched the surface of what constitutes
Maven. I hope this article has given you the confidence to build your J2EE
projects with Maven and sparked your curiosity to learn more about it.

About the Author

Srikanth Shenoy is a Technical Architect at Objectseek Inc.
(http://www.objectseek.com). He specializes in the architecture, design,
development, and deployment of large J2EE and EAI projects. He has helped
clients in the manufacturing, logistics, and financial sectors to realize
the Java's "write once, run anywhere" dream. He is a Sun Certified
Enterprise Architect and co- author of the upcoming book Practical Guide
to J2EE Web Projects. You can reach him at srikanth@srikanth.org.

Resources

* Download the Accompanying Source Code for this article.


-----------------------------------------
Get Free Email @BizHat.com
Report Spam: http://bizhat.com/contact.php