WEB4J Version History
web4j.jar version 4.10.0 (Published October 19, 2013)
This release is not backwards-compatible.
The most important changes are the use of JDK 1.6, and
the ability to easily use the web4j data layer in any app, outside of a servlet context.
JDK changed from 1.5 to 1.6
Version 4.10.0 is the first version to be compiled versus JDK 1.6.
At the moment, JDK 6 is nearly 7 years old. This change was prompted in part by the change which lets
InputStream be treated as a building block class (see below).
ServletConfig replaced with Map
This is, in part, to allow more ease of use outside of a servlet context. It also improves the design,
since it relies on a simple, universal data structure, and not on the presence of a servlet context.
These interface methods now take a Map instead of ServletConfig:
- ConnectionSource.init(Map)
- LoggingConfig.setup(Map)
- BuildImpl.init(Map) (not an interface, but closely related)
In the context of a web app, the Map (created and passed by the framework) simply includes all
of the init-param settings in web.xml.
Existing custom implementations of these methods will need to change.
Such changes will be minor, as long as existing code uses ServletContext to simply access config data,
and nothing else (which is expected to be the case).
TroubleTicket
Method name corrected from mailToWebmaster to the more accurate mailToRecipients.
Warning added to javadoc about possible problems with spam filters.
AppException
AppException now extends Exception, and not ServletException.
This will break any calls to the AppException.getRootCause method (which was inherited from ServletException).
This lets the class be independent of the servlet context.
When the Controller needs to throw an AppException, it now wraps it in a ServletException.
The remaining items below are backwards-compatible.
Using the database layer outside of a servlet context
Previously, the design of the web4j database layer relied on the presence of
javax.servlet. This was an embarrassing design error which has finally been corrected.
For more information, please see the User Guide.
Various init methods
Some classes have init methods which are called only by the framework.
As part of an internal re-design of how config data is processed, the following
classes have had their init methods removed, since they now have access to config data in an
improved style:
- EmailerImpl
- ConvertParamImpl
- UntrustedProxyForUserIdImpl
- RequestParameter
- Formats
- RequestParser
(Any init methods which do more than simply access config data have remained in place.)
Initialization changes
- Db.initStandalone - added, for using the database layer outside of a servlet context. Web apps don't call this method.
- BuildImpl.initDatabaseLayer - added, for using the database layer outside of a servlet context. Web apps don't call this method.
- ApplicationFirewallImpl.init - the ServletConfig param has been removed from this method; called only by the framework.
- RequestParserImpl.initWebActionMappings - the ServletConfig param has been removed from this method; called only by the framework.
InputStream has been added to the set of building block classes
- ConvertParamImpl - updated to include InputStream
- ConvertColumnImpl - updated to include InputStream
When passing an InputStream to the database, web4j uses (in the package-private SqlStatement class):
PreparedStatement.setBinaryStream(int, InputStream)
This is a JDBC method from JDK 1.6. It may not be supported by older database drivers. You may need to update
older drivers.
For example code which saves and fetches an InputStream with a relational database, see the
file upload
feature of the Fish & Chips Club example app.
Minor nuisance: in Servlet 2.5 there's no simple way to access the uploaded file as an InputStream, so
web4j isn't currently able to translate a RequestParameter into an InputStream. This will be amended
when web4j moves to Servlet 3.0 as its base. When you build a Model Object from an incoming request,
you will simply need to first get an InputStream, and then pass it to ModelFromRequest explicitly,
instead of passing a RequestParameter object as a proxy for the InputStream.
Use of sun.util.calendar.ZoneInfo
The silly import of this unpublished class in ConvertParamImpl has been removed.
The implementations of both ConvertParamImpl and ConvertParamErrorImpl have changed to
use Class.isAssignableFrom(), instead of an identity comparison with the (abstract) TimeZone class.
Util.logOnePerLine(Map,?> aMap)
In addition to suppressing values for items whose name contains 'password', this method will now
also suppress values for items whose name contains the text 'credential'.
web4j.jar version 4.9.0 (Published October 5, 2013)
This release is not backwards-compatible.
DynamicCriteria
[Mark Rostron, Thomas Hallgren].
This class has changed its name to DynamicSql.
Its javadoc has been clarified to note that it can be used to create not just WHERE and ORDER BY clauses,
but complete SQL statements as well. This is an annoying change - sorry about that.
In addition, the previous version attempted to perform an extra level of validation, by trying to detect
if the SQL was properly parameterized. That code was mediocre, and has been removed.
Indeed the whole idea seems to suffer from the fact that it doesn't seem possible to implement it
100% correctly.
Reference: link.
The DynamicSql class can be subclassed, if you wish to add that style of validation yourself.
StartupTasks
The single method in this interface now takes a second parameter,
the name of a database. The database names are passed in by the framework, and are the
exact same names as those already defined by your implementation of the ConnectionSource interface.
It's important to note that your implementation of StartupTasks will now be called multiple times, not just once:
- first with an empty String for the database name; this is intended for any tasks that
aren't attached to any database at all.
- once for each database name; this is called only when the database has been detected as being 'up', so you don't
have to worry about detecting such problems.
You will have to review your implementation of this interface to ensure it's compatible with the new semantics.
In almost all cases, the adjustments will be simple. As usual, you can use the example apps as guides.
Implementations should typically have this form:
public void startApplication(ServletConfig aConfig, String aDbName) throws DAOException {
if (!Util.textHasContent(aDbName)){
//tasks not related to any db
}
else if (ConnectionSrc.DEFAULT.equals(aDbName)){
//tasks related to this db
}
else if (ConnectionSrc.TRANSLATION.equals(aDbName)){
//tasks related to this db
}
}
Databases down at startup
[Thomas Hallgren]. The reason for the above change is that the Controller logic during startup has changed slightly regarding databases.
If a database is found to be down upon startup, the app will continue, and later attempt, with each incoming request, to
connect/startup the remaining 'bad' databases.
An example of how this can be useful is a translation database: if it happens to be down upon
startup, the app should still proceed, but in a degraded form without translations.
Decimal
The policy regarding internal rounding has been removed.
It was felt that the existing design was poor with respect to rounding. When performing a calculation,
rounding should be performed at the end of the calculation, and not at each intermediate step.
With the new version of this class, callers must round explicitly at the end of a calculation, if needed.
These methods related to rounding have been removed:
- init
- changeTimesDivDecimals
- getRoundingStyle
- getTimesDivDecimals
- getTimesDivDecimalsDefault
Warning: this change is trickier than most, since it affects the data returned by the API.
Apps that use Decimal for rounded amounts will need to review and test their use of this class.
The DecimalStyle setting in web.xml was related to the internal rounding. It can be
removed from your web.xml files. (Leaving it in will not do any harm.)
These methods (not related to rounding) have been added:
As well, a number of new overloads of existing methods have been added, as well as some new constants.
Stopwatch
The toString method now returns a
value to microsecond resolution (instead of milliseconds).
Example return value : '108.236 ms'.
It goes to microseconds (and not nanoseconds) to reflect the real resolution of most systems.
The toValue method now returns a value in nanoseconds, not millis; this will break most callers of this method.
DateTime
The plus and minus methods now take nanoseconds.
Existing callers can simply add a new 0-valued parameter at the end of the argument list.
Three new methods have been added: isParseable, forInstantNanos, and getNanosecondsInstant.
DateTime is now synchronized with the current revision of date4j (1.5).
The remaining items below are backwards-compatible.
ModelUtil
[Jared Thomas, Thomas Hallgren.] Javadoc clarified: self-referential arrays are not supported. The
areEqual(Object, Object) method now supports arrays.
ActionImpl
Added a field called DATA, to act as a
convenience key when adding
structured data to request scope (intended for JSON, XML, and so on).
As well, the User Guide has been updated with a new section for serving structured data.
Controller
Formerly, the Controller handled only GET and POST methods
The PUT and DELETE methods have been added as well, since those methods can be used by
XmlHttpRequest.
ShowForRole
[Thomas Hallgren.] This tag has been updated to accept a third attribute, isLoggedIn.
This lets you hide the display of the tag's body, simply according to whether the user has logged in or not.
Controller
[Angus Lee.]
NPE line 635 in the Controller class.
Logging value of app-scope item named 'com.sun.jsp.taglibrarycache', when using Jetty 9.
Relates to Util.quote(). Web4j wasn't at fault, but I have coded it defensively in case it happens in some other tool again.
web4j.jar version 4.8.0 (Published June 9, 2012)
Added support for some HTML5 form controls. This release is backwards-compatible.
HTML5 Input Controls
Support has been added for seven HTML5 form INPUT controls with these values for the type attribute:
- search
- email
- url
- tel
- number
- range
- color
The <w:populate> tag now understands such controls.
Not all browsers support these controls. For up to date information on browser support, please see html5test.com.
For an example of using these controls, please see the exercise module in the latest version of the Fish and Chips Club
example application.
Beware of the color and range controls.
The current draft version of the HTML5 specification (rather disturbingly) insists that such controls must always submit a
non-empty value when the form is submitted.
This means that it's not possible for such controls to cleanly model null-able columns in your database.
If you use such controls with null-able data, you will need to add extra logic - perhaps using magic values to take the place of null.
If the browser doesn't support the color control, then the user may see a color value in its raw hex form in an ordinary text
control, as in '#aa1133'.
Support for the new HTML5 date/time controls has not been added in this release.
Most current browsers don't support them.
Worse, when a browser doesn't support these controls, then problems ensue with prepopulating the control.
The problems center on the fact that the
value attribute has completely different syntax and behaviour between the new date/time controls and regular text controls.
This makes it very hard to properly control the value seen by the end user in a reasonable way, in cases where the browser may or
may not actually support that kind of control.
For the moment, support for the new date/time controls is being left out.
DateTime
The DateTime constructor which takes a single String now accepts Strings having either a 'T' separating
the date from the time, or a single space.
(Formerly, only the single space was accepted as the separator.)
The DateTime constructor now matches the ISO 8601 standard.
Note that the standard allows either a 'T' or a single space to separate the date from the time.
Both are acceptable.
This also matches what is allowed by the draft HTML5 specification for forms that submit a value for
input controls of type datetime-local and datetime.
WebUtil.getFileExtension
A bad bug has been fixed for the WebUtil.getFileExtension(String) method.
Its attempt to find the dot character should have used String.lastIndexOf instead of String.indexOf.
Its JUnit test case has also been updated.
ResponsePage
The templating mechanism used in the example applications has been moved into the core.
This is implemented simply by adding a new constructor, ResponsePage(String, String, Class).
This allows the removal of a helper class named TemplatedPage from the example applications. If you used such a helper
class in your applications, you can now remove it as well, if desired.
Postgres Database
A note has been added to the User Guide regarding postgres.
When postgres is used with web4j's data layer, you need to add this connection parameter:
stringtype="unspecified"
Populate Tag
In the example applications, instances of the <w:populate> tag have been altered to ensure
that the start and end of the tag are placed symmetrically around the tag's content. For example, the end tag
will no longer cut a table into two parts. (This is not a code change, merely a change in how the tag was being used in the example apps.)
web4j.jar version 4.7.2 (Published May 14, 2012)
Small release, fairly minor issues.
PermittedCharactersImpl
This is the default implementation of an interface. It was too restrictive. For example, it was disallowing U+00B4.
The new implementation only calls
Character.isValidCodePoint.
This change is not backwards-compatible.
ApplicationInfo
ApplicationInfo.getBuildDate() now returns a DateTime, not a java.util.Date.
This change is not backwards-compatible.
Form Population
[Thomas Hallgren]. For OPTION tags, special characters (for regular expressions) were not being escaped properly.
Link.
Text.java
Text.java was throwing an exception when the tag's body was empty and no text attribute was specified.
This should have been allowed in the first place.
Text.java was using greedy regular expressions, which should have been reluctant, in order to match
against the smallest data, not the largest.
ModelCtorUtil
[Thomas Hallgren]. The private vomit method should have passed along the underlying cause.
Link.
Controller Logging
The Controller now logs ApplicationInfo.toString() at the end of startup, so you can see the name and version of
the app which has just started.
web4j.jar version 4.7.1 (Published September 24, 2011)
One minor bug fix.
DateTime
The DateTime.toString() method (and its corresponding unit test)
should've been corrected in 4.7.0 to return a more natural result, but it wasn't. Sorry about that.
web4j.jar version 4.7.0 (Published September 17, 2011)
Small release, with relatively minor issues.
EmailerImpl
EmailerImpl can no longer be configured to send emails in a separate thread.
This is a conservative policy, more appropriate to the core library.
An application creating threads while running in a Servlet Container can lead to problems.
For example, on Tomcat, any user threads created by an application will cause Tomcat
to be unable to shutdown in the regular way.
In web.xml, the corresponding setting named EmailInSeparateThread has been removed from the
example applications.
PerformanceMonitor
The option of configuring a BadResponseDetector has been removed.
This tool was using worker threads. For the same reasons as stated above for EmailerImpl,
it's not a good idea for a web app to spawn threads inside a Servlet Container.
In addition, using an app to monitor itself is not robust, since it cannot detect all failures.
In web.xml, the corresponding setting named BadResponseDetector has been removed from the
example applications.
TroubleTicket
TroubleTicket now includes basic information on current memory use.
If available memory is low at a given instant, this doesn't necessarily mean that low memory
is a problem. Low memory is a problem only if subsequent garbage collection doesn't free up significant memory.
DateTime
The DateTime class has been updated, to remain synchronized
with the version published on date4j.net.
The toString method now returns a more natural result.
The format() methods have changed implementation.
The style 'YYYYMMDD', for example, is now permitted. (This corrects an oversight.)
In addition, the text that can be passed to the format methods can now take a much wider range of values.
For example, a valid format String is:
'Now: YYYY-MM-DD hh:mm:ss'
This text acts like a little template. The preamble 'Now :' is simply echoed, since it contains no formatting symbols.
Such free-form text will often need pairs of escape characters '|', to prevent h, m, s, a, f, and so on from being interpreted
as formatting symbols. For example :
'|The date is:| YYYY-MM-DD'
DateTime.isValidFormatString(String)
This method has been removed. Since the String passed to the format() methods has no restrictions, such a
method no longer makes sense.
MessageList
Two related methods have been removed from this interface (and corresponding implementations)
- getMessagesForSingleDisplay
- getIsDisplayable
These methods were used to suppress the display of session-scope messages in JSPs.
Formerly, the messages stayed in session scope after being displayed, and a boolean flag was used to
signal the fact that they shouldn't be displayed a second time.
That mechanism has been abandoned in favour of something simpler - just deleting the session-scope
messages after they have been displayed. The deletion from session scope takes place in the JSP,
immediately after showing the messages. The displayMessages.tag file in the example applications
has been updated to reflect the new style of removing the messages after they've been displayed.
web4j.jar version 4.6.2 (Published July 9, 2011)
This is a bug-fix release, for a single important bug.
Tomcat has changed its return value for
HttpServletRequest.getRequestURI()
with respect to jsessionid.
As a result, this was breaking WebUtil.getFileExtension(String). That method is used
to determine the operation associated with a request (.do, .show, and so on).
web4j.jar version 4.6.1 (Published May 15, 2011)
This is a bug-fix release, for a single important bug.
The web4j data layer was not always closing connections correctly during SELECT statements.
In some cases, when SELECT statements had unusual failures, a branch of code was not calling close() on database connections.
This means that such connections would not be returned to the connection pool.
As a result, the connection pool could become exhausted if :
- your connection pool isn't configured for resuscitating dead connections
- N SELECT statement failures occur, where N = the maximum size of your connection pool
If the above occurs, then it's a serious problem.
If the connection pool becomes exhausted, then your app will no longer function: no further HTTP requests would be
able to get a database connection. In other words, your app would completely hang.
web4j.jar version 4.6.0 (Published March 1, 2011)
LoginTasks
The LoginTasks interface has been added.
Implementations of this interface instruct the web4j Controller how to react when a successful user login is detected.
The Servlet API already has hooks for the creation of a session, but not for a successful login.
Many existing apps will already implement the same idea, usually with a Servlet Filter.
Those apps have the choice of sticking with their existing code, or migrating to this new interface.
If you choose to use this new interface, then you will likely need to:
- build a (non-trivial) implementation of LoginTasks; usually, you can simply steal code from your existing Servlet Filter
- remove your existing Servlet Filter
If you choose not to migrate to this new interface, then you will still need to supply a (trivial) implementation of LoginTasks, which
performs a no-operation.
As usual, please see the (updated) web4j example apps for working illustrations.
EmailerImpl Has Been Improved
The default implementation of the Emailer interface (EmailerImpl) has been improved.
It now allows you to log in to the SMTP server, and to pass name-value pairs to configure the java mail mechanism.
It uses two new settings in web.xml:
- MailServerConfig - the name=value pairs to be passed to the javax.mail mechanism (mail.host and so on)
- MailServerCredentials - the user name and password for the SMTP server (separated by a pipe character '|')
The old setting named MailServer is now obsolete, and should be removed from existing applications.
Bug Fixes
Bug fixes included in this release:
- SafeText no longer throws an exception when deserialized.
It was attempting to check for invalid characters, but the implementation of PermittedCharacters was not yet set.
- the mail server parameters have been moved from ServletContext (web app) to ServletConfig (Controller), where they should be.
Please see the note above regarding new settings for EmailerImpl.
web4j.jar version 4.5.1 (Published January 29, 2011)
This is a bug-fix release.
- Fix an encoding issue with CsrfFilter, whereby the response encoding was being incorrectly coerced to 8859-1. (That was a bad bug; sorry about that.)
- ApplicationFirewallImpl.checkParamValues() now also logs the size of the raw text (but not its value).
- DateTime.numSecondsFrom(DateTime) - its javadoc incorrectly stated that the number of milliseconds is returned.
It's really the number of seconds.
- the example apps have been made more robust with respect to encoding: jsp-config, all JSPs now saved as UTF-8,
database script specifies UTF-8, tag files include a tag directive.
- Predictions example app: DeleteAccountAction was using String, should have been SafeText.
web4j.jar version 4.5.0 (Published April 17, 2010)
Thank you to Burk Mayer of Barcelona for pointing out a number of ways to improve web4j, implemented in this release.
The DynamicCriteria Class Has Been Rewritten
The changes are not backwards compatible - sorry about that.
Every use of this class will need to be rewritten, but the amount of work to do so is usually minimal.
Migration tasks include :
- create the SQL fragment using StringBuilder, and pass that StringBuilder to the DynamicCriteria constructor.
The text of the SQL fragment is now completely up to you, with no policies being applied internally by DynamicCriteria
(except for validating that '?' placeholders are being used where they should be).
- ensure the base SQL statement in the .sql file doesn't have a dangling WHERE keyword at the end.
The reasons for changing this class are :
- the validation for SQL injection flaws was not very robust
- the class was too difficult to understand
- the class had too much policy regarding the structure of the WHERE clause
The current implementation of this class differs from the old in the following ways :
- it allows the caller to build a String in any way they see fit, instead of forcing specific policies upon the caller.
- it allows the caller to override the default SQL validation, if desired, and even to turn it off completely.
- it doesn't force the caller to include an ORDER BY clause.
- it has better checking for SQL Injection flaws.
- the base SQL statement defined in an .sql file must be a valid SQL statement - it cannot have an incomplete WHERE keyword
dangling at the end. The base SQL statement must be valid as a standalone SQL statement, such that, upon startup,
it can be (optionally) precompiled by the framework.
The DynamicCriteria class is still somewhat unsatisfying.
The main reason is that robust validation for SQL Injection flaws likely requires a full SQL parser - which the current implementation lacks.
The current implementation uses relatively simple regular expressions, and succeeds in protecting the programmer from obvious errors,
but it's not perfect. (See its javadoc for more on this issue.) On the positive side, even with these defects, this class goes
further than most other tools, which usually allow the programmer at least one way to define arbitrary, dynamically built Strings
for SQL statements, with no checking for SQL Injection flaws whatsoever.
Database Settings in web.xml Now Sensitive To Db Name
All settings in web.xml related to the database have been made sensitive to the database name.
There is a single exception - the TimeZoneHint setting is still applied across all databases.
(The reason for this exception is simply that changing it would have a large number of ripple effects, and would represent too much pain for too little gain.)
Formerly, the settings were applied uniformly to all databases.
This change was needed since, in particular, some applications use not only multiple databases, but also multiple database vendors
(MySQL and PostgreSQL in the same application, for example).
When a database setting has a single value applicable across all of your databases, you simply specify that single value, as before.
When a database setting takes different values for different databases, you define the various values with the following syntax :
100~Translation=200~AccessControl=300
The '~' character is used as a separator.
Here, the first entry '100' represents the setting for the default database.
It also represents the setting for all other databases, unless an override value is provided by one of the subsequent 'name=value' pairs.
Thus, the above represents :
Database Name | Value |
[the default db] | 100 |
Translation | 200 |
AccessControl | 300 |
[any other db name] | 100 |
Messages Are Now Serializable
AppResponseMessage
and MessageListImpl
now implement Serializable correctly, such that messages stored in session scope can be successfully transported to a
new session. This is needed for 'failover' operations between servers.
There is a defect to the implementation: 'Object...' is used for message parameters, not 'Serializable...'.
Thus, at runtime, you're not guaranteed that serialization will work.
In practice, however, almost all message parameters will be simple, serializable building block objects.
Other Changes
Other changes in this release :
- Add - new method DateTime.changeTimeZone(TimeZone, TimeZone)
- Add - new method DateTime.getMilliseconds(TimeZone)
- Fix - the precompilation of SQL statements upon startup was not sensitive to the name of the target database.
- Fix - the list of supported building block classes was not wholly consistent across the framework.
The idea is that ConvertParamImpl defines the building block classes,
to which other classes must conform.
- Fix - the framework now avoids using String whenever Id or SafeText will suffice.
This will avoid nuisance error messages when String is not supported by an application as a building block class.
- Fix - Db's javadoc for the allowable types of parameters was missing Decimal and DateTime, and included float in error.
- Fix - LoggingConfigImpl - small change to the format of date emitted upon startup. Seconds part - 'ss:fffffff' should be 'ss.ffffff'.
- Fix - SqlStatement.precompileAll() (a package-private class) was not properly closing connections, leading to a resource leak during precompilation.
web4j.jar version 4.4.0 (Published January 30, 2010)
The main item in this release is support for the new DateTime class.
This is a new building block class, similar to Integer, Decimal, Id, SafeText, and so on.
The DateTime class is intended as an alternative to the widely reviled java.util.Date class.
WEB4J will support both classes, but recommends DateTime as the preferred way of representing dates and times.
The following items resulted from the addition of DateTime :
- Change - DateConverter interface : the number of methods has doubled from 3 to 6.
- Change - ConvertParamImpl : now includes support for DateTime.
- Change - ConvertColumnImpl : now includes support for DateTime.
- Change - Controller : the Controller class puts the date-time of start-up in application scope; this object has been changed from a java.util.Date to a DateTime.
- Change - TroubleTicket : now uses a DateTime, not a java.util.Date.
- Change - LoggingConfigImpl : date-time used for the file name is now sensitive to the DefaultUserTimeZone setting in web.xml.
- Add - ShowDateTime : new tag has been added for displaying DateTime objects in JSPs; analogous to the existing ShowDate tag.
- Add - web.xml : a new setting named DateTimeFormatForPassingParamsToDb has been added. It controls how a
DateTime is formatted when it's passed as a parameter to an SQL statement.
- Add - Check : the min/max/range methods are now overloaded specifically for DateTime.
The addition of DateTime to WEB4J is not backwards compatible. Sorry about that.
Initially, to use the new web4j.jar with an existing app, you will need to :
- re-code your implementation of DateConverter to add 3 new methods.
Initially, you can simply provide stub implementations for the 3 new methods that refer to DateTime.
- update the displayMessages.tag file with the latest version, taken from the example apps (for a bug fix unrelated to DateTime).
Later, if you want to start using DateTime instead of java.util.Date, then you'll need to do more work :
- re-code your implementation of DateConverter to fully implement the 3 new methods.
- re-code your implementation of ConvertParamError to support DateTime.
- add the new DateTimeFormatForPassingParamsToDb setting to web.xml.
- update the web4j.tld file with the latest version, taken from the example apps.
Please use the Predictions example app as your guide. It makes extensive use of DateTime, while the Fish and Chips Club does not.
Other items in this release :
- Added : Check has 2 new methods, isTrue(Boolean...) and isFalse(Boolean...). They allow you to check any predicate that may need validation.
- Added : BuildImpl has a new pair of methods, adHocImplementationAdd/Remove. They allow a unit test to swap in implementations of various interfaces.
- Fixed : PermittedChararactersImpl now allows currency symbols (suggested by a user - thank you!)
- Fixed : AppException.getIsDisplayable() was returning the wrong value (fix sent in by a user - thank you!). This was a bizarre issue; there may have been a change/fix in the underlying libraries it was calling.
- Fixed : DbConfig.getTxIsolationLevelMessage (an unpublished class) - fix handling of case where db doesn't support a JDBC method call, as in DB2/AS400 (fix sent in by a user - thank you!).
- Fixed : ShowDate javadoc for setTimeZone was incorrect, in stating that calling setTimeZone necessitated also setting the format pattern.
web4j.jar version 4.3.0 (Published Sep 7, 2009)
This release is the first to include a second example application, called Predictions. It allows users to enter and search for predictions on
any topic. It was built for these reasons:
- it's more representative of public web apps: any user may register, lost passwords can be regained, a captcha
mechanism guards against spam, and it has data ownership constraints.
- it has a significantly simpler implementation than the original example application, the Fish and Chips Club: it has just a single
database, its user interface is in a single language, and it has no 'admin' features. Being simpler, it is more approachable as a learning tool.
Ownership Constraints
The most important addition in this release is improved support for "data ownership constraints".
When data is 'owned' by a specific individual user, then there are restrictions on who can edit (and perhaps view) the data.
Such constraints are very common for public web sites.
Whereas the Servlet Specification has ample support for role-based security constraints, it has nothing for
'owner-based' security constraints.
In previous versions of WEB4J, you had to implement ownerships constraints manually.
Version 4.3 of WEB4J adds the following items, to let you implement some commmon data ownership constraints in a manner somewhat
similar to role-based constraints:
- UntrustedProxyForUserId - identifies which requests need special protection for ownership constraints.
- UntrustedProxyForUserIdImpl, the default implementation of UntrustedProxyForUserId.
It uses web.xml, in a similar way as regular role-based security constraints.
- FetchIdentifierOwner - implemented by Actions which must query the database for the owner id,
before executing the main task.
Please see the updated User Guide for more information on this topic.
Other class have been updated to accomodate this new addition:
- the processing of requests by the Controller class has been changed to look for ownership constraints, and enforce them
- BuildImpl now accomodates the new UntrustedProxyForUserId interface.
The new Predictions example application demonstrates data ownership constraints.
Anonymous Sessions and CsrfFilter
Forms are usually presented to a user only after they have logged in.
There are some common cases, however, in which a form must be shown to a user who cannot log in:
- registering new accounts
- regaining lost passwords
(The new Predictions example application includes such forms, and illustrates the new feature described here.)
In previous versions of WEB4J, such forms could not be handled by CsrfFilter, since that class
required a valid login in order to function. That is no longer the case. CsrfFilter can now be used with sessions having no user login.
The following items are related to this issue :
- ActionImpl - the createSessionAndCsrfToken() method has been added. If an Action needs to create a session 'manually'
(because the user has not yet logged in), then the Action should call this method (usually in the Action's constructor).
- CsrfFilter - the addCsrfToken() method has been added; it is called by ActionImpl.createSessionAndCsrfToken().
- ApplicationFirewallImpl - the checking for CSRF attacks has been expanded to 'every POST request in a session'
With respect to CsrfFilter, there is one difference when a session does not include a user login: when a session expires,
there's no way to recover using a 'previous' token (since there is no previous token attached to the unknown user).
Change In Populate Tag's Logic
There are use cases in which a form shown in a GET operation should use request parameters to populate the form :
- forms that implement search criteria
- forms that reset a password, and need to reflect a one-off 'nonce' value sent in an email
- forms that need to reflect a 'parent id' in a hidden form variable
The logic of the Populate tag has been amended slightly to the following:
if a Model Object of the given name is in any scope {
override the default HTML for each control
use the Model Object
(match control names to Model Object's getXXX methods)
}
else if the request is a POST {
override the default HTML for each control
must populate every control using request parameter values
(match control names to request param names)
}
else if the request is a GET {
if control name has a matching req param name {
override the default HTML for each control
populate control using request param values
(match control names to request param names)
}
else {
use the default HTML for that control
}
}
The new logic change is in the final GET branch. Before, the logic was based on the kind of operation. The new logic is more inclusive,
and allows all GET operations to have the option of populating forms with request parameters. Strictly speaking, this change is not
backwards compatible. However, it is also likely that the great majority of applications will not be broken by this change.
Escaping Characters for JSON Data
JavaScript Object Notation is a simple way of implementing a public API to your website's database.
Serving JSON allows other developers to access your data programmatically, using javascript.
Two new methods related to JSON have been added:
Please see the ViewPublicListJsonAction in the new Predictions example web app for an illustration of generating JSON text.
Miscellaneous Changes
- WebUtil - add new method getFileExtension(String URL) - gets the 'operation' as a string.
- ResponsePage - add new constructor (String, Class), which uses the Class to locate the String (JSP).
This constructor is intended for a non-templated response located under WEB-INF.
- ShowDate - change the behavior when the named object cannot be found: just
return an empty String, instead of throwing an exception.
- ActionImpl -
many applications will benefit from having both the user id and the user login name placed in session scope upon login.
The Servlet Container will place the user login name in session scope upon login, but it will not place the corresponding user id (the database's primary key of the user record) in session scope.
If an app chooses to place the user's underlying database id into session scope under
the new USER_ID key,
then the user's id will be returned by the new getUserId() method.
- the delete methods in Db and DbTx
now take an Object... sequence parameter instead of a single Id
parameter. This change is actually backwards-compatible with existing source. Some delete operations specify both the Id of the item,
and the Id of a related 'parent' item owned by the user, in order to robustly implement a data ownership constraint.
- bug fix - the DynamicCriteria class now accepts
dynamic criteria having '?' placed within a function call. Before, it only accepted criteria in which '?' appeared
immediately after the operator, which excluded this case.
web4j.jar version 4.2.0 (Published March 19, 2009)
The following change is not backwards compatible.
However, it will affect only those who have created custom implementations
of the PermittedCharacters interface:
The PermittedCharacters interface and its default implementation have been
changed to use code points, not chars. This was necessary since some languages
use marks that are represented not by a single char, but by a pair of chars.
In addition, PermittedCharactersImpl has been changed to accept code points categorized as
NON_SPACING_MARK by Unicode. (This was needed to accept Thai characters, but is likely necessary for other scripts as well.)
The implementation of SafeText has been updated, to iterate correctly over code
points instead of chars.
The following additions are centered on making it a bit easier and safer to delete N items at once :
- a new method ActionImpl.getIdParams(ReqParam) to get N Ids
more quickly, without needing to go through the RequestParser.
- a new ForeignKeyException class to aid in detecting violations of foreign key constraints.
These exceptions can be thrown for delete, add, or update operations.
- a new setting ErrorCodeForForeignKey in web.xml. This setting takes N database error codes in a comma-delimited list.
These error codes correspond to violations of foreign key constraints.
- the existing ErrorCodeForDuplicateKey setting in web.xml is changed to accept N database error codes (instead of just 1),
in a comma-delimited list.
For an illustration, please see the "Members" feature of the Fish and Chips Club example application (version 4.2).
Minor changes to the User Guide :
web4j.jar version 4.1.0 (Published February 21, 2009)
This is the first open source version of WEB4J.
Minor fixes :
- internal initialization code, called upon startup, was throwing a NullPointerException as a side effect of the database
being down. This has been removed.
- typo in logging: the phrase "ErrorId encountered during attempts to precompile SQL statements" now simply reads
as "Error encountered...".
- CsrfFilter - javadoc and error messages have been improved, to communicate
that a successful login is required for this
filter to operate correctly. If a page has no login required, then the CsrfFilter cannot be applied to that page.
This can be handled by proper use of url-pattern in the Filter config.
- the Stopwatch class has been changed to use System.nanoTime(), instead of
System.currentTimeMillis().
New items added :
- the TimeSource interface has been added, along with TimeSourceImpl as its default implementation.
The TimeSource interface allows you to define a fake system clock, for testing purposes.
In addition, you can share your fake system clock with WEB4J framework classes, such that your app and the framework remain synchronized.
- the ModelUtil.comparePossiblyNull method has been added.
It helps you implement compareTo methods by allowing for possibly-null fields.
web4j.jar version 4.0.0 (Published December 21, 2008)
The web4j.jar binary is now free, and has no time limit restrictions whatsoever.
The distinction between Trial Version and Full Version no longer exists.
The following features, formerly available only in the Full Version,
are now always available :
- upon startup, identifiers in .sql files are matched one-to-one with declared public static final SqlId fields.
Any mismatches cause an exception, and your app will not proceed. This protects you, since it changes RuntimeExceptions into startup-time exceptions, and catches trivial typing errors as soon as possible.
- upon startup, SQL statement syntax can be verified by attempting pre-compilation. This is not supported by all JDBC drivers.
- upon startup, your Model Objects are scanned for possible Cross-Site Scripting vulnerabilities, where String is used instead of SafeText.
If an issue is found, it is logged as a WARNING.
- the PerformanceMonitor filter can be configured to issue a periodic 'ping' to a fixed URL.
If a problem is detected, or if the response is too slow, a TroubleTicket email is issued.
web4j.jar version 3.10.0 (Published September 20, 2008)
This release is focused mainly on adding a new building block class called Decimal.
The reason for adding such a class is to provide a more friendly way of dealing with items with decimal values than that provided by BigDecimal.
Decimal is meant for representing money amounts and measurements.
The Decimal class extends Number, so it can be used in the same way as a BigDecimal, Integer, and so on.
Conversely, support for Float as a building block has been dropped completely.
The reason is that, for typical business applications, floating point data has many undesirable characteristics, making it an almost pathological data type.
Any WEB4J apps that use floating point data will need to convert to
either the new Decimal class (recommended), or BigDecimal.
The following classes have been affected by this change, and no longer support
floating point data. Thus, these changes are not backwards compatible (sorry about that):
- the ConvertColumnImpl default implementation no longer accepts float
- the ConvertParamImpl default implementation no longer accepts float
- ConvertParamErrorImpl (in the example applications) no longer accepts float
- the Util.hasMaxDecimals() method now takes BigDecimal/Decimal only.
- the versions of the min/max/range methods in Check that take a double have been removed.
- support for Float in Formats has been removed.
- the FloatDisplayFormat setting from web.xml has been removed.
One other item is also not backwards compatible :
- the ambiguous name of Check.numDecimals() has been changed to numDecimalsMax(int).
In addition, the method now allows only BigDecimal and Decimal.
We apologize for any inconvenience these changes may cause. All other items are backwards compatible.
The addition of Decimal has made other additions necessary :
- add Check.numDecimalsAlways().
- extend the Check.max/min/range/numDecimals methods to include Decimal.
- extend the ConvertColumnImpl default implementation to include Decimal.
- extend the ConvertParamImpl default implementation to include Decimal.
- add support for Decimal in Formats.
- extend ConvertParamErrorImpl (in the example applications).
- add a new web.xml setting named DecimalStyle; defaults to 'HALF_EVEN,2'.
This setting controls how Decimal objects are rounded.
Other changes :
web4j.jar version 3.9.0 (Published August 30, 2008)
This release is focused mostly on improving security.
Many of these changes are not backwards-compatible.
We apologize for that.
The justification for these nuisances is that, in the end, your apps will have significantly better protection against malicious attack.
Reminder list of upgrading tasks (more details below) :
- review your app for problems with special characters (see below).
If any problems exist, they will likely be found simply by exercising your app for a few minutes.
If any problems are found, provide a custom implementation of PermittedCharacters (usually not necessary).
- in Actions, when extracting request parameters as raw Strings for a computation, you must now use getParamUnsafe().
The reason is to remind you that unescaped Strings are a dangerous substance in web apps (because of XSS attacks).
- any uses of DynamicCriteria need to be changed. 'WHERE' must now appear in the .sql file, at the end of the SQL statement.
If you were adding any static criteria in code (which would be rather weird), then such static criteria must be moved to the .sql file. It can't be added in code.
- review your implementation of ConvertParamErrorImpl.
Often, you can just steal the new implementation from Fish & Chips Club.
- replace your web4j.tld files with the updated version included with the new Fish & Chips Club.
- in JSPs, to produce valid HREF attributes that contain ampersands, you should use the new w:ampersand function now defined in web4j.tld.
If you were using w:safe before, you need to replace it with w:ampersand.
- consider using a SuppressUnwantedSessions filter.
SafeText versus String
Of particular note is the new emphasis on SafeText instead of String.
This new emphasis will often be a nuisance to those migrating from earlier versions.
We apologize for that.
The underlying reason for the change is to make the protection against Cross-Site Scripting attacks as strong as possible.
Roughly speaking, String has been made a second-class citizen in the list of supported base classes, while SafeText has been promoted to take its place.
If you were already making liberal use of SafeText, then this changes shouldn't be too onerous.
The PermittedCharacters interface has been added, with PermittedCharactersImpl as its default implementation.
The idea here is to define a white list of accepted characters for all instances of SafeText.
The default implementation may or may not work for you.
Old apps will break if they use unusual characters.
The fix is to supply your own implementation of PermittedCharacters which accepts the unusual characters.
For an example, see the Fish & Chips Club, which needed to extend the default implementation for a single unusual character.
ConvertParamImpl now works with a new setting in web.xml, called
AllowStringAsBuildingBlock. By default, this setting is 'NO', which disallows using String as a building block class
such as Date, Integer, and so on. Again, the reason is to protect you from Cross-Site Scripting attacks.
If you still wish to use String as a regular building block class, you may still do so
by setting AllowStringAsBuildingBlock to 'YES'.
Other related changes :
- EscapeChars.forHTML - the set of escaped chars has been expanded from 12 to 33.
Many tools escape only 5 characters. It's unclear if that is adequate, since the Open Web App Security Project recommends escaping 12 characters, not 5.
To be on the safe side, web4j takes a particularly paranoid approach, and now escapes 33.
On the downside, the expanded list of characters may now make some old data now appear as escaped, where before it appeared as 'normal'.
- ConvertColumn - instead of 'highly recommended', it is now required that ConvertColumn implementations must use ConvertParam.isSupported.
- you should review your application's implementation of ConvertParamError.
For example, see the Fish & Chips Club for an updated implementation.
- RequestParser.toString(s) has been replaced with RequestParser.toSafeText(s).
- ActionImpl.getParam() now returns SafeText, not String.
- ActionImpl.getParamUnsafe() now added, returns String.
This is provided as a convenience, when the returned String is used for a computation, instead of presenting data to the user.
- Id is still constructed with String, but uses SafeText internally, and returns a different value from its toString() method.
- Add Id.getRawString, and Id.getXmlSafe.
- Code now constructed with SafeText, not String.
- Translation now uses SafeText, not String.
- Translation now constructed directly with a Locale object directly, not with a locale String.
- Text tag - the setWikiAndHtmlMarkup method has been removed.
No longer allow user to enter arbitrary HTML markup. Way too risky, too open to attack.
Session Management
The following changes improve security of sessions.
The general idea is that since session identifiers are open to session fixation and session hijacking, sessions and their identifiers should be treated as a controlled substance.
Sessions should be created only when the programmer explicitly intends it.
They should not be created liberally.
- WebUtil.findAttribute() no longer creates a session, if one does not yet exist.
WebUtil.init() has been added.
Ripple effect of this change: the default LocaleSourceImpl will not look in session for an 'override' locale, if the session doesn't already exist.
- The methods HttpSession.getSession(true) and HttpSession.getSession() are no longer called by the framework.
These classes are affected, but only in an incidental way: ApplicationFirewallImpl, CsrfFilter, Controller.
- ActionImpl no longer creates sessions.
If one of its operations requires a session, and no session exists, then an UnsupportedOperation exception is thrown.
- ActionImpl.createSession() has been removed. If ever needed, you can instead use getRequestParser().getRequest.getSession(true).
- ActionImpl.getExistingSession() has been added.
- SuppressUnwantedSessions has been added as a new filter.
This filter works only with form-based login (the most popular style).
It uses wrappers to alter behavior of request and response. This filter disables URL rewriting, since it is a high security risk.
Calls to request.getSession() and request.getSession(true) are coerced to request.getSession(false).
This will suppress creation of extraneous sessions by JSPs.
The most conservative approach is to create a session only when the user logs in.
In addition, your app should explicitly destroy session cookies when the session ends.
See the LogoffAction in the Fish & Chips Club for an example.
SQL Injection
These changes improve protection against SQL injection attacks :
- the word 'WHERE' must now appear in the .sql file, as part of the base SQL statement. This clearly communicates to the reader of the
.sql file that the SQL statement is special, incomplete, and requires additional clauses.
- DynamicCriteria - the .sql file must contain any static WHERE criteria associated with a dynamic SQL statement.
All static criteria must appear in the .sql file since they cannot be added in code.
Only dynamic criteria taking a ? parameter can be added in code.
As well, DynamicCriteria enforces the rule that ? must appear in every location that it can appear in the dynamic criteria.
For example, an 'OR 1=1' kind of criterion does not follow that rule, and would be rejected, since no '?' appears after the '=' sign.
In essence, this seems to make it practically impossible to dynamically craft a malicious SQL statement, even in the case of egregious programmer error. (If you disagree, please let us know why.)
Although previous versions of WEB4J did not have the above behavior, those previous versions still had strong protection against
SQL Injection attacks. However, it was recently noticed that DynamicCriteria was theoretically open to some obscure
problems -- not really through crafted input, but rather through some egregious and bizarre programming errors,
in which criteria added in code did not actually contain any '?' parameters. Such cases were unlikely, but theoretically possible.
In addition, since the programmer is the source of the criteria, and not a crafted request, it's very improbable that
such programmer errors could have resulted in a successful SQL Injection attack.
However, the above improvements to DynamicCriteria were felt to be necessary, in the interest of providing
protection even from unlikely sources of error.
Defaults Settings in web.xml
The following changes were made to default settings in web.xml.
Strictly speaking, these changes are not backwards compatible.
In practice, however, these changes are not likely to affect most apps, since few apps would have actually relied on the old default values.
- Webmaster - no longer has a default value
- ImplicitMappingRemoveBasePackage - no longer has a default value
- MailServer - add 'NONE' as default
- BooleanTrueDisplayFormat - in default, change submitted value from 'blah' to 'true'
- BooleanFalseDisplayFormat - in default, change submitted value from 'blah' to 'false'
- IgnorableParamValue - change default from 'SELECT' to empty String
- DecimalSeparator - change default from 'PERIOD,COMMA' to just 'PERIOD'
Other Items
Other items in this release :
- BUG FIX -- ConvertParamImpl.init() was never called upon startup. It still functioned since it relied on an internal default.
This bug fix has had the effect of changing the order of startup operations, to ensure that default implementations get the same treatment as any possible custom replacements you may write.
As a result, the order of items appearing in the logs has changed.
- BUG FIX -- the FullyValidateFileUploads setting in web.xml was not documented in the User Guide.
- BUG FIX -- ConfigReader (an internal, upublished class) now ignores any package-info.class files, instead of treating like a real source file.
Previously, some apps would have seen extraneous error messages related to package-info.java files.
- logging statements that include user data are now at the FINEST. level. This is to minimize the likelihood of production data appearing in logs file entries (which is a security risk).
- RequestParserImpl.getWebAction() - if the Action constructor throws an exception, the exception message is now logged (more informative).
- Upon startup, the Controller will now check for classes appearing in Model Object constructors which are not supported by ConvertParam.
Any incidents are logged as a warning.
- EscapeChars.forHrefAmpersand() has been added, specifically for generating valid HREF attributes in links.
The <c:url> tag doesn't do this escaping.
HighlightCurrentPage now uses this escaping mechanism, instead of EscapeChars.forHTML().
Fish & Chips Club has a new w:ampersand() function for creating valid HREFs from the output of <c:url>.
Its web4j.tld has been updated (you should copy it into your projects).
web4j.jar version 3.8.0 (Published June 7, 2008)
Small update (backwards compatible) :
- TroubleTicket - add alternate constructor for specifying custom content for the email body.
- PerformanceMonitor - add periodic 'ping' of a fixed URL, and
send a TroubleTicket if a problem is detected. This feature is available only for
the Full Version of web4j.jar.
- Controller - fix NullPointerException thrown when Controller is
initialized outside of normal runtime environment (that is, when testing outside the container).
- Log Viewer (Full Version Only) - fix error for viewing Parsed Logs. Last record was missing.
This update is mostly about improving support for typical unit testing, by providing a
number of test doubles. The test doubles aren't provided as part of web4j.jar, but
rather as source code in the example application. They are provided as
source code since they are usually incomplete, and may need to be edited occasionally.
(They are incomplete since some methods, typically not needed for unit testing,
are left unimplemented.)
For more information on unit testing, please see the User Guide.
web4j.jar version 3.7.0 (Published May 12, 2008)
Small update (backwards compatible) :
- allow serving binary content under the main Controller.
Add ResponsePage.withBinaryData() factory method.
For such ResponsePages, the Controller will not perform a forward or redirect.
Instead, the Action is responsible for serving the response.
- in web.xml, the default value for the CharacterEncoding setting has been changed to UTF-8 (from ISO-88591-1).
(Technically, this isn't backwards compatible. In practice, it's very likely that all of your apps have this item set in web.xml, such that its default value is almost never used in the first place.)
- change PerformanceMonitor to insert blank PerformanceSnapshots to explicitly indicate periods with no activity.
(This provides a way of detecting problems with Apache connections. For example, if Apache connections are being hogged by some process, then
your app will show a 'black hole' of inactivity, even though your app is functioning correctly.)
web4j.jar version 3.6.1 (Published April 8, 2008)
Minor bug fixes (all backwards compatible) :
- Controller - correct logging of request parameter names and values
- ModelFromRequest - correction to javadoc
- internal, unpublished class used for Model Object construction now emits improved error message
web4j.jar version 3.6.0 (Published March 11, 2008)
A single change is not backwards compatible (sorry) :
- RequestParserImpl -
The URI Mapping String no longer includes the .do (or whatever) extension at the end.
Implicit mappings are not affected by this change.
Any actions that use explicit mappings, however, need to remove the extension.
Since explicit mappings are relatively rare, this change should not cause excessive pain.
This change was needed to implement fine-grained security constraints (see below).
(In retrospect, including the .do extension in the first place was a design error - it violated the Don't Repeat Yourself rule.)
As well, the related setting ImplicitMappingAddSuffix has been removed from web.xml.
All other changes are backwards compatible :
- WEB4J now handles file upload forms more naturally.
To implement file upload, a third party tool must still be used to parse the underlying request. In this way, WEB4J itself avoids unnecessary dependencies on third party tools.
See Fish & Chips Club for an example using the Apache Commons FileUpload tool.
- The behavior of ApplicationFirewallImpl has been extended, and its javadoc has been clarified.
It now uses a new setting in web.xml called FullyValidateFileUploads.
- Fine-grained security using extensions such as .list and .add is now supported.
- ActionImpl.getOperation() has been added.
It returns the operation, extracted in one of two ways: first from a request parameter, and second from the extension used in the URL.
- Operation.valueOf(String) is no longer case-sensitive.
- a new field called 'Do' has been added to Operation.
- EscapeChars.forReplacementString(String) has been added.
- Fix : EscapeChars.forReplacementString(String) is now used in
CsrfFilter, AppResponseMessages, Tooltips, TextFlow, Pager, and HighlightCurrentPage.
web4j.jar version 3.5.0 (Published February 16, 2008)
Two changes are not backwards compatible. Both are related to startup operations :
- StartupTasks - this interface
now has only a single method startApplication(ServletConfig), taking
a single parameter.
- ConnectionSource - this
interface has an additional method called init(ServletConfig).
In effect, any ConnectionSource initialization tasks have been moved directly into
ConnectionSource itself.
All other items are backwards compatible :
- Controller logging - session scope items are now logged at FINEST.
Sometimes large lists of items are held in session.
- Controller validation - upon startup, the Controller will scan for public Model Objects having
public getXXX methods that return a String instead of SafeText.
- Stopwatch - the stopwatch value can now be examined without having to
stop the stopwatch.
There is now a distinction between the behavior of the trial version of web4j.jar and the
full version of web4j.jar. These distinctions are minor, and affect only the execution
of the following startup validations :
- one-to-one matching of identifiers in .sql files to public static final SqlId fields
- scanning for possible Cross-Site Scripting vulnerabilities in Model Objects
web4j.jar version 3.4.0 (Published January 22, 2008)
The sorting mechanism has been changed (and the changes are not backwards compatible).
the <w:sort> tag has been removed, for these reasons :
- sorting items is more of a programming task, than a presentation task
- the most natural tool available for sorting items is the ORDER BY clause in an SQL statement
- the DynamicCriteria class already exists, and is capable of implementing sorting
- the implementation of <w:sort> was defective
The <w:sort> tag might have been fixed, but given the other issues, it was
decided to drop it entirely, in favor of a more satisfying mechanism, implemented in code instead
of the JSP.
Changes include :
- the name of the class SearchCriteria has been changed to DynamicCriteria, to
more accurately reflect its use outside of search operations.
- DynamicCriteria now allows the WHERE clause to be optional.
This corresponds to the common case of adding sorting criteria to an arbitrary SELECT statement,
which does not necessarily have a WHERE clause.
- all methods of the Report class have been changed to accept an additional
DynamicCriteria parameter. Given that sorting columns is
so beneficial, it is likely best to treat 'sortability' as the preferred, default case.
If no sorting is desired, it is recommeneded that DynamicCriteria.NONE be used to indicate that fact.
- ActionImpl has a new method called getOrderBy().
web4j.jar version 3.3.1 (Published January 15, 2008)
All changes are backwards compatible :
- Added - case of not using a database at all. To indicate no database is in use, the application's
implementation of ConnectionSource.getDatabaseNames() should just return an empty set.
- Added - the Operation class now has a valueFor(String) method. It is similar to valueOf(String),
but has different behavior for empty and unknown values, useful for Action constructors.
- Added - If a request parameter value is invalid, then ApplicationFirewallImpl
will log the occurence at SEVERE level in addition to throwing a BadRequestException.
- Fixed - the scope of the Check constructor was changed from private to protected.
The private scope was preventing the creation of subclasses, and thus preventing one style of implementing custom validations.
- Fixed - the behavior of ActionTemplateShowAndApply was not quite right when an error occured
during the Apply operation. Instead of doing a 're-show', it is better to populate the form with the data which caused
the errors in the first place, instead of showing the 'original' data.
- Fixed - The javadoc for Populate had an error in its example getXXX methods
web4j.jar version 3.3.0 (Published December 19, 2007)
Changed (not backwards compatible - sorry) :
- Fixed StartupTasks - this interface should have been separated into two methods, one for extracting config from web.xml, the other for doing the startup task.
To fix existing implementations, you will need to split the old implementation into two parts : one which reads the config params (if any), and one which actually performs the startup task.
Added/Changed (backwards compatible) :
- Controller - now attempts recovery when one or more databases are down upon startup.
- Controller - destroy method now logs the application name and version. This will aid in determining when the application was shut down.
- Check - add Check.range(min, max) methods. This is a nice, simple, addition, which makes Model Object validation code noticeably more legible.
- Util.textHasContent() is now overloaded to accept SafeText as well as String.
- ConvertParamImpl and ConvertColumnImpl extended to include int.class, as well as Integer.class (and so on, for various primitive types).
- LoggingConfigImpl will now attempt to create the logging directory if it doesn't already exist.
- Code constructor will now accept null for Id. Needed for 'add' operations.
- Code is now Serializable
web4j.jar version 3.2.0 (Published November 15, 2007)
Added :
Response Headers - the Controller now sets the charset HTTP
header for every response, according to the existing CharacterEncoding
setting in web.xml. Thus, JSPs no longer need to repeatedly set
this header. If desired, you may override in a JSP by using the
page directive.
web4j.jar version 3.1.0 (Published October 27, 2007)
Tools for building more secure web apps, and other items.
Only two new classes have been added.
Added :
- Add SafeText as new building block class.
Provides excellent protection against XSS attacks, by automatically
escaping for special characters in its toString() method.
- Add CsrfFilter for defense against CSRF attacks.
Warning - there is a bug related to this filter, and all filters that
use a response wrapper: the error page mechanism does not work as expected for wrapped responses.
That is, when an error occurs, the server's default, generic error page is shown, and not the error
page you have configured in web.xml.
- SqlId - add fromStringId(String) factory method,
to build SqlId from text which may or may not be qualified by the database name.
- EscapeChars - add new method forXML(String)
- Operation - add new method hasSideEffects()
Fixed :
WEB4J source did not compile/run under JDK 6! (Sorry about that. A single call to Class.getConstructors() failed.
This call generated only a warning under JDK 5. WEB4J source now compiles/runs under both JDK 5 and JDK 6.)
This failure was apparently an instance of the following (taken from JDK 6 docs) :
"The cast implementation adheres more closely to the Java Language Specification. In general, this means
that javac will accept more programs. However, in some rare cases, javac can now reject previously accepted,
yet incorrect programs." - see link (point 5).
- EscapeChars.forHTML() now extended to 12 chars, to match recommendations of OWASP.
- Report class - 'raw' and formatted cases now returns not String, but SafeText as the column value.
Caller can decide how to escape, by using default SafeText.toString(), or other method.
- ConvertColumnImpl had inadequate javadoc.
- Id class - implementation of Comparable should have been JDK 5 version.
- Operation.isDatastoreEdit() should have included the DeleteAll Operation.
- Populate tag javadoc - should have mentioned the escaping done for input type='text' tags.
- Populate tag - 'recycle params' mode will now coerce null param/param values to the empty String.
(Needed to allow delete operations to be a POST instead of a link.)
Changed (backwards compatible) :
- Check.min() and Check.max() extended to include SafeText.
- ConvertParamImpl extended to include SafeText.
- Db extended to include SafeText.
- Formats.objectToText() extended for SafeText.
- ApplicationFirewallImpl - extended to perform security checks agains CSRF attacks.
- AppResponseMessage - will do some escaping. Will escape parameters only (except if it is already SafeText).
Doesn't escape base pattern text, only parameters.
- ApplicationFirewallImpl - increased security. If an Operation param is present and
Operation.hasSideEffects() is true, then the underlying request must be a POST.
Changed (not backwards compatible - sorry) :
- Four items moved to the new hirondelle.web4j.security package: ApplicationFirewall, SpamDetector, and
their respective default implementations. (Sorry about this change. Best for the long-term health of the
tool, since security is such an important issue.)
- EscapeChars - method name changed from forHTMLTextFlow() to forHTML(), since not accurate:
applicable to more than regular text flow.
- Text tag - wiki formatting was using '-' for special formatting (bullets and horizontal bars).
That was interfering with escaping, since '-' is a special character. Change to use '~' for both bullets and horizontal bars.
- Formats.objectToTextForReport() now returns SafeText, not String.
This broke some items in Fish and Chips, where private methods in Report Actions returning
'List<Map<String, String>>'
needed a change to
'List<Map<String, SafeText>>'.
- ActionImpl.getLoggedInUserName() now returns SafeText instead of String, since user name
is so often displayed in the view.
web4j.jar version 3.0.0 (Published September 8, 2007)
Very large number of changes, deletions, and additions. (Unfortunately, there are too many to list here.)
The overall number of classes has actually decreased slightly.
The tool has been improved substantially, and is now both more elegant and robust.
Some highlights include :
- now requires JDK 1.5
- package-by-feature : all items related to a feature can live in the same directory - code, JSPs, .sql files
- automated mapping of URI to Action
- better Action templates
- configuration-by-reflection : the RequestParamters allowed for each Action are found by reflection
- excellent services for multilingual apps. Apps can assist in their own translation.
- removed onerous requirements on thread-safety
- simpler implementation of equals, hashCode
- SpamDetector, ApplicationFirewall
- many others...
web4j.jar version 2.3.0 (Published November 11, 2006)
Items not backwards-compatible with version 2.2.0 :
- Change parsing of decimal numbers to no longer use DecimalFormat. See
web.xml in the example application for more information.
- Change parsing and formatting of dates. Instead of using SimpleDateFormat and
settings in web.xml, the
DateConverter interface has been added.
It allows the application programmer to explicitly define how Dates are parsed and formatted.
- Change ConnectionSource by adding a second method, to allow more than
one database to be used by an application.
All other items are backwards-compatible with version 2.2.0 :
- Add Validator and
Check to help Model Objects implement validation.
In the example app, include a subclass of Check, and change Model Objects to
use this validation mechanism. (This is a nice addition. It makes Model Object implementations significantly more legible.)
- Add the Tooltip tag to translate all TITLE and ALT attributes.
This tag is placed in a template, and can translate all TITLE and ALT attributes served in the body of the template.
- Add the TextFlow tag to implement bulk translation of
all regular text flow in the tag's body.
- Add Util.removeQuotes and
Util.maxDecimals
- Fix javadoc in RequestParser.
web4j.jar version 2.2.0 (Published September 9, 2006)
Items not backwards-compatible with version 2.1.0 :
- several changes caused by internationalization (see below)
- Change name of PickListValue to
PickListItem,
since it often contains more than one value. This change is annoying but desirable. For many people,
the word "value" conventionally means a single, simple value such as a Date or an Integer.
- Change output of
Util's various logOnePerLine methods
WEB4J now has good support for multilingual applications. WEB4J generates user-visible output in these ways :
showing response messages (AppResponseMessage),
viewing ResultSets (ReportBuilder),
showing dates (ShowDate),
and prepopulating forms (Prepopulate).
All of these areas have been affected (some of the changes are unfortunately not backwards compatible).
Here is a summary of the changes :
- Add LocaleSource
to allow programmer to define how Locale is to be deduced for a given request.
Add LocaleSourceImpl as a simle default
implementation, which simply uses a single Locale specified in web.xml.
- Add ConversionError
to allow programmer to define error messages for low level parsing problems,
such as translating text into an Integer.
- Add a getLocale method to WebActionImpl,
such that any WebAction can get quick access to the Locale returned by
LocaleSource
- Change Formats methods to be instance methods, not static ones.
Pass a Locale to its constructor, instead of relying on a configuration item passed to its static init method.
LocaleSource will be the source of the Locale passed to the constructor.
- Change ReportBuilder - delete the ApplyFormats
type-safe enumeration, and replace it by passing a Formats
object directly. If the object is null, then no formatting is applied.
- Change signature of
AppResponseMessage.forCompound
- Delete the Web4jResource ResourceBundle mechanism, since now obsoleted by
ConversionError
All other changes are backwards-compatible with version 2.1.0 :
- Add a "test" precompile of SQL statements upon startup. The principal benefit is
finding errors more effectively : a possibly-rare runtime error is changed into a
much more obvious "startup-time" error.
This is a very nice feature, but JDBC does not require implementations to precompile
SQL statements during calls to Connection.prepareStatement(String). In the example application,
precompilation works for MySQL and JavaDB, but not for Oracle.
- Add Id class as a new kind of
'base' object. This allows Model Objects to read at a slightly higher level, since the
identifier - always of central importance in a Model Object - is clearly distinguished from
all other items.
The example application has been refactored to use this class for its identifiers.
The parsing of requests and ResultSets has been extended to include Id.
- Add new verbs to the Operation enumeration.
Add an
isDatastoreEdit
method, to identify operations which edit the database.
Update docs for related class
WebActionTemplateB.
- Add a new interface/implementation pair for the conversion of ResultSet
columns into 'base' objects :
ColumnToObject, and
ColumnToObjectImpl.
In the example application's config package, ColToObject is the name
assigned to the configured class. The application programmer can now override default behavior
for this translation, if desired.
- Add more flexibility to the
RequestParser,
to allow binary data to be
posted as well. The Servlet API is still disturbingly primitive at handling file uploads.
WEB4J now has minimal support for file uploads : such data can be posted, but
no direct assistance is provided for examining the file length, MIME type, and
so on. (Instead, some other tool must be used. The example application uses the
Jakarta FileUpload tool, but other tools exist as well.)
New files added to example application : UploadFile.jsp, UploadFile.java.
New item added to web.xml : MaxFileUploadRequestSize.
Changes to
RequestParameter and
RequestParser were made as well.
Note : prepopulation of file upload controls is not implemented. It does not seem
to make sense, since popular browsers do not render the value attribute for such controls.
- Add JavaDB as third database option for the example application.
This port is about 95% functional. It is not 100% functional since a couple of items
need actual code modifications in a Data Access Object, and not simple translation of SQL statements.
(The cause was JavaDB's minimal set of built-in functions.)
Such code modifications are "left as an exercise to the reader". This partial porting to
JavaDB is unfortunate - but a 95%-complete port is better than no port at all.
- Add the convenience method getRequest to
CommonBodyTag
and CommonEmptyTag.
- Delete from the example application all items related to the Admin screen, since they do not offer any real value.
Remove myadmin directory : Admin.jsp, Login.html, and Error.html
Remove related entries in web.xml as well: security-constraint, login-config, and
security-role. (This deletion does not break backwards-compatibility, since it was part of the
example application, not of WEB4J itself.)
- Change controls names from coder keys (emailAddr) to user-friendly style (Email Address). This allows
error messages regarding from input to reuse the control name directly, instead of requiring continual,
trivial translation from a coder key into user-friendly text
- Fix :
SqlStatement items increased to public
scope, to render their javadoc visible to the programmer. Although these items are not called directly
by the programmer, they should still be visible. (Silly error - my apologies).
- Fix : Bug in Pager.
'Missing' links should have been empty Strings, not null. Bug present since version 2.0.0 (Feb 2006).
- Fix : Bug in TroubleTicket.
Did not properly parse the web.xml setting (dumb). Bug present since version 2.1.0 (?).
web4j version 2.1.0 (Published March 26, 2006)
One item in 2.1.0 is not backwards-compatible with version 2.0.0 :
-
Change to using CDATA in the web.xml entries for formatting boolean items
in reports. (The previous style erroneously forced the programmer to drop
any special < and > characters, instead of using the standard CDATA
escape mechanism for xml files.)
All other changes are backwards-compatible with version 2.0.0 :
-
Change the mechanism for finding .sql files upon startup, to allow
.sql
files to appear anywhere under WEB-INF, instead of only in WEB-INF
itself. This allows .sql files to appear immediately beside classes
which use them. This makes features more modular, by allowing items related
to a single feature to appear in a single location. This change is reflected
by ConfigReader.
Both styles are illustrated in the example application. For the MySQL version,
the .sql files are located beside their related classes. In addition,
two "disabled" .SQL files, for both MySQL and Oracle, are provided
in the WEB-INF directory. (As before, a .SQL file is
enabled by altering its extension to .sql - lower case.)
-
Change all web4j init-params in web.xml to have default values
if not present. (Not included in this mechanism are webmaster email address
and mail server, which are context parameters, not init-params.)
The reason for this is to allow portions of web4j to be used without requiring
large amounts of undesired configuration. For example, the web4j data layer
services might be used to implement an application's data layer, while
some other tool may be used for other parts of the application. Items can
be included only if needed, and only if its value differs from the default.
(The default values are documented in the web.xml of the example application.)
-
Add a new interface/implementation pair called ConnectionSource
and ConnectionSrc,
to give the application programmer complete control over how an application
creates or accesses Connections. (The example implementation's ConnectionSrc
has the same policy as in all previous versions - accessing a Datasource
using JNDI.)
-
Add a web.xml setting for character encoding. This item is used in the
Controller.
In addtion, it is also made accessible as an application scope item named
web4j_character_encoding, which may be easily referenced in an
application's template JSPs, to set the desired encoding.
-
Add a second version number. Previously, one was defined in AppInfo
for the example application. Now, the name and version of the web4j.jar
itself is also compiled into the Controller. (Both items are logged
upon startup.)
-
Add Util.logOnePerLine for both Collections and Maps. These
Util
methods are used to eliminate long lines when logging. It simply places
each item in a Collection/Map on its own line. This simple technique makes
some log entries much more legible, since horizontal scrolling is usually
eliminated.
-
Fix javadoc by generating with -protected instead of -public.
This will add a few items which should have been visible, but were not.
In particular, this affected items in the hirondelle.web4j.ui.tag
package.
web4j.jar version 2.0.0 (Published February 18, 2006)
-
Large changes to how code is arranged, plus a few new fixes and features.
-
Split old code base into web4j.jar plus an example application.
-
Discard the 'MyXXX' naming convention. This corresponds to the separation
into web4j.jar and the example application.
-
Add InterfaceToObject
as a plug-in mechanism, used with various new interfaces used to control
the behavior of web4j.
-
Add hirondelle.web4j.config
package.
-
Add interface ApplicationInfo,
with AppInfo
example implementation.
-
Add interface ParameterNameToText,
with ParameterNameToTextImpl
as example implementation.
-
Add interface RequestParameterEnumeration,
with ReqParam
as example implementation.
-
Add interface SqlIdEnumeration,
with SQL
as example implementation.
-
Add interface StartupTasks,
with Startup
as example implementation.
-
Add Web4jResources.
-
Add Web4jBean, for "reserved"
names of objects used by web4j.
-
Add AppResponseMessage.
-
Add two new elements to Operation
- List and ListForChange.
-
Add line number to all reports.
-
Add an alternative paging mechanism - Pager
and PagerLink - which
can be added to any existing JSP without code changes to the WebAction
or DAO
-
Move asList utility methods for building Lists to Util.
-
Remove some unused import statements, etc.
-
Change NumDaysOfRecentHistory setting in web.xml, for PerformanceMonitor,
to actual number of items stored
-
Move the 51200 max request size into web.xml, as configured item.
-
Changed names : AbstractRequestParser to RequestParser,
MyBean to Bean,
DestinationPage to ResponsePage,
MyActionEnsureLogin to ForceLogin,
SqlReader to ConfigReader,
MyWebActionMapping to RequestToWebAction,
Sql to SqlStatement.
-
Change the PerformanceMonitor links to tooltips. Reason: underlying request
might actually be a GET which edits the database (common error), or may
be a POST. For POST, the POSTed data is absent from the presented URL.
-
Change the Controller to
allow limited subclassing.
-
BUG : ConcurrentModificationException with PerformanceMonitor. Change the
synchronization of PerformanceMonitor to use lock on the collection, return
a synchronized version to the caller, and add a synchronized block around
the JSTL snippet which iterates over it.
web4j.jar version 1.9.0 (Published November 12, 2005)
-
Add PerformanceMonitor
filter. Add PerformanceSnapshot,
MyActionShowPerformanceReport, and PerformanceMonitor.jsp. (Here is the
page in the example
deployment.)
-
Add TxIsolationLevel,
and allow changes to transaction isolation level. Edit web.xml, DbConfig,
SqlEditor, SqlFetcher, TxTemplate, DbConnection, MyReportDAO, MyUserDAO.
Configure default transaction isolation level for SqlEditor and SqlFetcher
in web.xml.
-
Add AbstractResponseFilter
-
Add Trim filter as alternative
implementation to custom tag which does the same thing
-
Add CommonEmptyTag,
as base class for common style of custom tag Add ShowDate
as concrete impl
-
Add CommonBodyTag,
as base class for another common style of custom tag. Refactor most tags
to use it as ABC
-
Add Trim tag for removal
initial whitespace from markup
-
Add Util.getLogger
to centralize policy for logger names, and change all Logger users to call
it.
-
Add Util.quote,
and use it where string data is logged.
-
Change the text file containing SQL statements from a properties file to
a .sql file, with a much improved style. No more line continuation characters
are needed. In addition, simple substitution variables can be used to avoid
repetition, both of magic numbers and of sub-queries. For details on the
file format, see Sql, and
the example .sql files themselves.
-
Change - rename WebInfProperties to ConfigReader.
Allow ConfigReader to read in .sql files, in addition to .properties files.
Add SqlReader.
-
Change - rename some important abstract base classes, to clarify and simplify
the names. AbstractLocalTx -> TxTemplate
, MyRequestParser -> MyWebActionMapper,
AbstractWebAction
-> WebActionImpl,
AbstractStandardWebAction -> WebActionTemplateA,
AbstractStandardOpsWebAction -> WebActionTemplateB
-
Change - remove AbstractValidatingWebAction. Almost the same as WebActionTemplateA
-
Change - rename ModelFromParams to RequestToObject,
since so similar to RowToObject. Clearer, simpler name.
-
Change - treatment of duplicate keys. If detected, translate into a new
kind of exception (DuplicateException,
a subclass of DAOException), instead of returning 0. Forces caller to be
aware of the problem. Allows much cleaner transaction implementation, since
no need to continually check-for-failure. SqlEditor now throws both DAOException
and DuplicateException. Applies to add/change operations only. The asymmetry
between this kind of SQLException and all others has been eliminated, while
still allowing for its special nature.
-
Change - the API of SqlEditor to follow the superior style of SqlFetcher.
-
Change - replace the constructors of SqlFetcher
and SqlEditor with factory
methods, to make much more clear to the reader that a transaction is or
is not involved.
-
Change - remove ad hoc timings from MyPersonDAO, since now handled by PerformanceMonitor.
-
Change - move name/version/author from Consts to Controller, since this
data is not really constant.
-
Change - improve Sql.getPS() - stored procedure branch referred to field
fSqlText, which should have been aSqlText (worked ok anyway, in this case).
-
Change - DbUtil.isSuccess
now returns true only if arg > 0 (instead of only if != 0). This allows
more than one value to denote an error condition. For example, returning
-1 can now be used to indicate an error condition.
-
Bug Fix - Extended Pick Lists. Add/Change of a duplicate does not fail
as expected. Should have been checking the return value of the INSERT operation,
and then asking for rollback
-
Bug Fix - TxTemplate. Should have been catching DAOException, in addition
to SQLException. Important since SqlEditor can only throw a DAOException.
web4j.jar version 1.8.4 (Published September 4, 2005)
-
improve the look and feel, and use a robust cascading style sheet. Firefox
renders well. Internet Explorer 6 renders less well (especially the input
forms), since IE6 does not have robust support for CSS
-
allow multiple sql.properties files to be used, using a simple
naming convention - see Sql
-
change the level of almost all logging statements to conform with a more
typical style - CONFIG for startup, SEVERE for problems, FINE for debugging
-
change two CSS class names to lower case (HIGHLIGHT, ROW_HIGHLIGHT), simply
to match other class names
-
remove AddToppingsEtc.jsp, which was not being used
-
recommend the CSS empty-cells property instead of the ReportEmptyOrNull
workaround present in web.xml
web4j.jar version 1.8.3 (Published June 11, 2005)
The main addition to this version is Pick Lists. See MyPickListDAO
for an extended discussion of WEB4J's design for Pick Lists.
Add two items which model Pick Lists :
-
PickListValue.java
-
MyPickListTitle.java
Add two JSPs to allow an administrator to edit Pick Lists :
-
PickListSimple.jsp
-
PickListExtended.jsp
Add corresponding WebActions for such edits :
-
MyActionFetchPickList.java
-
MyActionEditExtendedPickList.java
-
MyActionEditSimplePickList.java,
Extensive changes to MyPickListDAO.java were needed, along with minor changes
to
-
MyPerson.java
-
ModelFromParams.java
-
AbstractRequestParser.java
-
ConvertColumToObject.java
-
sql.properties and CreateTable statements for Pick Lists
Other items included in this version :
-
Add WebUtil.java. Like Util.java, but specific to web. Move a method from
MyDestinationPage to this class ( the method which added a param to a URL).
Change that method to either append or add. Add TESTWebUtil JUnit class
for it as well.
-
Change the template method of AbstractStandardWebAction.java, to allow
errors to be added during doFailure, if desired, in the same way that success
messages can be added in doSuccess
-
Allow messages to survive a redirect when redirecting to a second WebAction.
Place errors and messages in session only if they have content. Change
AbstractWebAction.java, AppException.java.
-
Add Util.checkNumItemsInTypeSafeEnumeration, for catching common error
related to type safe enumerations
-
Change AbstractLocalTx to follow the style of SqlEditor, by catching duplicate
key errors explicitly
-
Change SqlFetcher.fetchValueObjects to return maps whose keys/values can
be swapped as desired
-
Change ModelCtorUtil.java to allow Model Objects to have multiple public
constructors
-
Add AlternatingRow tag to Report.jsp to improve legibility
-
Bug Fix : CONCAT and the || operator both return null if an argument
is null. Fix needed for Artist names.
-
Bug Fix : Report.jsp. Fix date format for Style 2 of report, from mm/dd/yyyy
to MM/dd/yyyy
-
Bug Fix : ModelFromParams.java was calling AbstractRequestParser.getRawParamValue,
and should have been calling getParamValue. This applies the proper filtering
to raw request param values.
web4j.jar version 1.8.2 (Published April 23, 2005)
-
Add StoredProcedureTemplate.java to reduce repeated code associated with
CallableStatements. Exercise in MyPersonDAO.java, for updating the
number of neurons for MyPersons.
-
Change Sql.java to allow '{call }' syntax, but treat only as PreparedStatement,
and return either a single ResultSet or a single update count. Reject the
{?= } syntax at load-time, since explicit return values are not supported
by this mechanism (Use StoredProcedureTemplate.java for most use cases
of stored procedures). Reject intersection of {0} style and stored procedures
: if operation is backed by a stored procedure, then the MessageFormat
style is not applicable. Exercise in MyPersonDAO.java.
-
Add DbConfig.java to carry all data related to database configuration,
and to decouple the data layer more effectively from the web server environment.
-
Change ConvertColumnToObject.java to add support for CLOB data.
-
Bug Fix : AbstractWebAction.hasExistingSession() had reversed logic. This
error was introduced in 1.8.0, and caused the logout mechanism to fail.
(Sorry about that.)
-
Re-implement the paging mechanism with ANSI-compliant SQL, without the
LIMIT keyword, which is not portable. Altered SqlFetcher.java by adding
limitRowsToRange. Altered MyMessageDAO.java to exercise the changes.
-
Change the name of "Configured Selection" to the more natural "Pick List".
MySelectionDAO.java => MyPickListDAO.java, with related changes to callers.
Add Oracle 9.2 as a second database example, in addition to MySQL. Provide
CREATE TABLE statements for Oracle, and a second version of the sql.properties
file. As an illustration, the issues encountered during the port were :
-
MyPerson table - 'Name' is an illegal identifier in Oracle, and was
changed to FullName
-
sql.properties - remove trailing semi-colons from all statements (done
for MySql as well)
-
sql.properties - Report queries - 'AS' aliases need to be quoted identifiers,
to avoid being converted to upper case by Oracle.
-
sql.properties - replace some functions FORMAT -> TO_CHAR, DATEFORMAT
-> TO_DATE, IF -> CASE (done for MySql as well), CONCAT (x,y,z) ->
||
-
sql.properties - LIMIT is not an Oracle (or ANSI) keyword
-
Oracle has no autoincrement feature - use sequence.nextval for some INSERTS
-
Sql.java - autogenerated keys are now indicated by a web.xml setting
-
SqlEditor.java - the error code for duplicate key is now in web.xml
web4j.jar version 1.8.1 (Published March 5, 2005)
-
Change the Data Access Object implementations to forgo the use of interfaces
altogether, in favor of simple concrete classes. This is much closer to
the style needed by the typical application, which only supports one database
at a time. (Remove all DAO interfaces, and MyDAOFactory.java. Change the
name of all MyXXXDAOSql classes to MyXXXDAO.)
-
Model classes are now permitted to have a no-argument constructor. Such
constructors are not used in web4j, but are now silently ignored, instead
of causing an exception. (Change ModelBuilder.java, ModelFromParams.java,
and MyPerson.java.)
-
Add ModelCtorUtil.java to eliminate code repetition.
-
In all JSPs, simplify the names of the custom tags from 'web4j' to 'w',
using the standard tag prefixing mechanism.
web4j.jar version 1.8.0 (Published Feb 5, 2005)
-
Add support for SqlEditor with no params. Edit sql.properties, SqlId, SqlEditor
gets new constructor. EditPerson.jsp gets new button, MyRequestParser.java
gets new branch. Add MyActionUpdateNumNeurons. Add updateNumNeurons method
to DAO interface and corresponding implementation.
-
Update the db driver in the example deployment from version 3.0.8 to version
3.0.16.
-
Add config of max rows, as safeguard against retrieving too many rows.
Add config of fetch size as well. Edit: web.xml, Sql.java
-
Improve class and method names, to use simpler, more natural language :
SelectorEditor -> FormPopulator, VOParserMatchOrder -> ModelBuilder,
SimpleVOParser -> ValueBuilder, VOException -> ModelCtorException,
VOFromParams -> ModelFromParams, AbstractVOParser -> RowToObject, SqlFetcher.fetchModelObject(s)
-> fetchObject(s). Now follows Martin Fowler's advice, and the term Value
Object has been replaced with Model Object.
-
Add ReportBuilder, a tool for quickly building reports, and exercise in
an example report. Add Report.jsp, MyReportDAO, MyReportDAOSql, ActionShowReport,
Formats.objectToTextForReport added. web.xml has new settings settings
as well
-
Add mechanism to save messages across a redirect. Add MessageList.java,
MessageListImpl.java. Edit DisplayErrors.jsp (rename DisplayMessages.jsp,
and move to Template.jsp), MyActionEditPerson.java, AppException.java,
AbstractStandardWebAction (no more returnToSender, different template adds
messages). AbstractWebAction has more liberal creation of sessions, in
part to allow messages to survive redirects.
-
Refactor WebAction ABC's. At the top are all final methods, while the abstract
subclasses are 'pure template'. Some changes to the templates themselves,
to accomodate the addition of messages.
-
Upon failure to load sql.properties, add message regarding line continuation
characters.
-
Allow SqlFetcher to use a shared connection, in a transaction. AbstractLocalTx
executeMultipleSqls can now throw DAOException as well as SQLException
as well.
-
Bug Fix : for ToStringUtil for factory methods which return objects of
the native class.
-
Bug Fix : MyActionDeleteUser.java must fetch Login Name from session
-
Bug Fix : Browse.do ServletError: if on page two, and page size is increased,
then '2 not in range 1..1'. Cause : HIDDEN item formerly constant, was
being dynamically pre-populated (since 1.7.0). Simple Fix : wrap only part
of the form, not its entirety, in the web4j:prePopulate tag. Edit Browse.jsp,
add comment to Prepopulate.java regarding partial forms.
web4j.jar version 1.7.3 (Published Dec 29,2004)
-
Template.jsp : added charset to head tag
-
bug fix : hidden form item in Browse.jsp should be outside the prepopulate
tag, since it needs a fixed, constant value.
-
bug fix : UpdateToppingsEtc.jsp was not rendering BigDecimals correctly
web4j.jar version 1.7.2 (Published Dec 26, 2004)
-
Add method addQueryParam to MyDestinationPage.java. Allows dynamic addition
of any number of query parameters to a destination URL, with proper escaping
of special characters. Demo in MyActionChangeAccount.java, with redirect
to view of user's most recent messages. This was needed since it is the
only way to pass data to a redirect URL.
-
Add Float and Long to list of supported types. Exercise with new items
related to MyPerson.java. Edits to VOFromParams.java, AbstractRequestParser.java,
Sql.java, and VOParserMatchOrder.java. (No simple way to add support for
primitives, since primitives do not model nullable columns well.)
-
Add SimpleVOParser.java, to collect simple, common implementations of AbstractVOParser.
Exercise SimpleVOParser.java in MyPersonDAOSql.java, and display result
using EditPerson.jsp and MyActionEditPerson.java.
-
Add ConvertColumnToObject.java, to centralize policies for translation
of ResultSet columns into supported objects.
-
Add Stopwatch timings to MyPersonDAOSql.java, to help evaluate typical
response times.
-
Add new config item: number of seconds which denotes a problematic delay
in processing. Using a Stopwatch, the Controller detects when the response
time has exceeded this configured limit, and emails the Webmaster with
a message stating how much time it has taken. The messages are throttled.
-
Change ToStringUtil.java to use all public no-argument methods with a return
value, instead of only getXXX methods
-
Remove the prepop of the search box item in EditPerson.jsp.
-
Create javadoc using JDK 1.5.
web4j.jar version 1.7.1 (Published Nov 8, 2004)
-
add EscapeChars.toDisableTags to escape only the start-of-tag and end-of-tag
characters. Use in MyMessage.java to correct bug in presentation of messages.
web4j.jar version 1.7.0 (Published Nov 7, 2004)
-
Add prepopulation support for two new controls : HIDDEN tags and TEXTAREA
tags
-
Add AbstractStandardWebAction, to explicitly capture two species of failure,
instead of one : invalid user input (common), and db failures due mostly
to multi-user nature (rather rare). Refactor most WebActions to use it
instead of AbstractValidatingWebAction
-
add Operation.java, to enumerate common datastore operations
-
Add AbstractStandardOpsWebAction.java, for case where common fetch, add,
change, and delete operations are handled by a single class
-
All database operations have been made "as atomic as possible". Check-for-existence
was code has been entirely removed, since it is not robust in a multi-user
environment. This resulted in a large number of small edits, both to DAOs
and the WebActions which use them.
-
SqlFetcher.java now returns null if no record is found, not SqlFetcher.NO_RECORDS
-
Add MyPerson.java, MyPersonDAO.java, MyPersonDAOSql.java, to allow wide
open exercising of toy data.
-
Bug fix : posting an empty message caused a NullPointerException. Amend
MyMessage.java, MyActionAddMessage.java
web4j.jar version 1.6.0 (Published October 10, 2004)
-
Amend README, and some initial config issues
-
Prepopulation : collapse the old 'add' and 'change' use cases into a single
'edit' use case, to handle the common case of using the same form for multiple
operations. Retain but deprecate the old use cases
-
Add Edit page : demo of handling all four operations (Fetch, Add, Change,
Delete) with a single JSP, a single WebAction, and a single DAO. Add EditPerson.jsp,
Operation.java, MyActionEditPerson.java.
-
MyDestinationPage.java - bug fix, call EscapeChars.forURL on title text
-
AbstractValidatingWebAction.java - overload the returnToSender method,
to handle a common case.
web4j.jar 1.5.0 (Published July 3, 2004)
Configurable Selection scheme for enumerated items
-
MySelectionDAO.java, MySelectionDAOSql.java
-
tables : MyPizzaTopping, MyArtist
-
demo - Register.jsp, UpdateAccount.jsp, UpdateTheories.jsp, UpdateToppings.jsp
Better support for multi-valued parameters, and demo thereof
-
add methods in AbstractRequestParser.java, and some refactoring
-
some edits to SelectorEditor.java
-
demo - UpdateToppingsEtc.jsp, MyToppingsEtc.java, MyActionFetchToppingsEtc.java,
MyActionUpdateToppingsEtc.java
Variation of MyUser to demonstrate 1..N relation
-
MyUserTheories.java
-
UpdateTheories.jsp
-
MyActionFetchTheories.java, MyActionUpdateTheories.java
-
MyUserTheoriesDAO.java, MyUserTheoriesDAOSql.java
AbstractRequestParser.java
-
much improved design for parsing request parameters into java objects and
Collections
Small changes
-
web.xml - added IgnorableParamValue
-
MyRequestParser.java - if no overrides of default base class implementations
are provided, will now have sole task of translating URL to WebAction
-
MyReqParam - call MySelectionDAO for regexes related to Configured
Selections
-
Formats.java - add objectToText method, to make the formatting policy for
objects rendered in forms more obvious
-
Bug fix - SelectorEditor.java for selects and null bean properties
web4j.jar 1.4.0 (Published May 15, 2004)
Large changes
-
added VOFromParams.java, a much improved method for constructing Value
Objects from request parameters.
-
possibly-null items now used in Value Objects
Medium changes
-
web.xml : new entries standardize formats used in forms.
-
Formats.java added.
-
Regex.java expanded.
Small changes
-
Fixed bug in SelectorEditor.java : user input containing regex symbols
('$', for example) was not properly escaped
-
MyUser.java has additional fields, to exercise new cases. Corresponding
changes to underlying table.
-
Util.java has new some new methods
web4j.jar 1.3.0 (Published Feb 21, 2004)
There is a single, large edit to this version. A browsing mechanism,
suitable for browsing a large result set interactively, using various sort,
filter, and page criteria, has been implemented.
Added :
-
Browse.jsp - browse pages of a large result set, with various criteria
-
MyActionBrowseMessages.java - fetch a single page of a large result set
-
AlternatingRow.java - tag for alternating table row color
-
PagingLinks.java - tag for navigating large result sets
-
EchoParser - experimental helper class for tags which edit their body
Edited :
-
Sql.java - add '{0}' style in addition to '?' style, to handle the case
where a dynamic SQL statement cannot be easily parameterized in the usual
way.
-
Prepopulate.java - new use case
-
MyMessageDAO.java and MyMessageDAOSql.java - add getNumPages and
browse
methods
-
MyRequestParser.java, MyReqParam.java, MyDestinationPage.java, Template.jsp,
and sql.properties - various small edits
web4j.jar 1.2.0 (Published Feb 03, 2004)
Large changes
-
Prepopulate custom tag entirely rewritten, and now much less restrictive
-
Updated: Prepopulate.java, Register.jsp, UpdateAccount.jsp
-
Added: SelectorEditor.java (helper class for Prepopulate.java)
Medium changes
-
MyRequestParser, MyActionAddUser, MyActionChangeAccount - removed code
duplication for parsing the SendCard and StarRating request params. Placed
in MyRequestParser, not AbstractRequestParser.
-
Regex class added to collect common regular expressions.
Small changes
-
MyActionFetchMessages - remove VOException import, add logging statement
-
Sql and MyUserDAOSql - illustrate alternate method of passing List of params
to Sql constructor, using Object[] and Arrays.asList. Especially useful
when there are a large number of parameters.
-
Template.jsp - removed misleading comment near footer
-
custom.tld - Updated inaccurate description of Prepopulate custom tag.
-
package.html (data package) - correct link to zip file
-
Login.jsp - removed extraneous slash at the end of <input> tags
web4j 1.1.1
This is the first version sold as a zip file.