Overview
Great software requires a fanatical devotion to beauty.
- Paul Graham
The important things about WEB4J are:
In the interest of not wasting your time, we also include a listing of its drawbacks.
If you can accept the above, then WEB4J is often the best tool for the job of creating browser
interfaces to databases. Because of its deep simplicity, it allows markedly faster delivery of applications.
WEB4J Has a Clear Philosophy
WEB4J stands aggressively for the following:
- simplicity and minimalism
- concision
- reducing the pain of programming in Java
- showing compassion for the typical programmer just wanting to get their work done
- using tools that have been proven over a long period of time
- treating the data as king, not the code
WEB4J stands aggressively against the following :
- complexity
- verbosity
- requiring the programmer to be an uber-geek
- using fashionable-but-unproven programming techniques
- assuming the programmer has a lot of time available to learn new tools
- treating the database as secondary to the code
- forcing the programmer to learn new ways to do the same old thing
WEB4J is Small
One measure of complexity is size. Here is a listing of the number of
documented classes in various tools :
Name | Num Classes | Relative Size |
WEB4J | 95 | |
Servlet/JSP API | 133 | |
Rails | 674 | |
Struts | 704 | |
Tapestry | 1,091 | |
Rife | 1,154 | |
JEE | 1,188 | |
Spring | 2,312 | |
As you can see, most tools have a size that might be described as "rather large".
Note that WEB4J has the smallest surface area of any tool in its class.
It's 14% of the size of Ruby on Rails, which is widely lauded for its ease of use.
Correspondingly, it takes a shorter time to learn WEB4J, and to implement features with it.
Not only is WEB4J compact, but, more importantly, applications built with WEB4J are compact as well.
Here are some typical line counts per feature, taken from a cross section of several features in one of the example applications.
(Documentation comments are included in the line counts.)
Item | Avg Lines | Relative Size |
SQL file (.sql) | 25 | |
Presentation (.jsp) | 108 | |
Total | 133 | |
Model (.java) | 111 | |
Action (.java) | 144 | |
DAO (.java) | 46 | |
Total | 301 | |
In general, your code will only be roughly twice the size of the non-code elements of your application.
(DAOs are often short and simple, consisting only of a few single-line methods.
In such cases, it's recommended that those methods be moved into the Action class.)
WEB4J Requires A Minimal Toolset
You use the following tools when building a WEB4J application:
- HTML and CSS (javascript not required)
- JSP 2.0+ and JSTL 1.1+
- some custom tags defined by web4j. These custom tags are minimal, and
do not interfere with regular HTML. In particular, your forms still use plain HTML.
- web4j.jar, JDK 1.6+, and Servlets 2.4+
- standard SQL statements, placed in .sql text files (no database mapping of any kind)
In short, you use existing, well known tools appropriate for each layer.
In addition, there are no other dependencies on third-party tools, other than widely used items
published by Oracle.
WEB4J Uses Convention Over Configuration
Convention over configuration is used to reduce the effort needed to create and maintain your application.
It's used in the following ways:
- a default naming convention maps request URIs to corresponding Actions.
See RequestParserImpl.
- in JSPs, a naming convention for the names of input controls allows for automatic mapping between controls and corresponding getXXX
methods of a Model Object. This convention allows painless population of forms with data. See RequestParameter.
- an ordering convention for the columns of a ResultSet is used to map columns to
corresponding parameters in a Model Object constructor. This allows painless construction of Model Objects out of ResultSets.
See the overview of the database package.
- an ordering convention is used for SQL statements with ? parameters: when your DAO passes values for such parameters
to the framework, the order of the passed parameters matches the order of the ? items appearing in the underlying SQL statement. See
Db.
- where possible, default implementations of required interfaces can be used with no effort on the part of the application programmer.
If there's no default implementation, or if the default implementation is overridden, then a naming convention for the package/class can be used. See BuildImpl.
- the set of acceptable RequestParameters for each Action
are found automatically by the framework upon startup, with no configuration required.
See ApplicationFirewallImpl.
WEB4J Application Classes Are Usually Simple
The quality of a framework can be measured by examining the
concrete classes which use it. Questions to ask of a such a class include:
- is it fairly simple and compact?
- does it read at a high level of abstraction?
- does it read clearly?
WEB4J performs well in this regard. Here are some examples of typical implementations:
Model Objects:
Data Access Objects (DAOs):
Actions:
WEB4J Has Nice Building Block Classes
Your application's model objects are built out of simpler classes such as Integer, BigDecimal, and so on, which WEB4J refers to as building block classes.
The framework supplies building block classes appropriate to most web apps.
Included among these are several custom building block classes designed to make your life easier:
- SafeText is the recommended replacement for String, since it protects you from Cross-Site Scripting (XSS) attacks.
- Decimal is the recommended replacement for BigDecimal, since it's simpler to calculate with.
It also corresponds nicely to the DECIMAL data type used in databases.
Decimal can be used for monetary amounts.
- Id is specifically for identifiers, and helps them stand out more clearly in your code.
- DateTime
is recommended for dates and times. Although you can still use java.util.Date if desired,
WEB4J recommends DateTime as a replacement.
The other building block classes are simply taken from the JDK:
- String
- BigDecimal
- Date
- Locale
- TimeZone
- Integer and int
- Long and long
- Boolean and boolean
WEB4J Enables Package-By-Feature
The package-by-feature technique is a powerful
method for organizing your code. It has many advantages, and is superior to the package-by-layer style
so often promoted by other tools.
All items related to a single feature can usually be isolated in their own directory/package - Action,
Model Object, DAO, plain text SQL statements, and even the JSP.
This gathering together of all items related to a single feature (and only that feature) is extremely satisfying.
It allows the following goodness:
- say goodbye to tedious navigation from directory to directory to change closely related items - everything is in one place
- it often allows the deletion of unwanted features simply by deleting a single directory
- it allows some items to reduce scope from public to package-private. (Minimizing scope
is a central idea of lasting value in programming, and should always be aggressively pursued.)
- in many source-code control environments, it allows developers to see immediately if another developer
has checked out an item related to their current work
WEB4J Forms Use Plain HTML
Forms are an important part of web applications.
Most frameworks implement forms with a large set of custom tags, that are different for each framework.
These are meant to replace the existing, well known HTML controls such as <INPUT>,
<SELECT>, and so on. That style is suctorial, since it forces you to learn a
new set of tools to do something you already know how to do - build an HTML form. This is neither necessary
nor desirable.
In WEBJ, the typical form looks like this:
<form action='MemberEdit.do' method="post">
<w:populate using="member">
<input name="Id" type="hidden">
<table align="center">
<tr>
<td><label>Name</label> *</td>
<td><input name="Name" type="text"></td>
</tr>
<tr>
<td><label>Is Active?</label></td>
<td><input name="IsActive" type="checkbox" value="true"></td>
</tr>
<tr>
<td align="center" colspan=2>
<input type="submit" value="Add/Edit">
</td>
</tr>
</table>
</w:populate>
</form>
The population of the form is done by wrapping a normal HTML form with a single <w:populate> tag - that's it.
There are no custom tags for the various kinds of form controls.
The WEB4J mechanism is the simplest possible way of populating forms.
WEB4J Has No Custom XML Files
The only XML file required by WEB4J is the deployment descriptor, web.xml.
Whereas many other tools force you to spend significant time coding in XML, WEB4J was explicitly designed to let you avoid it.
In a WEB4J app, you implement features using JSPs, Java, and text files containing SQL statements. That's it.
If you are looking for "XML hell", you won't find it here.
WEB4J Doesn't Use Object Relational Mapping
When building DAOs, you may use either WEB4J's data layer, or any other persistence tool of your choice.
By design, WEB4J's data layer doesn't use object-relational mapping (ORM).
For the majority of cases, implementing a DAO method with WEB4J's data layer will be more compact than an ORM implementation.
The minority case in which an ORM tool may result in less coding effort and increased elegance is that of building an extensive object graph.
However, building an extensive object graph is the exception, not the rule.
The majority of pages in a typical application relate not to relatively complex views of data, but to relatively simple ones.
The reason for this is that it matches how people think, and how they work - on one specific thing at a time.
Yes, large summary pages are very often part of an application, but such pages are usually the exception, not the rule.
There are some serious drawbacks to object-relational mapping:
- it replaces standard, well known SQL with alternate query mechanisms implemented in code (reinventing the wheel).
- it makes it difficult to debug and tune SQL, since the SQL is generated behind the scenes.
- it often forces you to code in XML, which is inherently more difficult to work with.
- its details are clearly non-trivial to learn and use.
- it's often tedious and verbose.
- it destroys the clear separation between application layer and data layer.
- it violates encapsulation of database secrets, since the application layer repeats information that's usually hidden in the database: column types, nullity, key information, and so on.
(SQL statements never explicitly include such information.)
- ORM tools need to be ported to each new database vendor/version, while tools based on SQL don't have this problem.
In addition, ORM tools are sometimes invasive, in the sense of restricting the implementation of your Model Objects in certain ways, such as:
- perhaps requiring you to add a no-argument constructor
- perhaps requiring your class to be non-final
- perhaps requiring you to add setXXX methods (roughly doubling the number of methods)
- perhaps requiring you to add annotations
- perhaps requiring you to implement Serializable (doing this correctly is non-trivial)
These restrictions don't exist for the benefit of your Model Object.
Rather, they exist because the implementation of the ORM tool needs them in order to function.
That is, they represent "leaks" of the ORM tool into your data model.
These restrictions are particularly annoying since they may not allow you to design your own classes as immutable objects.
This is a serious defect since immutable objects have so many compelling benefits.
If you choose to use WEB4J's data layer, then these restrictions don't exist.
The only restriction for WEB4J Model Objects is that the constructor must throw a ModelCtorException,
and that restriction has nothing to do with persistence.
Rather, it's related to an important problem each Model Object should solve: the problem of validating state, and communicating related errors to the caller.
WEB4J Uses Plain .sql Text Files
The WEB4J data layer uses regular SQL statements, stored in ordinary .sql text files.
Here is an example showing the basic idea.
This style has many benefits.
WEB4J Has Minimal Configuration
WEB4J has no .xml configuration files, other than the familiar web.xml file (used for
a number of initialization settings). In addition, it requires the application programmer to
supply concrete implementations for several interfaces. Default implementations are
supplied for most of these items (no reasonable defaults are possible for the others).
See BuildImpl for details.
WEB4J Doesn't Impose Thread-Safety Constraints
Some tools force some application classes to be thread-safe. In Struts 1, for example, Action classes must be
thread-safe. Forcing such a requirement on an application programmer is inappropriate:
- implementing thread-safety is not trivial, especially for novice programmers
- even if the programmer is experienced with the issue of thread-safety, it's still dangerously easy
to simply forget to enforce it. Thus, there is the continual danger of introducing thread-related bugs.
WEB4J makes no requirements of thread-safety on the application programmer.
WEB4J Simplifies Multilingual Apps
WEB4J translation tools allow the implementation of a multilingual application to look almost the same
as that of an ordinary single language application. All Actions, Model Objects, and DAOs are
exactly the same in both cases.
The only differences are in JSPs - and even there, the differences are relatively minor.
The markup retains the overall look of a single language application.
It remains legible, and appears natural to the eye.
This is because the WEB4J translation tags are designed explicitly to be non-invasive. For example,
- translation of large chunks of markup can be often be implemented by wrapping the 'single language'
markup in a TextFlow tag
- translation of all tool tips (TITLE attributes) can be done by placing a single
Tooltips tag in a template JSP
WEB4J Allows Applications To Assist In Their Own Translation
The WEB4J translation mechanism can be backed by a database (recommended), or by
any other means, including properties files.
If a database is used to store translations, then applications can assist in their own translation.
The general idea is that, during development, all user interface items needing translation can be collected simply by exercising the application.
This is done with a Translator implementation that records items having missing translations.
Translations for such items can then be added later, through the browser, using screens created for that purpose, just like any other data.
(Please see the WEB4J Fish & Chips Club example app for further illustration of this useful technique.)
WEB4J Protects You From Common Hacks
WEB4J has tools to protect you from common hacks:
- SafeText
models free-form user input, and automatically escapes special HTML characters
(by default). This protects you against XSS attacks.
It also allows you to forget about repeatedly escaping special characters in the view.
By default, String cannot be used to model free-from user input.
If you need to allow String as a "building block" class, then you must explicit permit it using a setting in web.xml.
- CsrfFilter protects you against
CSRF attacks.
- ApplicationFirewallImpl
checks that all incoming parameters have known names, and that their values satisfy basic sanity checks.
- SQL Injection attacks are very unlikely
when using the WEB4J data layer.
When using an SQL statement defined in an .sql file, such attacks are impossible.
(When creating dynamic SQL in code, however, you must be careful to use the PreparedStatement
mechanism correctly, and parameterize all user input.)
- UntrustedProxyForUserId and
FetchIdentifierOwner cooperate to
help you avoid Insecure Direct Object Reference problems.
- SpamDetector
helps you prevent spam from entering your database.
WEB4J Has Example Applications
WEB4J has 3 example applications, of varying size:
- a minimal tutorial application, which gives you a brief overview of the tool.
- an intermediate-sized example application called Predictions, built
in the style of many public web applications, with access control based on user, not on role.
- a full-sized example application called Fish & Chips Club, built in the
style of many intranet applications, with access control based on role. This application exercises almost
all of the WEB4J API, and could be considered an informal "reference implementation".
The example applications are provided as both a starting point and as a guide. It's recommended,
though not required, that your applications be created by starting with an example app, and changing
it gradually. If any items are undesired, then they can usually be removed simply removed by deleting directories (and any links from
menus). This is only possible because of the package-by-feature style recommended by WEB4J.
(See the User Guide for more information.)
This approach is consistent with the following:
- destroying things is easiest of all
- next, changing something that already exists is usually easier than starting with nothing
- finally, starting with nothing usually takes the most time
In any case, the classes in the example applications are always effective guides.
Other WEB4J Features
- action classes are usually automatically mapped to URIs, without any manual configuration (see RequestParserImpl)
- several abstract base classes are provided as templates for common action classes (see the subclasses of ActionImpl)
- Report helps you build reports quickly
- ModelUtil helps you implement equals, hashCode, toString, and compareTo in your Model Objects
- Check and
Validator implement many common validations, and can be extended with validations particular to your application
- ModelFromRequest and Db allow rapid
creation of Model Objects from incoming requests and ResultSets, respectively.
- messages to the user can survive a redirect, allowing the application to inform the user of successful edits to the database
- settings in web.xml are used to establish application-wide default formats for dates and currencies
- the Db class is the main tool for implementing DAO methods
- applications can easily use multiple databases, when required
- upon startup, WEB4J can optionally perform a test precompilation of all SQL statements. This is
highly beneficial since it detects errors at startup-time instead of at run-time.
(Not supported by all database drivers.)
- if a database is down when the container starts, your app will attempt to recover with each
incoming request. As soon as the database is up, any related start-up tasks for that database will be executed,
and your web app will start functioning normally.
- the webmaster is emailed if an error occurs, or if your application's response
time exceeds a configured number of seconds. In the case of an error, the
email includes extensive diagnostic information, including a stack trace
- upon startup, WEB4J will scan your Model Objects for possible Cross-Site Scripting vulnerabilities
- and other features as well...