Tuesday, May 15, 2007

AJAX: The veins of Web 2.0

In Homer's Iliad "Ajax the great" is a legendary Greek warrior that the Trojans feared. AJAX is therefore a fitting name for a technology that could prove as unstoppable in conquering the web as Ajax was in fighting the Trojans.

Perhaps it is still too early to give Ajax more prominence than DHTML and Java, that have been around for much longer. But AJAX is a development platform that is already gaining traction on some of the most popular sites on the web.

Web 2.0 and AJAX are partners. Web 2.0 is about making the web more intelligent and interactive, building communities and encouraging collaboration. It doesn't prescribe how this vision is to be achieved, nor is it a development suite. It's simply a vision that speaks of a new way of thinking about the web.

AJAX is a collection of development tools that work together to make an individual web page more intelligent and interactive. In some sense AJAX fulfils the Web 2.0 culture of moving away from static web pages with fixed content towards a more dynamic and interactive experience. It doesn't quite fulfil every single Web 2.0 dream, but that may even be the reason why AJAX has become so popular so rapidly – it's a real technology with achievable implementation rather than an abstract description of a utopian vision.

The principle of making web pages more dynamic and interactive is not a new one. So what's so great about AJAX?

The early web was basically a collection of online documents that were interconnected through hypertext links. The vision was quite revolutionary at the time, because it connected chunks of isolated information with its interlinked content based around a common standard – HTML – and this increased the informational value of the entire network.

Even now, as in the early days of the web, web pages are often created offline and simply uploaded to the web server. Changes to the page requires manual editing offline and for the new version to be uploaded and copied over the old one. This was fine for posting an essay online, but it lacks interactivity and is also cumbersome to manage. The web had far greater potential in terms of information and content delivery than merely displaying static pages.

Technology evolved through the last decade and a half, to include more dynamism and interactivity on web pages using JavaScript, ActiveX, and XML, and more intelligent back-ends, such as SQL databases, CGI and ASP. This lead to the other kind of ASPs (Application Service Providers) such as Hotmail or Yahoo Notepad, as well as other interactive features like online forums and web-based chat.

HTML was never developed with real-time interactivity in mind, but it was still the foundation of the Internet and it became a major drawback. Any change to a web page – such as entering and saving information in a form or viewing the next image in a slideshow – typically required the web server to compose a new page in HTML and download that to the client.

In the late 1990s DHTML was touted as the first real answer to the demand for interactive pages. The beauty of it was that it made possible, for example, the client to display a new image on a web page without having to contact the server and request a whole new page. With DHTML however, web pages only appeared to be dynamic. All the content related to a page would be pre-loaded, and the page couldn't get additional information from the server without needing to refresh. Interactive web pages required information to be sent from the server to the client without needing to refresh the page.

The difference between AJAX and DHTML is subtle, but the implications are profound. AJAX uses many of the same tricks as DHTML, such as JavaScript and CSS, but the key difference is that AJAX can communicate with the server, and request new information, without needing to reload the page.

This seemingly trivial feature makes all the difference. No longer is a page limited by the information that can be loaded into the background. Instead it can have the full wealth of the information on the server at its fingertips, and yet present a solid and consistent front end to the user.

Without AJAX, pages like Google Earth would need to refresh each time you panned or zoomed. You can interact with the map using the intuitive tools you'd expect, such as dragging it around or zooming in and out. And all this takes place without the page needing to reload. An example of a site that does not use this technology is the Cricinfo.com – 'Live scorecard' feature which has to reload web pages constantly as new information is added.

AJAX uses a range of tools to bring web pages to life. At the core is XHTML (Extensible HTML), which is a fusion of XML and HTML and is ratified by the World Wide Web Consortium or W3C, who are the overseers of HTML and other web standards. XHTML brings the power of XML to web pages, with its ability to manage information and interact with servers in ways that HTML can't. XHTML works along with CSS to actually render the page.

The next piece of the puzzle is DOM (Document Object Model), which is a way of managing and manipulating the information in an HTML or XHTML document.

The final, and critical component, is XMLHttpRequest, which is a clumsy name for a very neat piece of technology. XMLHttpRequest is an API that works with a range of scripting languages, which in the case of AJAX is usually JavaScript. XMLHttpRequest can communicate directly with the server and request and manipulate data, and then pass that through to the page being viewed via JavaScript.

Another way to visualise AJAX in action is to picture the AJAX engine sitting in between the web and the page you're viewing. Instead of your page requesting information from the server directly, and constantly reloading, the AJAX engine does all the talking, and leaves your web page alone, with AJAX only updating the elements on the page that it needs to.

It's not that AJAX will completely transform the web, but it will further the evolution of the web from being a series of interlinked documents to being an information-based application platform. Online email, calendars, maps, stock market graphs, world clocks and image viewers are just some of the rudimentary applications of AJAX that are around today, with more sweeping implementations on the horizon.

AJAX doesn't do everything, nor does it purport to, but it has become a cornerstone of Web 2.0 technology which is without a doubt the single most significant development in web technology since the turn of the millennium.

Resources for the professional web designer

this is a list with the best design links submitted to 101out.com.

  1. Creating Beautiful Interfaces with CSS 18 points (video.google.com)

    Drop-down menus and sophisticated interface elements have traditionally been implemented using JavaScript and kludgy coding workarounds that often don't work. It's increasingly practical to deliver rich, beautiful, functional interfaces using semantic markup and CSS. Learn how modern markup can deliver great Web interfaces that are fast and reliable.

  2. Business side of web design 17 points (www.centernetworks.com)

    A interesting 40 step plan presented by James Archer of Forty

  3. Web Standards - Business Benefits 15 points (boagworld.com)

    This presentation introduces you to a web design approach called Web Standards. It aims to explain exactly what web standards are and why they provide huge business benefits that will increase the exposure of your site, attract new audiences and make the running of your website considerably more efficient. In short we will explain how web standards will improve your return on investment.

  4. CSS Formatter and Optimiser 14 points (www.cleancss.com)

    CSS Formatter and Optimiser (based on csstidy 1.1)

  5. Reducing Your Website's Bandwidth Usage 12 points (www.codinghorror.com)

    What can we do to reduce a website's bandwidth usage?

  6. 25 Code Snippets for Web Designers (Part1) 12 points (tutorialblog.org)

    There are loads of handy scripts, bits of html and widgets that you can incorporate into your websites and blogs - here we bring together 25 of the most helpful in the first part of this series...

  7. Website Launch Flowchart 12 points (www.virante.com)

    The flowchart is a detailed guide that covers optimized website design, development and multichannel marketing integration. Web design doesn't exist in a vacuum nor does marketing. The most optimized, easiest functioning and best performing sites are those that find a balance between design, content, business tool complexity and marketing integration.

  8. Eyetracking points the way to effective news article design 12 points (www.ojr.org)

    OJR's design experts review usability research and offer suggestions on how you can make your online articles better connect with readers.

  9. Creating the foundation for robust architecture 12 points (www-128.ibm.com)

    The answer to "What is architecture?" depends on who you ask. What it takes to develop a strong architecture is even more difficult to define. However, there are well-known tenets you should employ when doing architecture.

  10. Best Practices for form design 12 points (www.lukew.com)

    Rules, requirements and suggestions for quality form designs. A nice presentation by Luke Wroblewski.

  11. 71 CSS Menus for free 11 points (razvan.seopedia.ro)

    Great list of resources for CSS developers [ro]

  12. Creating User Friendly 404 Pages 11 points (www.codinghorror.com)

    We understand what 404 means: Page Not Found. But the average internet user has no idea what 404 means or what to do about it. To them, it's yet another unintelligible error message from the computer. Most 404 pages are unvarnished geek-speak...

  13. Web Page Readability / Usability Research 10 points (hubel.sfasu.edu)

    An interesting collection of resources related to variables that relate to readability of text displays on web pages.

  14. Nice and clean table CSS designs 10 points (icant.co.uk)

    Data tables and cascading style sheets gallery.

  15. Rss 2.0 and Atom 1.0 Compared 10 points (intertwingly.net)

    People who generate syndication feeds have a choice of feed formats. As of mid-2005, the two most likely candidates will be RSS 2.0 and Atom 1.0. The purpose of this page is to summarize, as clearly and simply as possible, the differences between the RSS 2.0 and Atom 1.0 syndication languages.

  16. No more tables: CSS layout techniques 13 points (video.google.com)

    Creating complex multi-column layouts used to mean having to nest multiple HTML tables, a technique that's cumbersome and introduces accessibility and compatibility problems. You've heard it's possible to eliminate those layout tables by using Cascading Style Sheets, but you haven't made the jump yet. In this session, CSS guru Doug Bowman will walk you through the steps of a real-world conversion. Learn the advantages of doing away with tables, and see how to avoid common pitfalls.

  17. 168 CSS Layouts made in Cross Browser, Standards Compliant CSS. 9 points (layouts.ironmyers.com)

    These CSS Layout offers full Grade-A browser support. That means that these CSS Layout will look and behave the same in internet browsers like Internet Explores 6 (IE6), Internet Explorer 7 (IE7), Firefox, Opera, Safari and so on.

  18. Designing With Grid-Based Approach 9 points (www.smashingmagazine.com)

    The main idea behind grid-based designs is a solid visual and structural balance of web-sites you can create with them.

  19. Why you should be using HTML instead of XHTML 9 points (www.google.com)

    If you're a web developer, you've probably heard about XHTML, the markup language developed in 1999 to implement HTML as an XML format. Most people who use and promote XHTML do so because they think it's the newest and hottest thing, and they may have heard of some (usually false) benefits here and there. But there is a lot more to it than you may realize, and if you're using it on your website, even if it validates, you are probably using it incorrectly.

  20. Help to make the internet a prettier place 9 points (www.openwebdesign.org)

    Open Web Design is a community of designers and site owners sharing free web design templates as well as web design information. A good resource for web designers.

  21. Ten Common Database Design Mistakes 8 points (www.simple-talk.com)

    No list of mistakes is ever going to be exhaustive. People (myself included) do a lot of really stupid things, at times, in the name of "getting it done." This list simply reflects the database design mistakes that are currently on my mind, or in some cases, constantly on my mind.

  22. Measuring Web Site Usability 8 points (www.readwriteweb.com)

    In Jakob Nielsen's latest book, Prioritizing Web Usability, the usability guru presents his latest discoveries on how to design usable web sites. His meticulous research is based on lab experiments, with thousands of users of diverse backgrounds.

  23. HTML5, XHTML2, and the Future of the Web 8 points (www.digital-web.com)

    XHTML2 is XML - just as XHTML 1.0 is - but it doesnt have backward compatibility to HTML 4.01. HTML5 (also sometimes referred to as Web Applications 1.0) is a technology developed by the WHATWG, an open community started by three of the four major browser vendors: Mozilla, Opera, and Apple. HTML5 is not so much a replacement for HTML 4.01 or XHTML 1.0 as it is an upgrade or evolution.

  24. Guidelines for Desigining User Interface Software 8 points (www.hcibib.org)

    This report offers guidelines for design of user interface software in six functional areas: data entry, data display, sequence control, user guidance, data transmission, and data protection. 944 guidelines compiled by U.S. Air Force, most of them related to military command and control systems built in the 1970s and early 1980s.

  25. The beauty of data visualization 8 points (pingmag.jp)

    This list brings up the most beautiful outpourings of information aesthetics. This is a symbiosis between creative design and information visualization: form follows data and evolves in such unique graphs that you can call them art.

  26. How To Design A Good API and Why it Matters 8 points (video.google.com)

    Nearly all programmers occasionally function as API designers, whether they know it or not. A well-designed API can be a great asset to the organization that wrote it and to all who use it. Good APIs increase the pleasure and productivity of the developers who use them, the quality of the software they produce, and ultimately, the corporate bottom line.

  27. The 32 Best Photography Sites in 2007 8 points (www.photosbyjay.com.au)

    The 32 Best Photography Sites in 2007. There are some photography sites here you may know, as well as some Australian and obscure ones you may have never seen before.

  28. Choosing the right font 8 points (www.designersmind.com)

    Designers spend a large portion of their work time contemplating the aspects of text and/or font. In order to help understand the importance of font, ask yourself What differences are there between the font and text of professional designs as opposed to low quality work?

  29. Murray Gell-Mann on Getting Creative Ideas 8 points (video.google.com)

    Famous theoretical physicist Murray Gell-Mann gives a talk on Getting Creative Ideas. Followed by an interesting question sessing. From the Google Tech Talks, March 14, 2007.

  30. High Performance Web Sites: The Importance of Front-End Performance 11 points (developer.yahoo.net)

    Steve Souders is Yahoo!'s Chief Performance Yahoo!. This is one in a series of blogs describing the best practices he's developed at Yahoo! for improving performance. This article is based on Chapter 1, The Importance of Front-End Performance from Steve's forthcoming book High Performance Web Sites, published by O'Reilly.

  31. Handbook of Software Architecture 7 points (www.booch.com)

    The primary goal of the Handbook of Software Architecture is to fill this void in software engineering by codifying the architecture of a large collection of interesting software-intensive systems, presenting them in a manner that exposes their essential patterns and that permits comparisons across domains and architectural styles. [registration required]

  32. Proposal for a scalable class of graphical models for Social Networks 7 points (www.cs.cmu.edu)

    This proposal is about new statistical machine learning approaches to detect evolving relationships among large numbers of entities. One example is the set of friendship relations among participants in Friendster.

  33. Listamatic: CSS and lists 7 points (css.maxdesign.com.au)

    Take a simple list and use different Cascading Style Sheets to create radically different list options? The Listamatic shows the power of CSS when applied to one simple list. Good resource.

  34. CSS: Advanced Formatting and Organization 7 points (jarrodspillers.com)

    Gone are the days of the table based layout days where CSS, if used at all, would simply be a replacement for the notorious font tag. In this day it is very common for a stylesheet to contain many times more line of code than its corresponding XHTML document. Part of the challenge of witting good CSS is not just learning the correct properties to use, but formatting and organizing your document in a way that allows for easy maintenance and speedy display bug fixes.

  35. Software design for users 7 points (www.infoq.com)

    Unless you're writing programs for a bunch of burned out computer geeks, your user isn't you. ... This is very hard to get through somebody's head; it's very hard to get rid of this notion that what you like your user is going to like... Again, your user is not you.

  36. Color Matching Guide 7 points (www.elogodesign.com)

    Learn basics about colors and color matching.

  37. Static vs. Dynamic urls 7 points (video.google.com)

    Matt Cutts answers Google questions on Static vs. Dynamic urls: Does PageRank flow the same to both? What pitfalls should I avoid with dynamic urls? Can Sitemaps alert webmasters when their site has been hacked?

  38. Icon Design: Sizing 7 points (mezzoblue.com)

    "One of the more deceptively time-consuming things youll do when creating an icon is producing out size variations. If you require a single icon in more than one size, the time you spend designing the first size is only about two thirds of the work youll end up doing; the other third lies in tweaking it for different dimensions."

  39. Research Supporting How Line Length Affects Usability 7 points (www.webusability.com)

    Certain aspects of usability have been researched for over 120 years. One active area of investigation has been the influence of line length on the speed of reading prose text. Cohn (1883) confirmed that 3.6 inches (90 mm) was the best length, and that 4 inches (102 mm) was the longest admissible line length.

  40. Video Tutorials on how to use the Firebug Extension 10 points (www.litfuel.net)

    Firebug is a must know tool for web developers now. If you've heard of it but haven't had time to play around with it please look at these videos to see what you're missing out on. The first tutorial covers an introduction to debugging ajax applications with firebug. The second tutorial shows you how you can manipulate CSS live on your webpage without having to change code, reload, change code, reload.

  41. Complete Logo Design Guide 10 points (www.elogodesign.com)

    A list of quality resources that can help you to learn more about everything related to logo design. From the start, why do you need a good logo; which software to use and why; how to use software, which format is used for what and why; how to choose colors; how to choose fonts; where to ask for help and direction; where to find inspirational help, what other logo designers know and you don't...

  42. Faux Column CSS Layouts 10 points (www.code-sucks.com)

    There are 42 Faux Column CSS Layouts available for download. All of these css layouts use a background image to make it look like all the columns are of equal height.

  43. Website Optimizer [from Google] 10 points (services.google.com)

    Their description: "Website Optimizer, Google's free multivariate testing application, helps online marketers increase visitor conversion rates and overall visitor satisfaction by continually testing different combinations of site content (text and images)"

  44. Top 50 Sources for Web Design Inspiration 6 points (www.fuzzyfuture.com)

    This list is intended to help you with your designer's block and give you the inspiration you need to come up with the perfect design for your next blog, community portal, social networking hub, or corporate e-commerce resource.

  45. My Favorite Free Fonts 6 points (www.elogodesign.com)

    Collection of favorite free fonts.

  46. How to make sexy buttons with CSS 6 points (www.oscaralexander.com)

    This tutorial will teach you how to create pretty looking textual buttons (with alternate pressed state) using CSS. Dynamic buttons save you heaps of time otherwise spent creating graphics and will basically make you a happier person at the end of the day.

  47. Use text instead of graphics on your website | Improve the Web 6 points (www.improvetheweb.com)

    Numerous eye-tracking studies, done by multiple large research companies (many of which having been researching website usability for a while), have shown that, though humans are sometimes attracted to graphics...

  48. CSS creme of the month 6 points (www.roscripts.com)

    Every once in a while we try to identify what's hot in one of our categories and this time we picked CSS since it's becoming more popular with each day that goes by. More and more web designers become interested in learning every trick. A good way to do it is by good examples which is what this list will try to showcase. The best CSS examples of the month.

  49. Ajax and XML: Five Ajax anti-patterns 12 points (www-128.ibm.com)

    You can learn a lot about how to do things correctly by understanding how things are done incorrectly. Certainly, there's a right way and a wrong way to write Asynchronous JavaScript + XML (Ajax) applications. This article discusses some common coding practices you will want to avoid.

  50. Keep It Simple, Stupid! 12 points (www.smashingmagazine.com)

    Simplicity is more complex than you probably think it is. To design a web-site in user-friendly tones, presenting all information and removing unnecessary details isnt easy. In fact, many designers dont manage to find the right mix between details and their presentation on the screen, which usually results in an information overkill and/or decreased usability. However, some designers do manage to find the right balance and create usable, elegant and clean web-sites with simple layouts.

Monday, May 14, 2007

An evening with Google's Marissa Mayer

posted Wednesday, 12 January 2005
Last night I went to the BayCHI lecture at PARC given by Marissa Mayer (Product Manager for Google). A very well attended (standing room only session), Marissa took us through a presentation geared around the user experience at Google and the efforts/lengths they go to.

Some interesting facts came out:

  1. The prime reason the Google home page is so bare is due to the fact that the founders didn't know HTML and just wanted a quick interface. Infact it was noted that the submit button was a long time coming and hitting the RETURN key was the only way to burst Google into life.
  2. Due to the sparseness of the homepage, in early user tests they noted people just sitting looking at the screen. After a minute of nothingness, the tester intervened and asked 'Whats up?' to which they replied "We are waiting for the rest of it". To solve that particular problem the Google Copyright message was inserted to act as a crude end of page marker.
  3. One of the biggest leap in search usage came about when they introduced their much improved spell checker giving birth to the "Did you mean..." feature. This instantly doubled their traffic, but they had some interesting discussions on how best to place that information, as most people simply tuned that out. But they discovered the placement at the bottom of the results was the most effective area.
  4. The infamous "I feel lucky" is nearly never used. However, in trials it was found that removing it would somehow reduce the Google experience. Users wanted it kept. It was a comfort button.
  5. Orkut is very popular in Brazil. Orkut was the brainchild of a very intelligent Google engineer who was pretty much given free reign to run with it, without having to go through the normal Google UI procedures, hence the reason it doesn't look or feel like a Google application. They are looking at improving Orkut to cope with the loads it places on the system.
  6. Google makes changes small-and-often. They will sometimes trial a particular feature with a set of users from a given network subnet; for example Excite@Home users often get to see new features. They aren't told of this, just presented with the new UI and observed how they use it.
  7. Google has the largest network of translators in the world
  8. They use the 20% / 5% rules. If at least 20% of people use a feature, then it will be included. At least 5% of people need to use a particular search preference before it will make it into the 'Advanced Preferences'.
  9. They have found in user testing, that a small number of people are very typical of the larger user base. They run labs continually and always monitoring how people use a page of results.
  10. The name 'Google' was an accident. A spelling mistake made by the original founders who thought they were going for 'Googol'
  11. Gmail was used internally for nearly 2years prior to launch to the public. They discovered there was approximately 6 types of email users, and Gmail has been designed to accommodate these 6.
  12. They listen to feedback actively. Emailing Google isn't emailing a blackhole.
  13. Employees are encouraged to use 20% of their time working on their own projects. Google News, Orkut are both examples of projects that grew from this working model.
  14. This wasn't a technical talk so no information regarding any infrastructure was presented however they did note that they have a mantra of aiming to give back each page with in 500ms, rendered.
  15. Quote: Give Users What They Want When They Want It
  16. Quote: Integrate Sensibly
All in all, a very interesting evening and I thank my colleague Mary Weeks for inviting me to come along and attend. Much appreciated.

Common Web Design Mistakes Prevent Google From Indexing Your Site

Web Designers frequently destroy their clients’ chances of ranking well in Google, without even knowing it! Here are three common mistakes that can ruin a client’s chances of ranking well in Google, Yahoo or MSN - simply by preventing the site from being indexed!
Search engines follow regular text links, but web designers like to use these unfriendly search engine navigation methods:

1. JavaScript Menus
Search Engines do not follow links reliably in JavaScript, if at all.

2. Imagemaps
Search Engines cannot see the image, and so cannot classify the relevance or topic of the link. Lesser search engine robots do not even attempt to follow imagemap links.

3. Image Links / Rollover links
These links frequently contain JavaScript, but also are difficuly for search engines to classify.

4. JavaScript popups
Search Engines do not follow JavaScript reliably, and do not seem to like popups at all!

5. “Jump menus”
These pulldown menus are usually submitting a form. If the form target is sent GET requests, there is a chance that the links will be followed in some manner, but again - this isn’t reliable navigation for Search Engines.

6. NOSCRIPT embedded links
We were told that content in NOSCRIPT tags is for those visitors that have JavaScript off. But if you were told this means search engines, you were told wrong! This HTML tags has been abused by spammers early on, and search engines do not reliably follow navigation within these tags.

7. Frames - they’re rarely done in a search friendly manner
More on the “right way” in a later post. Frames are challenging for search engines, and we have recently seen Google penalizing framee-based sites, perhaps due to the usability challenges they can present.

8. Java
Java cannot be executed by search engines. Many early rollover effects relied on Java, but the navigation cannot be read by search engine robots.

9. Flash
Flash navigation cannot be followed by search engines. Splash pages can become a deadend for search engines, and alternatives to Flash navigation should always be given.
So what can you do to be sure that search engines will crawl your site? We’ll have answers in a future post, but a frequent supplement to websites that use the above techniques - meant almost entirely for search engines - is a set of footer links for seach engines to follow.

Tags: , , , , ,

Thursday, May 10, 2007

What Is Quartz

by Chuck Cavaness, author of Programming Jakarta Struts, Second Edition
09/28/2005
Quartz
Quartz is an open source job-scheduling framework written entirely in Java and designed for use in both J2SE and J2EE applications. It offers great flexibility without sacrificing simplicity. You can create simple or complex schedules for executing any job. It includes features such as database support, clustering, plugins, prebuilt jobs for EJB, JavaMail and others, support for cron-like expressions, and many more.

In This Article:

  1. Job Scheduling Made Easy
  2. The History Behind Quartz
  3. Getting Your Hands on Quartz
  4. Inside the Quartz Architecture
  5. Jobs, Jobs, and More Jobs
  6. Job Management and Storage
  7. Available JobStores
  8. Jobs and Triggers
  9. Scheduling a Job
  10. Calling Your Jobs with the Scheduler
  11. Programmatic vs. Declarative Scheduling
  12. Stateful and Stateless Jobs
  13. Other Features of the Quartz Framework
  14. What's down the Road?
  15. Finding Out More About Quartz

Have you ever needed an application to perform a task that runs daily, every other Tuesday at 11:30 p.m., or maybe only on the last day of every month? A task that can run automatically, in a hands-off mode, and, if a serious error occurs during execution, the application will be so self aware that it declares a misfire and attempts to run itself again? Are you and your team programming in Java? If you've answered yes to any of these questions, then you ought to be using the Quartz Scheduler.

Job Scheduling Made Easy

Quartz is an open source job-scheduling framework written entirely in Java. Don't let the term job scheduling frighten you. While the Quartz framework is packed with many bells and whistles, in its simplest form, it's almost scary how easy it is to use.

Simply create a Java class that implements the org.quartz.Job interface. The Job interface contains a single method:

public void execute(JobExecutionContext context)
throws JobExecutionException;

In your Job class, add some logic to the execute() method. Once you configure the Job class and set up the schedule, Quartz will take care of the rest. When the Scheduler determines it's time to notify your Job, the Quartz framework will call the execute() method on your Job class and allow it to do its thing. You don't have to report anything back to the Scheduler or call anything special. Just perform the tasks within the Job and end. If you configure your Job to be called again at a later time, the framework will take care of calling again at the right time.

If you've used other popular open source frameworks, like Apache Struts, you'll be comfortable with the design and components in Quartz. Even though the two open source projects solve completely different problems, there are enough similarities that everyday users of open source software will feel right at home. Quartz can be used within a stand- alone J2SE application, as an RMI server, within a web application, and even within a J2EE Application Server.

The History Behind Quartz

Quartz has been around for a while, although it has started to receive a lot of attention this year. It was created by James House and originally added as a SourceForge project in the spring of 2001. Over the next several years, a number of features and releases came, but it wasn't until the project was moved to a new site and became part of the OpenSymphony family of projects, that it really started to take off and receive the attention it deserves.

House still participates in much of the development work, with several part-time developers assisting him. The Quartz development team has been able to release several new versions this year, including the 1.5 release, which is currently in a candidate release stage.



Getting Your Hands on Quartz

The Quartz project is hosted on OpenSymphony's site. On the Quartz site, you will find all of the usual suspects: JavaDocs, documentation including tutorials, CVS access, links to the user and developer forums, and, of course, the downloads.

Grab the distribution from the download link and unzip it to a local directory. The download includes a prebuilt Quartz binary that you can drop into your application. The framework requires very few third-party libraries, and those that are required, you are probably already using anyway.

From the distribution, you'll want to add the third-party libraries from the /lib/core and /lib/optional directories to your project. Most of these libraries are the standard Jakarta Commons libraries that we all know and love like Commons Logging, Commons BeantUtils, and so on.

The quartz.properties File

Quartz includes a configuration file called quartz.properties, which allows you to modify the runtime environment of the framework. By default, the version of this file contained within the Quartz binary is used. You should create a copy of this file and put it in your classes directory so that it can be found by the class loader. A sample quartz.propeties file is shown in Example 1.

Example 1. The quartz.properties file allows you modify the Quartz runtime:

#===============================================================
# Configure Main Scheduler Properties
#===============================================================

org.quartz.scheduler.instanceName = QuartzScheduler
org.quartz.scheduler.instanceId = AUTO

#===============================================================
# Configure ThreadPool
#===============================================================

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5

org.quartz.threadPool.threadPriority = 5

#===============================================================
# Configure JobStore
#===============================================================

org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

Once you have the Quartz binary and the third-party libraries added to your project, and the quartz.properties in the classes directory, it's time to create some Jobs. Before we do, however, let's take a short detour and talk briefly about the Quartz architecture.

Inside the Quartz Architecture

In terms of size, Quartz is comparable to most other open source frameworks. It contains approximately 300 Java Classes and Interfaces organized into roughly 12 packages. This compares to approximately 325 Classes and Interfaces and 11 packages in Apache Struts. Although size is rarely a characteristic used to determine the quality of a framework, the point here is that there's a lot of functionality included within Quartz, and functionality and feature set is, and should be, one factor used to judge the quality of a framework, open source or not.

The Quartz Scheduler

At the heart of the Quartz framework is the Scheduler. The Scheduler is responsible for managing the runtime environment for your Quartz application. It doesn't do all of the work by itself, but depends on some very important components within the framework. Quartz is very much about threads and thread management. To ensure scalability, Quartz is based on a multithreaded architecture. When started, the framework initializes a set of "worker threads" that are used by the Scheduler to execute the scheduled Jobs. This is how Quartz is able to run many Jobs concurrently. Quartz relies on a loosely coupled set of ThreadPool management components to manage the thread environment. We'll mention it several times throughout the article, but just about everything in Quartz is either configurable or customizable. So, for example, if you wanted to "plugin" your own ThreadPool management facilities, guess what, you can!

Jobs, Jobs, and More Jobs

In Quartz lingo, a Job is simply a Java class that performs a task. This task can be anything that you can code in Java. The only requirement is that you implement the org.quartz.Job interface and throw a JobExecutionException in the case of a serious error. You saw in the beginning that the Job interface contains a single method, execute().

Once you implement the Job interface and implement the execute() method, Quartz will invoke your Job when it determines it's time for the Job to run. What you do inside the execute() method is entirely up to you. Here are a few examples of things you might want to do inside a Job:

  • Use JavaMail (or another Mail framework like Commons Net) to send emails

  • Create a remote interface and invoke a method on an EJB

  • Get a Hibernate Session, and query and update data in a relational database

  • Use OSWorkflow and invoke a workflow from the Job

  • Use FTP and move files around

  • Call an Ant build script to kick off scheduled builds

The possibilities are endless and that's what makes the framework so powerful. Quartz provides you with the mechanism to establish a very granular, repeatable schedule, and then you just create Java classes that get called to execute.



Job Management and Storage

Once Jobs have been scheduled, the Scheduler needs to remember and keep track of the Jobs and the times to execute them. It wouldn't be very useful if your Job is called 30 minutes late or even 30 seconds early. In fact, Job execution needs to be very exact and prompt about calling the execute() methods on the scheduled jobs. Job storage and management is done through a concept Quartz refers to as a JobStore.

Available JobStores

The Quartz framework provides two basic types of JobStores. The first type, which utilizes ordinary memory (RAM) to persist Scheduler information, is called RAMJobStore. This type of JobStore is the easiest to configure and get up and running. For many applications, this JobStore will be sufficient. However, since the Scheduler information is stored in the memory assigned to the JVM, when the application is stopped, all knowledge of the schedule is lost. If you need to persist schedule information between restarts, then you're going to need the second type of JobStore.

The second type of JobStore actually comes with two different implementations in the framework, but both are commonly referred to as JDBC JobStores. Both JDBC JobStores use a JDBC driver and require a backing from a relational database to persist the scheduler information. The two types differ in whether or not you want to control the database transactions or relinquish control to an application container such as BEA's WebLogic or JBoss. (This is similar to the difference between Bean Managed Transactions or Container Managed Transactions from the J2EE world.)

The two JDBC JobStores are:

  • JobStoreTX: used when you want to control transactions or when you're operating in a nonapplication server environment

  • JobStoreCMT: used when operating within an application server environment and you want the container to manage the transactions

The JDBC JobStores are designed for users who require the Scheduler to maintain scheduling information, even after a shutdown and startup.

Jobs and Triggers

Jobs are only half the equation. The designers of Quartz made a design choice to separate the Job from the schedule. A Trigger in Quartz is used to tell the Scheduler when a Job should be triggered (or fired). The framework comes with a handful of Trigger types, but the two most commonly used are the SimpleTrigger and the CronTrigger.

The SimpleTrigger is designed for when you need a simple firing schedule. Typically, if you need to fire a Job at a given time and repeat (n) number of times, possibly waiting (m) seconds between firings, then the SimpleTrigger is for you. If on the other hand, you have a much more complicated scheduling need for your Job, then the CronTrigger will probably be required.

The CronTrigger is based on Calendar-like schedules. When you need a Job executed every day at 10:30 a.m., except on Saturdays and Sundays, then a CronTrigger should be used. As the name implies, the CronTrigger is based on the Unix cron expression. As an example, the following Quartz cron expression would execute a Job at 10:15 a.m. every day, Monday through Friday.

0 15 10 ? * MON-FRI

and this expression

0 15 10 ? * 6L 2002-2005

fires at 10:15 a.m. on the last Friday of every month during the years 2002, 2003, 2004, and 2005.

You can't do this with the SimpleTrigger. Either can be used for your Jobs. Which one just depends on your schedule needs.

Scheduling a Job

So, let's take this discussion into the practical realm by looking at an example Job. Suppose that you manage a department that needs to be notified by email whenever a client stores a file on its FTP site. Our Job will FTP to a remote server and download any files found there. It will then send an email containing the number of files found and downloaded. This Job would be handy to prevent someone from having to manually performing this task during the day, not even considering during the night. We can set this Job up to check every 60 seconds and to run indefinitely, 24 hours a day, seven days a week. This is a perfect use of the Quartz framework!

The first step is to create the Job class that will perform the FTP and Email logic. The following Example shows our Quartz Job class, which implements the org.quartz.Job interface.

Example 2. A Quartz Job that downloads files from a FTP site and sends an Email

public class ScanFTPSiteJob implements Job {
private static Log logger = LogFactory.getLog(ScanFTPSiteJob.class);

/*
* Called the scheduler framework at the right time
*/
public void execute(JobExecutionContext context)
throws JobExecutionException {

JobDataMap jobDataMap = context.getJobDataMap();

try {
// Check the ftp site for files
File[] files = JobUtil.checkForFiles(jobDataMap);

JobUtil.sendEmail(jobDataMap, files);
} catch (Exception ex) {
throw new JobExecutionException(ex.getMessage());
}
}

}

We intentionally kept the ScanFTPSiteJob very simple. We created a utility class for this example called JobUtil. That's not part of Quartz, but it makes sense to build your own library of utilities that various Jobs can reuse. We could have just as easily put all of that code inside the Job class and the Quartz Scheduler would have been just as happy, but reuse doesn't stop just because we're using Quartz.

The parameters that the JobUtil.checkForFiles() and JobUtil.sendEmail() methods use come from the JobDataMap object, which is a Quartz-created object. An instance of it is created for every Job execution and it is a way to pass configuration parameters to your Job class.

The implementation of the JobUtil is not shown here, but we could very easily use the Commons Net from Jakarta to implement both the FTP and Email functionality.



Calling Your Jobs with the Scheduler

Creating the Job is the first step, but to get your Job called by the Scheduler, you need to indicate to the Scheduler how often, and at what time, your Job should be called. This is done by associating a Trigger to the Job. Since we are only interested in calling the Job every 60 seconds or so, and repeating this Scheduler forever, we are going to use a SimpleTrigger.

Jobs and Triggers are scheduled through the Quartz Scheduler interface. In order to get an instance of the Scheduler, we need to create one from the factory. The easiest way to do this is to call the static method getDefaultScheduler() on the StdSchedulerFactory class.

When using the Quartz framework, you're required to start the Scheduler by calling the start() method. The code in Example 3 follows a common pattern of most Quartz applications: create one or more Jobs, create and set up the Triggers, schedule Jobs and Triggers with the Scheduler, and start the Scheduler. (Note: the Scheduler could have been started first, it doesn't matter.)

Example 3. Quartz Jobs have to be scheduled through the Quartz Scheduler.

public class MyQuartzServer {

public static void main(String[] args) {
MyQuartzServer server = new MyQuartzServer();

try {
server.startScheduler();
} catch (SchedulerException ex) {
ex.printStackTrace();
}
}

protected void startScheduler() throws SchedulerException {

// Use the factory to create a Scheduler instance
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

// JobDetail holds the definition for Jobs
JobDetail jobDetail =
new JobDetail("ScanFTPJob", Scheduler.DEFAULT_GROUP,
ScanFTPSiteJob.class);

// Store job parameters to be used within execute()
jobDetail.getJobDataMap().put(
"FTP_HOST",
"\\home\\cavaness\\inbound");

// Other neccessary Job parameters here

// Create a Trigger that fires every 60 seconds
Trigger trigger = TriggerUtils.makeSecondlyTrigger(60);

// Setup the Job and Trigger with the Scheduler
scheduler.scheduleJob(jobDetail, trigger );

// Start the Scheduler running
scheduler.start();
}
}

Programmatic vs. Declarative Scheduling

In Example 3, we scheduled our ScanFTPSiteJob using a programmatic approach. That is, we used Java code to setup the Job and Trigger with the Scheduler. The Quartz framework also supports setting up the Job schedule declaratively in XML files. A declarative approach allows us to more quickly modify which Jobs are being executed and when.

The Quartz framework includes a "plugin" that reads an XML file containing Job and Trigger information upon startup of a Quartz application. All Jobs within the XML are added to the Scheduler, along with their associated Triggers. You still have to write the Job classes, of course, but configuring the Scheduler with those Job becomes very dynamic. Example 4 shows an example XML file that performs the same logic as the code in Example 3, but just in a

declarative fashion.

Example 4. Quartz Jobs can also be scheduled using an XML File.





ScanFTPSiteJob
DEFAULT

A job that scans an ftp site for files

ScanFTPSiteJob




FTP_HOST
\home\cavaness\inbound









ScanFTPSiteJobTrigger
DEFAULT
ScanFTPSiteJob
DEFAULT
2005-09-11 6:10:00 PM

-1
60000




You should be able to match the XML elements from Example 4 with the Java code from

Example 3--they are conceptually the same. The benefit of using a declarative approach like the one shown in Example 4 is that maintenance becomes extremely simple, as changes only require a change to the XML file and a restart of the Quartz application. No source code changes, no recompilation, and no redeployment of the new build.



Stateful and Stateless Jobs

The Quartz Job examples that you have seen in this article have all been stateless. This means that for each Job execution, any changes made to the JobDataMap during the Job's execution are not maintained between executions. If you need to ability to add, change, or remove values from the JobDataMap, and have those changes seen by the Job during the next execution, a Quartz Stateful Job will be required.

If you're an experienced EJB developer, I'm sure you're wincing right now because Stateful has taken on a negative connotation. This is primarily due to the scalability issues that "Stateful EJBs" present. Quartz Stateful Jobs are implemented by the org.quartz.StatefulJob interface. The key difference between stateless and stateful Jobs is that Stateful Jobs can have only a single instance of the Job definition executing at a time. So, using our example from Example 3, we could only have one instance of the "ScanFTPJob" Job executing at a time. For most situations, this doesn't present a huge problem. If, however, you have a Job that needs to execute so often, or one that takes a long time to finish, Stateful Quartz Jobs may present a scalability problem for you.

Other Features of the Quartz Framework

The Quartz framework has a very rich feature set. In fact, there are too many features to really appreciate in just one encounter. The following list will give a taste of some of the other features contained within Quartz that we won't have time to talk about in detail here.

Listeners and Plugins

Everybody likes Listeners and Plugins. Download just about any open source framework today and you'll be sure to find support for both of these concepts.

Quartz Listeners are Java Classes that you create and that will receive callbacks from within the framework when key events take place. For example, when a Job is scheduled or unscheduled, or when a Trigger has ended and will not fire anymore, all can be setup to notify your Listener. The framework includes Listeners for the Scheduler, for Jobs, and for Triggers. You can also configure the Job and Trigger Listeners to be global or specific to a Job and/or Trigger.

Once your concrete Listener is called, you can use this knowledge to perform any logic you want within your Listener class. If, for example, you wanted to send an email each time a Job completes, you could program that into the Job. You could also use a JobListener, which enforces a looser coupling and probably makes for a better design.

Quartz Plugins are new functionalities that can be created and added to the framework without having to modify Quartz source. It's done for those developers who need to extend the Quartz framework but don't have time to submit changes to the development team and wait for a new release. If you're familiar with Struts plugins, then you understand the use of Quartz plugins completely.

Rather than Quartz providing a finite set of extension points that may not serve your needs, you have an almost open-ended extension point through the use of Plugins.

Clustering Quartz Applications

Quartz applications can be clustered, both horizontally and vertically, depending on your needs. Clustering offers the same benefits as any other type of clustering:

  • Scalability

  • High Availability

  • Load Balancing

Currently, Quartz supports clustering with help from a relational database and one of the JDBC JobStores. In a future version, this constraint will be lifted and clustering will possible with the RAMJobStore and will not require a database.

The Quartz Web Application

One of the needs of Quartz users that usually manifests after a few weeks or months of using the framework is the need to integrate Quartz into a GUI. There are facilities that currently exist in the framework that allow you to initialize and start Quartz using a Java servlet. Once you have access to the Scheduler instance, you can store it in the ServletContext of the web container and manage the scheduling environment through the Scheduler interface.

Fortunately, some Quartz developers have been working on a stand-alone Quartz Web Application that can be used to better manage the Quartz Scheduler environment. This GUI, built on top of several popular open source projects like Struts and Spring, supports great functionality, all wrapped up in a simple interface. A screenshot of that GUI is shown in Figure 1.


Figure 1. The Quartz Web Application allows easier management of the Quartz environment.

What's down the Road?

Quartz is a project on the move. The development team is definitely not resting on its laurels. Things are already in motion for the next major release of the framework. You can get a taste of the features and design being considered for Quartz 2.0 on OpenSymphony's wiki.

As always, everyday Quartz users are free to add suggestions for features and design ideas so that they can be considered for the core framework.

Finding Out More About Quartz

As you start to use more of the features of the Quartz framework, the User and Developer Forum becomes an extremely useful resource for answering questions and communicating with other Quartz users. The individuals that frequent the forums are always helpful and constructive, and you can also count on James House to share his knowledge and comment on your needs and requirements.

The forum is free and you're not required to have a login to search and view the forum archive. However, once you're comfortable with navigating the forum and need to post a reply to someone, you'll need to sign up for a free account.

Chuck Cavaness is a graduate from Georgia Tech with degrees in computer engineering and computer science. He has built Java-based enterprise systems in the healthcare, banking, and B2B sectors. He is also the author of two O'Reilly books, Programming Jakarta Struts and Jakarta Struts Pocket Reference.

Job Scheduling in Java

by Dejan Bosanac
03/10/2004

On some projects, you find you need to execute certain jobs and tasks at an exactly specified time or at regular time intervals. In this article we will see how Java developers can implement such a requirement using the standard Java Timer API, and then we will focus on Quartz, an open source library for those who need some extra features in their scheduling system.

Let's, for a start, go through few common use cases that will help you recognize situations when you could need this kind of behavior. Then we will see how to find the best solution according to your functional request.

Almost every business application has some reports and statistics that are needed by its users. You can hardly imagine such a system without these reports, because the common purpose for someone to invest in such a system is the ability to collect a large amount of data and see it in a manner that can help with further business planning. A problem that can exist in creating these reports is the large amount of data that needs to be processed, which would generally put a heavy load on the database system. This heavy load decreases overall application performance and affects users that only use the system for data collecting, making it practically useless while it's generating the reports. Also, if we think about being user-friendly, a report that takes ten minutes to generate is not an example of a good response time.

We will now focus on the type of reports that can be cached, meaning those that are not needed in real time. The good news is that most reports fall into this category -- statistics on some product sales in last June, or company income in January. For these cacheable reports, a simple solution is possible: schedule report creation for times when the system is idle, or at least when the load on the database system is minimal. Let's say that you are creating an application for a local book reseller that has many offices (all in the same time zone) and that you need to generate a (possibly large) report for weekly income. You could schedule this task of generating necessary data for a time when the system isn't being used, such as every Sunday at midnight, and cache it in the database. This way, no sale operators will notice any performance problem in your application and company management will have all necessary data in a moment.

A second example that I will mention here is sending all kinds of notifications to application users, such as account expirations. This could be done using date fields in the user's data row, and creating a thread to check users on that condition, but using a scheduler in this case is surely a more elegant solution, and better from the aspect of overall system architecture (and that's important, right?). In a complex system you would have a lot of these notifications, and could find that you need a scheduler-like behavior in many other cases, so building a specific solution for every case makes a system harder to change and maintain. Instead, you should use one API to handle all of your application scheduling. That is the topic of the rest of this article.

In-House Solution

To implement a basic scheduler in your Java application, you don't need any external library. As of J2SE 1.3, Java contains the java.util.Timer and java.util.TimerTask classes that can be used for this purpose. Let's first make a little example that will help us describe all of the possibilities of this API.

package net.nighttale.scheduling;

import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class ReportGenerator extends TimerTask {

public void run() {
System.out.println("Generating report");
//TODO generate report
}

}

class MainApplication {

public static void main(String[] args) {
Timer timer new Timer();
Calendar date = Calendar.getInstance();
date.set(
Calendar.DAY_OF_WEEK,
Calendar.SUNDAY
);
date.set(Calendar.HOUR, 0);
date.set(Calendar.MINUTE, 0);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);
// Schedule to run every Sunday in midnight
timer.schedule(
new ReportGenerator(),
date.getTime(),
1000 * 60 * 60 * 24 * 7
);
}
}

All example code for this article can be downloaded from links at the end of the article.

The code above implements the example from the introduction, scheduling report generation for a time when the system is idle (in this case, Sunday at midnight).

First, we should implement a "worker" class that will actually do the scheduled job. In our example this is ReportGenerator. This class must extend from java.util.TimerTask, which implements java.lang.Runnable. All that you need to do is to override run() method with the report generation code.

Then, we schedule this object's execution using one of the Timer's scheduling methods. In this case, we use the schedule() method that accepts the date of the first execution and the period of subsequent executions in milliseconds (since we repeat this report generation every week).

As we use the scheduling features, we must be aware of the real-time guarantees that the scheduling API provides. Unfortunately, because of the nature of Java and its implementations on various platforms, thread scheduling implementations in various JVMs are inconsistent. Thus, the Timer cannot guarantee that our Task will be executed at exactly the specified moment. Our Tasks are implemented as Runnable objects and are put to sleep (with wait) for some time. Timer then wakes them up at a specified moment, but the exact moment of execution depends on the JVM's scheduling policy and how many threads are currently waiting for the processor. There are two common cases that can cause our tasks to be executed with a delay. First, a large number of threads might be waiting to be executed; second, a delay could be caused by garbage collection activity. All of these influences could be minimized using different techniques (such as running a scheduler within a different JVM or tuning some options for the garbage collector) but that is beyond the topic of this article.

In this new light, we can explain the existence of two different scheduling method groups in the Timer class: scheduling with fixed delay (schedule()) and scheduling with fixed rate (scheduleAtFixedRate()). When you are using methods from the first group, every delay in the task execution will be propagated to the subsequent task executions. In the latter case, all subsequent executions are scheduled according the time of the initial task execution, hopefully minimizing this delay. Which methods you use depends on which parameter is more important in your system.

One more thing is very important to say here: every Timer object starts a thread in the background. This behavior is not desirable in a managed environment, such as a J2EE application server, because these threads are not in the scope of the container.



Beyond the Ordinary

So far, we saw how we can schedule tasks in an application, and for simple requirements that is quite enough. But for more advanced users and complex requirements, a lot more features are needed to support fully useful scheduling. In such cases, there are two common solutions that one could choose. The first is to build your own scheduler with the desired functionality; the second is to locate a project that can fulfill your specific needs. The second solution is more appropriate in most cases, because you can save time and resources and won't have to duplicate someone else's effort.

This brings us to Quartz, an open source job-scheduling system with significant advantages over the simple Timer API.

The first advantage is persistence. If your jobs are "static," as in our introductory example, then maybe you don't need to persist jobs. But we often find tasks need to be "dynamically" triggered when a certain condition is met, and you have to be sure that those tasks won't be lost between system restarts (or crashes). Quartz offers both non-persistent and persistent jobs, in which state is saved in a database, so you can be sure that those jobs won't be lost. Persistent jobs introduce additional performance overhead in the system, so you have to use them pragmatically.

The Timer API also lacks methods to simplify setting the desired execution time. As we saw in the example above, the most you can do is to set a start date and a repeat interval. Surely, everyone who has used the Unix cron tool would like to see similar configuration possibilities within their scheduler. Quartz defines org.quartz.CronTrigger, which lets you set a desired firing date in a flexible manner.

Developers often need one more feature: managing and organizing jobs and tasks by their names. In Quartz, you can get jobs by their names or presence in a group, which can be a real help in environments with a large number of scheduled jobs and triggers.

Now, let's implement our report generation example using Quartz and explain basic features of the library.

package net.nighttale.scheduling;

import org.quartz.*;

public class QuartzReport implements Job {

public void execute(JobExecutionContext cntxt)
throws JobExecutionException {
System.out.println(
"Generating report - " +
cntxt.getJobDetail().getJobDataMap().get("type")
);
//TODO Generate report
}

public static void main(String[] args) {
try {
SchedulerFactory schedFact
new org.quartz.impl.StdSchedulerFactory();
Scheduler sched schedFact.getScheduler();
sched.start();
JobDetail jobDetail
new JobDetail(
"Income Report",
"Report Generation",
QuartzReport.class
);
jobDetail.getJobDataMap().put(
"type",
"FULL"
);

CronTrigger trigger new CronTrigger(
"Income Report",
"Report Generation"
);
trigger.setCronExpression(
"0 0 12 ? * SUN"
);
sched.scheduleJob(jobDetail, trigger);
} catch (Exception e) {
e.printStackTrace();
}
}
}

Quartz defines two basic abstractions, Jobs and Triggers. A Job is the abstraction of the work that should be done, and Trigger represents time when the action should occur.

Job is an interface, so all we have to do is to make our class implement the org.quartz.Job interface (or org.quartz.StatefulJob, as we will see in a moment) and override the execute() method. In the example, we saw how one can pass parameters to the Job through the jobDataMap attribute, which is a modified implementation of java.util.Map. Deciding whether you are going to implement stateful or non-stateful jobs is a matter of deciding whether you want to change these parameters during execution. If you implement Job, all of the parameters are saved at the moment the job is scheduled for the first time, and all changes made later are discarded. If you change the StatefulJob's parameters in the execute() method, this new value will be passed when the job triggers another time. One important implication to consider: StatefulJobs can't be executed concurrently, because the parameters might change during the execution.

There are two basic kinds of Triggers: SimpleTrigger and CronTrigger. SimpleTrigger provides basically the same functionality you get from the Timer API. It should be used if the Job should be triggered once, followed possibly by repeats at a specific interval. You can specify start date, end date, repeat count, and repeat interval for this kind of trigger.

In the example above, we used CronTrigger because of its flexibility to schedule jobs on a more realistic basis. CronTriggers allow us to express schedules such as "every weekday at 7:00 p.m." or "every five minutes on Saturday and Sunday." We will not go further into explaining cron expressions in this article, so you are advised to find all of the details about its possibilities in the class' Javadoc.

In order to run the above example, you'll need a file named quartz.properties in the classpath, with basic Quartz configuration. If you want to use a different name for the file, you should pass it as a parameter to the StdSchedulerFactory constructor. Here is an excerpt of the file with minimal properties:

#
# Configure Main Scheduler Properties
#

org.quartz.scheduler.instanceName = TestScheduler
org.quartz.scheduler.instanceId = one

#
# Configure ThreadPool
#

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 4

#
# Configure JobStore
#

org.quartz.jobStore.misfireThreshold = 5000

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

Another advantage of Quartz versus the standard Timer API is its usage of a thread pool. Quartz uses this thread pool to get threads for job execution. The size you choose for the thread pool affects the number of jobs that can be executed concurrently. If the job needs to be fired and there is no free thread in the pool, it will sleep until a thread becomes available. How many threads to use in the system is a tough decision, and it is best to determine it experimentally. The default value is five, which is quite enough if you are not dealing with thousands of Jobs. There is one thread pool implementation in Quartz itself, but you are not limited on its usage.

Now we come to the JobStores. JobStores keep all the data about Jobs and Triggers. So, this is where we need to decide if we are going to keep our Jobs persistent or not. In the example, we used org.quartz.simpl.RAMJobStore, which means that all of the data will be kept in memory and thus will not be persistent. As a result, if the application crashes, all the data about scheduled Jobs will be lost. In some situations, this is the desired behavior, but when you want to make the data persistent, you should configure your application to use org.quartz.simpl.JDBCJobStoreTX (or org.quartz.simpl.JDBCJobStoreCMP). JDBCJobStoreTX requires some more configuration parameters that will be explained by example.

org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_

#
# Configure Datasources
#

org.quartz.dataSource.myDS.driver = org.postgresql.Driver
org.quartz.dataSource.myDS.URL = jdbc:postgresql:dev
org.quartz.dataSource.myDS.user = dejanb
org.quartz.dataSource.myDS.password =
org.quartz.dataSource.myDS.maxConnections 5

In order to successfully use a relational database with Quartz, first we need to create the tables it needs. You can use any available database server that has an appropriate JDBC driver. In the docs/dbTables folder, you'll find initialization scripts to generate the necessary tables.

After that, we should declare the delegate class that adapts standard SQL queries to the specific RDBMS SQL dialect. In our example, we have chosen PostgreSQL as the database server so the appropriate org.quartz.impl.jdbcjobstore.PostgreSQLDelegate class is submitted. For information what delegate to use with your specific server, you should consult the Quartz documentation.

The tablePrefix parameter defines what prefix is used for Quartz tables in the database (the default is QRTZ_). This way, you can distinguish these tables from the rest of the database.

For every JDBC store, we need to define datasource to be used. This is part of the common JDBC configuration and will not be further explained here.

The beauty of Quartz is that after these configuration changes are made, our report-generation example would persist the data in the database without changing a single line of code.



Advanced Quartz

So far we have described basic Quartz features that can be a good foundation to start using it in your projects. Besides that, this library has great architecture that can fully leverage your effort.

Besides the basics provided by Quartz, the library has a great architecture that will help solve problems in your application. One of its key features is listeners: objects that are called when some event in the system occurs. There are three types of listeners: JobListeners, TriggerListeners, and SchedulerListeners.

Listeners can be particularly useful when you want a notification if something goes wrong in the system. For example, if an error occurs during report generation, an elegant way to notify the development team about it is to make a JobListener that will send an email or SMS.

A JobListener can provide more interesting functionality. Imagine a Job that has to deal with a task that is highly dependent on some system resource availability (such as a network that is not stable enough). In this case, you can make a listener that will re-trigger that job if the resource is not available when the job is executed.

Quartz can also deal with situations when some Trigger has misfired, or didn't fire because the scheduler was down. You can set a misfire instruction by using the setMisfireInstruction() method of the Trigger class. It takes the misfire instruction type for a parameter, which can have one of the following values:

  • Trigger.INSTRUCTION_NOOP: does nothing.
  • Trigger.INSTRUCTION_RE_EXECUTE_JOB: executes the job immediately.
  • Trigger.INSTRUCTION_DELETE_TRIGGER: deletes the misfired trigger.
  • Trigger.INSTRUCTION_SET_TRIGGER_COMPLETE: declares the trigger completed.
  • Trigger.INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE: declares all triggers for that job completed.
  • Trigger.MISFIRE_INSTRUCTION_SMART_POLICY: chooses the best fit misfire instruction for a particular Trigger implementation.

Trigger implementations (such as CronTrigger) can define new types of misfire instructions that can be useful. You should check out the Javadocs for these classes for more information on this topic. Using the TriggerListener, you can gain more control on actions that should be used if a misfire occurs. Also, you can use it to react to trigger events, such as a trigger's firing and completion.

SchedulerListener deals with global system events, such as scheduler shutdown or the addition or removal of jobs and triggers.

Here, we will just demonstrate a simple JobListener for our report generation example. First we have to write a class to implement the JobListener interface.

package net.nighttale.scheduling;

import org.quartz.*;


public class MyJobFailedListener implements JobListener {

public String getName() {
return "FAILED JOB";
}

public void jobToBeExecuted
(JobExecutionContext arg0) {
}


public void jobWasExecuted(
JobExecutionContext context,
JobExecutionException exception) {

if (exception != null) {
System.out.println(
"Report generation error"
);
// TODO notify development team
}
}
}

and then add the following line to the main method of our example:

sched.addGlobalJobListener(new MyJobFailedListener());

By adding this listener to the global list of scheduler job listeners, it will be called for all of the jobs. Of course, there is a way to set listeners only for a particular job. To do this, you should use Scheduler's addJobListeners() method to register the listener with the scheduler. Then add the registered listener to the job's list of listeners with JobDetail's addJobListener() method, with the listener name as a parameter (the value returned from getName() method of the listener).

sched.addJobListener(new MyJobFailedListener());
jobDetail.addJobListener("FAILED JOB");

To test if this listener really works, simply put

throw new JobExecutionException();

in the execute() method of the report generation job. After the job has been executed, the jobWasExecuted() method of our listener is executed, and the thrown exception is passed as the argument. Because the exception is not null in our case, you should expect to see the message "Report generation error" on the screen.

One final note about listeners is that one should be careful about number of listeners that is used in the system, because it could down the performance of the application.

There is one more way you can extend Quartz's features, and that is through plug-ins. Plug-ins can do practically any work you need; all you have to is to write the class implementing the org.quartz.spi.SchedulerPlugin interface. This interface defines two methods that need to be implemented -- one for initialization (which takes a Scheduler object as a parameter) and one for shutdown. Everything else is up to you. In order to make SchedulerFactory use a certain plug-in, all you have to do is to add a line in the properties file (quartz.properties) with the plug-in class and a few optional configuration parameters (which depend on the particular plug-in). There are a few plug-ins already in Quartz itself. One is the shutdownHook, which can be used to cleanly shut down the scheduler in case the JVM terminates. To use this plug-in, just add the following lines in the configuration file:

org.quartz.plugin.shutdownHook.class =
org.quartz.plugins.management.ShutdownHookPlugin
org.quartz.plugin.shutdownHook.cleanShutdown = true



Adaptable in Every Environment

All of the above applies to using Quartz in a standalone application. Now, we will see how we can use its interface in some of the most common environments for Java developer.

RMI

With a distributed application using RMI, Quartz is simple, as we've seen above. The differences are in the configuration.

There are two necessary steps: first we have to set Quartz as an RMI server that will handle our requests, and then we just use it in the standard manner.

The source code of this example is practically the same as in our first example, but here we will divide it in two parts: scheduler initialization and scheduler usage.

package net.nighttale.scheduling.rmi;

import org.quartz.*;

public class QuartzServer {

public static void main(String[] args) {

if(System.getSecurityManager() != null) {
System.setSecurityManager(
new java.rmi.RMISecurityManager()
);
}

try {
SchedulerFactory schedFact =
new org.quartz.impl.StdSchedulerFactory();
Scheduler sched = schedFact.getScheduler();
sched.start();
} catch (SchedulerException se) {
se.printStackTrace();
}
}
}

As you can see, the code for scheduler initialization is standard except that contains a part that sets the security manager. The key is in the configuration file (quartzServer.properties), which now looks like this:

#
# Configure Main Scheduler Properties
#
org.quartz.scheduler.instanceName = Sched1
org.quartz.scheduler.rmi.export = true
org.quartz.scheduler.rmi.registryHost = localhost
org.quartz.scheduler.rmi.registryPort = 1099
org.quartz.scheduler.rmi.createRegistry = true


#
# Configure ThreadPool
#

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 4

#
# Configure JobStore
#

org.quartz.jobStore.misfireThreshold = 5000

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

Notice the highlighted lines, which indicate that this scheduler should export its interface through RMI and provide parameters for running the RMI registry.

We have do a few more things to successfully deploy our server, all of which are typical tasks for exporting objects through RMI. First, we need to start rmiregistry on the server (if it is not already up). This is done by calling:

   rmiregistry &

on Unix systems, or

   start rmiregistry

on Windows platforms.

Next, start the QuartzServer class with the following options (all on one line):

java  -Djava.rmi.server.codebase
file:/home/dejanb/quartz/lib/quartz.jar
-Djava.security.policyrmi.policy
-Dorg.quartz.propertiesquartzServer.properties
net.nighttale.scheduling.rmi.QuartzServer

Now, let's clarify these parameters a little bit. Quartz's Ant build tasks include an rmic call to create the necessary RMI classes, so to point clients to the codebase with these classes, you have to start it with the -Djava.rmi.server.codebase parameter set to file: plus the full path to the location of quartz.jar (of course, this could also be a URL to the library).

An important issue in a distributed system is security; thus, RMI enforces that you use security policy. In this example, we used the basic policy file (rmi.policy) that grants all privileges.

grant {
permission java.security.AllPermission;
};

In practice, you should adapt this policy to your system security needs.

OK, now the Scheduler is ready to accept your Jobs via RMI. Let's write the client that will do that.

package net.nighttale.scheduling.rmi;

import org.quartz.*;
import net.nighttale.scheduling.*;

public class QuartzClient {

public static void main(String[] args) {
try {
SchedulerFactory schedFact =
new org.quartz.impl.StdSchedulerFactory();
Scheduler sched = schedFact.getScheduler();
JobDetail jobDetail = new JobDetail(
"Income Report",
"Report Generation",
QuartzReport.class
);

CronTrigger trigger = new CronTrigger(
"Income Report",
"Report Generation"
);
trigger.setCronExpression(
"0 0 12 ? * SUN"
);
sched.scheduleJob(jobDetail, trigger);
} catch (Exception e) {
e.printStackTrace();
}
}
}

As you can see, the source for the client is literally the same as before. Of course, there are different settings for quartzClient.properties here, too. All you have to do is to specify that this scheduler is the RMI client (proxy) and the location of the registry where it should look for the server.

# Configure Main Scheduler Properties 

org.quartz.scheduler.instanceName = Sched1
org.quartz.scheduler.rmi.proxy = true
org.quartz.scheduler.rmi.registryHost = localhost
org.quartz.scheduler.rmi.registryPort = 1099

No other settings are necessary, because all the work is done on the server side. In fact, if other settings are present, they will be ignored. The important thing is that the names of the schedulers must match in the client and server configurations (Sched1 in this case). And that's all there is, for a start. Just run the client with redirected properties file (again, all on one line):

java -Dorg.quartz.properties
quartzClient.properties
net.nighttale.scheduling.rmi.QuartzClient

and you should expect the same behavior in the server console as in the first example.

Web and Enterprise

If you are developing a web or enterprise solution, one question that may come up is the right place to start the scheduler. For that, Quartz provides org.quartz.ee.servlet.QuartzInitializerServlet. All we need to do is to make the following configuration in the web.xml file:



QuartzInitializer


Quartz Initializer Servlet


org.quartz.ee.servlet.QuartzInitializerServlet


1

If you want to call the EJB method as a Job, you should pass the org.quartz.ee.ejb.EJBInvokerJob class to your JobDetail. To demonstrate this technique, we will implement ReportGenerator as a session bean and call its generateReport() method from the servlet.

package net.nighttale.scheduling.ee;

import java.io.IOException;

import javax.servlet.*;
import net.nighttale.scheduling.Listener;
import org.quartz.*;
import org.quartz.ee.ejb.EJBInvokerJob;
import org.quartz.impl.StdSchedulerFactory;

public class ReportServlet implements Servlet {

public void init(ServletConfig conf)
throws ServletException {
JobDetail jobDetail = new JobDetail(
"Income Report",
"Report Generation",
EJBInvokerJob.class
);
jobDetail.getJobDataMap().put(
"ejb",
"java:comp/env/ejb/Report"
);
jobDetail.getJobDataMap().put(
"method",
"generateReport"
);
Object[] args = new Object[0];
jobDetail.getJobDataMap().put("args", args);

CronTrigger trigger = new CronTrigger(
"Income Report",
"Report Generation"
);
try {
trigger.setCronExpression(
"0 0 12 ? * SUN"
);
Scheduler sched =
StdSchedulerFactory.getDefaultScheduler();
sched.addGlobalJobListener(new Listener());
sched.scheduleJob(jobDetail, trigger);
System.out.println(
trigger.getNextFireTime()
);
} catch (Exception e) {
e.printStackTrace();
}
}

public ServletConfig getServletConfig() {
return null;
}

public void service(ServletRequest request,
ServletResponse response)
throws ServletException, IOException {
}

public String getServletInfo() {
return null;
}

public void destroy() {
}
}

As you can see, there are three parameters that needs to be passed to the job.

  • ejb: The JNDI name of the enterprise bean.
  • method: The actual method to be called.
  • args: An array of objects to be passed as a method arguments.

Everything else remains the same from the Quartz usage perspective. I have put this example in the servlet initialization method for simplicity, but of course, it could be done from any convenient place in your application. In order to successfully run such a job you'll need to register this EJB with your web application. This is usually done by putting the following lines in the web.xml file.


ejb/Report
Session
net.nighttale.scheduling.ee.ReportHome
net.nighttale.scheduling.ee.Report
ReportEJB

Some application servers (such as Orion) need to be instructed to allow creation of user threads, and thus would need to be started with the -userThread switch.

These are by no means all the enterprise features of Quartz, but it's a good start and you should look at Quartz's Javadocs for further questions.

Web Services

Quartz currently has no built-in support for being used as a web service, but you can find a plug-in that enables you to export the Scheduler interface through XML-RPC. Building an installation procedure is simple. To start, you have to extract the plug-in source into the Quartz source folder and rebuild it. Plug-ins rely on the Jakarta XML-RPC library, so you have to be sure that it is in the classpath. Next, add the following lines in the properties file.

org.quartz.plugin.xmlrpc.class = org.quartz.plugins.xmlrpc.XmlRpcPlugin
org.quartz.plugin.xmlrpc.port = 8080

Now the Scheduler is ready to be used through XML-RPC. This way you can use some of the Quartz features from different languages such as PHP or Perl, or in a distributed environment where RMI might not be the right solution.

Summary

We've looked at two ways to do scheduling in Java. Quartz is indeed a powerful library, but for simple requirements the Timer API can save the day, keeping you from putting unnecessary complexity into the system. You should think of using the Timer API in cases where you don't have a lot of tasks that need to be scheduled, and when their execution times are well-known (and unchangeable) in the design process. In these situations, you don't have to worry whether some tasks are lost because of a shutdown or crash. For more sophisticated needs, Quartz is an elegant scheduling solution. Of course, you can always make your own framework, based on the Timer, but why to bother when all that (and much more) already exist?

One event worth noting is IBM and BEA's submission of JSR 236 titled "Timer for Application Servers". This specification is focused on creating an API for timers in managed environments where using the standard API is insufficient. You can find more details about the specification on IBM's developerWorks site, and the specification should be available for public review in spring.

Sample Code

ReportGenerator.zip

Dejan Bosanac is a software developer, technology consultant and author. He is focused on the integration and interoperability of different technologies, especially the ones related to Java and the Web.