Version 1.4b25 of 26-Sep-2008
- Added the
Form.getControlByIndexandForm.getControlByIndexAndNamemethods, for getting information about one control among many that share the same name. - Added the
FormDataSet.getActionURLandFormDataSet.setActionURLmethods. - Added the
Form.getAction,Form.getActionURL, andForm.getMethodmethods. - Added the
Form.getDataSet(IncludeSolitarySubmitControl)method for obtaining form data sets that optionally include the data (if any) provided by the form's "submit" button, provided that the form has only one "submit" button. - Added the
Form.getSubmitControlsmethod to return information about all of the "submit" controls in a form. - Modified the
Form.getControlValuesmethod to return values for graphical submit buttons ("input" controls of type "image"), when theIncludeSubmitControlsparameter istrue. The values returned for such controls are always two zeros ({ "0", "0" }). - Added two new
goodbyemethods:Qwicap.goodbye(String MIMEType, byte[] Data)andQwicap.goodbye(Downloadable). - Changed the "dialog box" pages that appear when a Qwicap application crashes, is supplied with obsolete parameters in the absence of a current session, etc. such that the "dialog box" will be "80ex" wide, rather than "60%" wide. This will give the dialogs a more reasonable appearance in very wide browser windows.
- Upgraded the Table library from version 1.0a45 to 1.0a46. The new version, by default, prevents tab characters from distorting tables by translating each one into as many as four spaces.
Version 1.4b24 of 7-Aug-2008
- Upgraded the Table library to version 1.0a45, which fixes a bug in its automatic storage unit formatter. Consequently, the Service Data Recorder's reports will no longer display the maximum size of the Java heap in Exabytes (EB). While the Exabyte value ("0.00 EB") included in the reports was correct, it was also thoroughly useless.
- Supplied some missing Javadocs for methods in the
FormDataSetclass. - Added the
FormControlValue.setValuesmethod, added theFormDataSet.setDatamethod, and improved theForm.getDataSetmethod. - Modified the code to use the new
ReadOnlyTableclass wherever possible, and made some other uses of the Table library more efficient.
Version 1.4b23 of 24-Jul-2008
- Corrected a bug in the internal
FormDataSet.getInputBytesmethod that could prevent some form data sets from being read completely. - Resolved floating-point precision issues in the
Qwicap.getFloatandQwicap.getDoublemethods. These methods have usedBigDecimalinternally for a long time, in order to deal with magnitude issues, but, until now, they had not used it in a way that also dealt with precision issues. - Replaced most uses of CSS pattern strings with pre-compiled, static
CSSPatternsobjects. This eliminates a lot of redundant CSS pattern parsing. - Added the missing
Match.get(CSSPatterns)method. - Removed obsolete code from the internal
ServiceDataclass. - Upgraded the "Table" library from version 1.0a39 to 1.0a42.
- Improved some logging messages.
Version 1.4b22 of 14-Jul-2008
- Upgraded the "Table" library from version 1.0a37 to 1.0a39.
- Various Javadoc improvements, including the documentation of the methods
of the interfaces in the "
edu.utexas.its.eis.tools.qwicap.template.xml.structure" package. - Removed the code (added in 1.4b21) for killing the MySQL JDBC driver's lingering
TimerTask, because killing that task didn't appear to make the web application'sClassLoaderany more likely to be garbage-collected. - Fixed an obscure bug in the internal
MatchEnumeratorclass that could cause aNullPointerExceptionto be thrown during someMatch.getTextinvocations. - Tweaks to the handling of namespaces in CSS selectors.
- CSS attribute selectors now support namespaces.
- Added two unit tests relating to operations on attribute names that include namespace prefixes.
- Corrected a bug in the internal
MuTagWithAttributesclass'toStringandwritemethods that could prevent the namespace prefix from being included in a tag's name when the markup is being handled in a namespace-aware manner. - Added two unit tests pertaining to the preservation of namespace prefixes in markup that's operating in a namespace-aware manner.
- Removed some obsolete "todo" items from the code. Removed old sections of commented-out code from various classes. Took advantage of terser syntax in some portions of the code.
- Improved the internal
TagHierarchyclass such that, when a namespace prefix on a tag's name cannot be resolved to a namespace declaration in the markup, the prefix ceases to be considered a namespace prefix and instead reverts to being considered a part of the tag's name. This prevents the prefix from being lost in some processes, notably the conversion of the tag from its immutable to its mutable form. - Changed the access control modifiers of the
QwicapServletmethodsdoGet,doHead, anddoPostto "protected".
Version 1.4b21 of 18-Jun-2008
- Corrected a mistake that would prevent a web application's
ClassLoaderfrom being garbage-collected. - The names of threads are now more descriptive, and a thread's name changes as its purpose changes.
- Corrected a bug that could cause a
NullPointerExceptionwhen rejecting bad input from a "form" element possessing an "input" control of type "submit" that has no name. - Corrected a bug that could corrupt the user's rejected input when that input was automatically embedded in the page from which it originated, so that the page could be sent back to the user for correction of the bad input.
- The
QwicapThreadPoolclass will now make a list-ditch effort to kill any lingering threads of classjava.util.TimerThreadthat it finds in its thread group. In practice, this problem arises due to a design issue in the MySQL JDBC driver, which creates a Timer named "MySQL Statement Cancellation Timer" that lingers even after all database connections have been closed. That lingering timer prevents the web application'sClassLoaderfrom being garbage-collected. - Added support for an experimental tool that monitors garbage collection
of
ClassLoaders associated with web applications. - Upgraded the "Table" library from version 1.0a36 to 1.0a37.
Version 1.4b20 of 3-Jun-2008
- Minor tweak to the private
geti18nServicesmethods of the classesResultsandSmartStringConverter. - Minor improvement of terminology in the Javadoc for the
Qwicap.getCurrrentInstancemethod.
Version 1.4b19 of 2-Jun-2008
- The portion of the
ClassPreloaderAndHolderclass that scans JARs in a web application for classes that need to be preloaded, now avoids trying to open some things that are obviously not JAR files, and recovers from arbitrary exceptions produced by theJarInputStreamclass. - Improvements to the implementation of the
geti18nServicesmethods of the classesResultsandSmartStringConverter. - Corrected an error in the Javadoc for the
Qwicap.getCurrrentInstancemethod. - Corrected a typographical error in a log message.
- Removed some old, commented-out code from various classes in the CSS package.
Version 1.4b18 of 22-Apr-2008
- Corrected a bug introduced into status reports in version 1.4b17.
That bug would cause the "Threads Total", "Threads Active", "Threads Inactive"
and "Threads Jammed" columns to display a range from
Integer.MAX_VALUEtoInteger.MIN_VALUEwhen no data was available. The correct behavior is to display "N/A" in such cases.
Version 1.4b17 of 21-Apr-2008
- When transmitting pages to clients,
IOExceptions, especiallySocketExceptions (usually reporting broken pipes caused by clients), are now handled by catching and logging them, rather than by catching, wrapping and re-throwing them. Depending on how a particular web application approaches its exception handling, this change can eliminate a cause of premature web application termination. - Disabled processing of Qwicap AJAX queries when Qwicap's AJAX support is disabled.
- Supplied the missing
Results.getDeclarationsmethod. - Classes that allow themselves to be enumerated now also implement the
Iterableinterface. Classes that implement theEnumerationinterface now also implement theIteratorinterface. - Upgraded the Table library from 1.0a32 to 1.0a36.
- Revised the
ServiceDataRecorderclass to populate the service data report tables with raw data (instead ofStringobjects) which is automatically formatted usingCellFormatters. This lays the groundwork for making the contents of Qwicap's status reports available programmatically. - Minor improvements to the Javadocs.
- The Ant build script for Qwicap, "build.xml", has been made more generic.
- Added Eclipse project files.
Version 1.4b16 of 16-Mar-2008
- Corrected bugs in the file upload code.
- Removed the Apache Commons File Upload library's source code from the Qwicap source tree. Instead, the File Upload library is included as a JAR, version 1.2.1, in the "lib/dist" directory. Also, updated the associated Apache Commons I/O library JAR to version 1.4.
Version 1.4b15 of 3-Mar-2008
- Further fine-tuning of the log messages associated with thread pool destruction, including the addition of a final report of any daemon threads that have resisted Qwicap's effort to persuade them to exit.
- Modified the
QwicapAbandonmentException.rethrowIfThisPageWasAbandoned(Throwable)method such that it will rethrowQwicapSessionDeathExceptionandQwicapSessionWillNotDieError, in addition to the various "abandonment" exceptions that it has always rethrown (when appropriate).
Version 1.4b14 of 3-Mar-2008
- Added code to the
MutableMarkupclass to detect the insertion, into one body of markup, of another body of markup that includes an XML declaration. Because there should be only one XML declaration in an XML document, and because it must be the very first item in the document, inappropriately located XML declarations are now omitted from the insert process (in the most common cases). - Made incident logging more elegant in cases where the incident forces the termination of a session of an application.
- Modified the thread pool shutdown log message to correct plural-related grammar issues when there was only one thread in the pool.
- The thread pool shutdown logging code now differentiates between daemon
and non-daemon threads in its thread descriptions, and only logs the stack
traces for daemon threads when the logging level is
FINEor lower. - After a Qwicap application's thread pool is destroyed, all lingering threads in its thread group are now interrupted. Such threads would have been created by code other than Qwicap, so they aren't Qwicap's direct responsibility, but testing shows that even daemon threads can persist across application deployments and can therefore create memory leaks. That's bad, so the interrupt operation has been added in the hope of inducing any such threads to stop in a timely manner.
Version 1.4b13 of 27-Feb-2008
As specified by RFC 3236, web pages transmitted by Qwicap are now identified with the MIME type "application/xhtml+xml" by default. (They used to be identified as "text/html".) However, if present, the "<meta http-equiv='Content-Type' content='...'/>" tag in an XHTML document's "head" section will be used to set the document's MIME type when it is transmitted, thereby overriding the default XHTML MIME type of "application/xhtml+xml".
By using the "application/xhtml+xml" MIME type, browsers will actually interpret XHTML documents as XHTML. Without it, they interpret XHTML as the usual HTML "tag soup". See "Sending XHTML as text/html Considered Harmful" for a discussion of this subject.
NOTE: Including a "<meta http-equiv='Content-Type' content='...'/>" tag in the "head" section of an XHTML (or HTML) document is a good practice, whether or not you want to override the document's MIME type. The reason is that the value of "Content-Type" can (and should) include a character set specification (for example: "application/xhtml+xml; charset=UTF-8"), which web servers in general (though not Qwicap) usually omit from the value of the HTTP "Content-Type" header. That omission leads to ambiguity in the interpretation of documents, which is bad by itself, but has also been shown to lead to security problems (see "Specify the output encoding").
- Corrected a bug in session tear-down that prevented some browsers from
retrieving
Downloadablesin the final page of a web application. - Added logic that prevents the submission of obsolete data sets (sets associated with pages leftover in a browser's cache/history) from automatically creating a new session when there is no current, valid session. In some browsers, in some situations, viewing a cached page whose URL includes a data set (AKA URI attributes, parameters, or a query string) causes that data set to be re-submitted to the web application. Qwicap has never allowed bad/obsolete data sets to reach its client applications, but it has been in the habit of starting a new session whenever a web application is hit in the absence of an existing session. Now, an obsolete data set sent to a Qwicap web application in the absence of an existing session causes Qwicap to prompt the user to decide whether or not they want to start the web application again.
- Adds user-friendly reports for two abnormal application exit cases: (1)
when the web application exits due to an exception, and (2) when the web
application exits without invoking one of the
Qwicap.goodbyemethods. In the first case, the exception is logged, but, for security reasons, no description of it is included in the web interface. Instead, an "incident code" is displayed. The code consists of the date, and a random number. The incident code is included in the log record for the exception, so the developer can easily match a user's problem report to a particular entry in a log file. Changed the error reporting mechanism of the
Qwicap.reportExceptionmethod such that, by default, it only shows high-security, opaque error reports ("incident codes"), and it no longer includes the stack traces for exceptions as comments in web pages. This change prevents information leakage that might aid attackers, and is therefore a very important change.However, that new, high-security behavior of
Qwicap.reportExceptionis less convenient for developers than the previous behavior, which was to display the exception's message as the user-visible error message, and to include the exception's stack trace as a comment in the web page source.To balance these concerns, the old, low-security/high-convenience behavior can be restored by creating a "context-param" named "qwicap-development-mode" with a value of "true" in your web application's "web.xml" file. It is anticipated that, if enabled at all, development mode will be disabled before applications are made available to their users.
- Added the
Qwicap.reportProblemmethod as an additional means of easily reporting errors to users. It differs fromQwicap.reportExceptionin that it cannot be used to report exceptions directly (and it should be used to report them indirectly only with caution, due to potential information leakage issues). Because of that limitation, its behavior does not have to change visibly when Qwicap is operating in its default, high-security mode. Therefore,Qwicap.reportProblemshould only be used to report errors whose messages have been reviewed to ensure that they do not reveal any information about the web application, its internal state, its underlying data stores, or anything else, that could aid an attacker in any way. - Internationalized some error messages in the
Qwicapclass that had previously been overlooked in the internationalization work. - Added to the Qwicap class the methods:
getBigDecimals,getBigIntegers,getDoubles,getLongs,getFloats, andgetInts. These new methods parallel the functionality of the pre-existing singular forms of those methods, but for controls with multiple values. - Added variants of the methods
toWWWFormURLEncodedStringandtoWWWFormURLEncodedBytesto theFormDataSetclass. These variants accept aURLAttributeSeparatorparameter. According to the relevant standards (RFC 1866, section 8.2.1, and the HTML 4 specification), the separator character can be either '&' or ';'. The semicolon character has the obvious benefit of not requiring encoding when placed in an HTML document. Ordinarily, this would be reason enough to always use the semicolon character, instead of the ampersand character, but—believe it or not—some web servers and/or CGIs don't support the relevant standards, and therefore don't recognize semicolons as URI attribute separators. So, when creating encoded data sets using theFormDataSetclass, you may now specify whether to use '&' or ';' as your attribute separator. Qwicap understands both. Other systems may not. - This version also attempts to provide a more consistent naming of methods
in the
FormDataSetclass (but doesn't necessarily succeed). - Reduced the
QwicapApplicationServicesclass to package-level access. - Extended the XML engine to support manipulation of CDATA, comments and declarations.
- The internal
CharacterSetFamilyUTF16class has been modified such that leading byte sequences that match UTF byte-order-marks (BOMs) are not removed from input data when further analysis of the data reveals that the input cannot be using one of the UTF-16 character encodings. - Gracefully handles the absence of certain basic character sets, like the EBCDIC family of character sets, which, evidently, are present in some Java distributions, but not others.
- Handles a
NoClassDefFoundErrorwhen using Qwicap's XML engine outside of a servlet environment. - Added some tests to
ResultsJUnit, and tweaked theResults.getBigIntegermethod. - Created the
QwicapBlockingListenerStatesclass to remove clutter from theQwicap.synchronizemethod by removing all of the code associated with notifying blocking listeners of blocking, holding their state while blocked, and then notifying the listeners when we unblock, returning their state to them when they are invoked. - Modified the
Form.actionRefersToThisWebAppmethod, and related code, to recognize the fact that "form" elements without "action" attributes nonetheless do submit their data sets to the current web application. - Modified the
Formclass to interpret lists of character sets in a form's "accept-charset" attribute. - Provided a much better implementation of the code responsible for adding the various "qwicap-" URI attributes to the URLs in a page, and, for the first time, it can also remove those URI attributes from the URLs in a page.
- Improved Qwicap's experimental AJAX features for visually reflecting the state of cached pages. The visual dimming effect used on pages that are no longer valid targets for user interaction is now clearer, cleaner and simpler. Also, the script now works in Safari and Firefox. Previously, it only worked correctly in Firefox. Internet Explorer compatibility is currently unknown. (These features, being experimental, remain disabled by default.)
- When the experimental AJAX features are enabled, and the user employs their browser's "back" button to return to an invalid page, they are presented with a dialog box informing them of the problem. That is not new. This is: If there is more than one valid page available from the web application at that time, they are presented with a pop-up menu of the valid page titles. Picking one takes the user directly to that page.
- Added code to prevent any scripts in the "onload" and "onunload" attributes of a page's "body" element from replacing Qwicap's own "onload" and "onunload" event handlers.
- Added encoding of single quote characters in URLs in order to prevent Javascript syntax corruption.
- Refactored all AJAX-related Java code into the
QwicapAJAXclass for neatness. - Added each web application's context path to many of the log messages that Qwicap produces in order to avoid confusion amongst log messages from multiple web applications on the same server.
- Eliminated a case in which a thread's session could be torn-down without freeing-up the thread for either future use, or garbage collection (depending on the thread pool settings).
In Tomcat versions 6.0.14 and 6.0.16 (and possibly many others), it has been observed that the re-deployment of a web application (but, oddly enough, not the shutdown of the Tomcat server) can trigger
NoClassDefFoundErrors during execution of the servlet'sdestroymethod. This appears to apply only to those classes that have not been loaded prior to the execution ofdestroy, but which are used by thedestroycode (directly or indirectly), and implies that the web application's class loader has been instructed to suspend class loading prior to the invocation ofdestroy.A means to change this behavior of the web application's class loader has not been identified. One workaround, however, is to force loading of the problematic classes before
destroyis invoked. TheQwicapServlet.initmethod, through use of the newClassPreloaderAndHolderclass, now performs such loading for several internal packages on which thedestroyimplementation depends, directly or indirectly. References to the loaded classes are retained by the servlet in order to ensure that they cannot be garbage-collected prior to servlet destruction.- When the
QwicapServlet.destroymethod is invoked, a more persistent thread shutdown algorithm is now employed, and, if all threads haven't shutdown after 30 seconds, the stack traces of the survivors are logged to aid in debugging. Also, warnings about applications exiting without invoking theQwicap.goodbyemethod are not shown when an application's thread was forcibly shutdown. - Corrected a problem in the thread pool implementation that left it unable to destroy a pool containing one or more threads that had not yet been started.
- Added a new last-ditch method for forcing a session to die, which is activated after a session has ignored a large number of coventional attempts to tell it to exit.
- Greatly increased the amount of information logged about "jammed" threads (assuming that such things still exist) by adding thread state and stack traces to the relevant log messages.
- To further ensure that the servlet destruction process is fully
understood, an instance-level concurrent execution counter has been
added to
QwicapServlet. The counter's value is logged when theQwicapServlet.destroymethod is entered, and again when it exits. If the counter is non-zero at exit, that would require some explaining. - Added a log message (level "INFO") announcing the invocation of the
QwicapServlet.destroymethod. (There was already a similar log message announcing the completion of thedestroymethod.) - Added to
QwicapThreadPool.destroya final check of the pool's thread group for active threads. It shouldn't be possible for there to be any at the point when this new code executes, but, if there were such threads, they would be worth knowing about. - Added more information to the log messages in the
QwicapThreadPool.destroymethod, including a tally of the states of all threads, in order to ensure that the pool shutdown process is fully understood. - Added a method to
QwicapThreadListto create a tally of the states of all threads in the list. - Removes a very small race condition in setting the "pool closed" flag during thread pool shutdown. It does not appear to have had any potential for negatively affecting the shutdown process. Nonetheless, the code is better-off without it.
- Improved comments in
QwicapThreadList, and eliminated some methods that are no longer used. - Revised the "build.xml" file such that it includes ".svn" directories in the project source zip file.
- Modified "build.xml" to automatically set the value of the
kQwicapVersionStrvariable in the "Qwicap.java" source file. As a result, the version number only has to be updated in one place, and the version string automatically includes a unique build number. - The "build.xml" file now provides a build step named "jar-without-libs" that builds a Qwicap JAR that does not include the various libraries in the project's "lib/dist" subdirectory. Qwicap still requires the presence of those libraries, so they'll have to be included in any project that uses Qwicap, but this library-free build of the Qwicap JAR makes it easier to avoid situations in which several libraries used in a project contain copies of the same library.
- Updated the internal "table" library.
- Javadoc additions and improvements.
Version 1.4b12 of 20-Nov-2007
- Re-enabled the
Qwicap.getStatusReport(boolean)method that had been disabled in version 1.4b11. However, the method had to be made an instance method, rather than a static method, due to the refactorings in version 1.4b11 that made it possible for Qwicap to maintain separate status information for multiple web applications when it is deployed as a shared library. - Added the static
Qwicap.getStatusReport(Class, boolean)method, so that a means remains by which status information can be obtained from Qwicap in contexts where no instance ofQwicapis available. The caller is required to pass in a reference to the class containing the web application's entry point (the "public static void main(String[])" method that Qwicap invokes to begin execution of the web application). The reference to the entry point class is required in order to determine which application's status should be returned. (In cases where Qwicap is deployed as a shared library, it may be maintaining status information for any number of web applications.) - Corrected a bug in the internationalization services discovery methods of
the
ResultsandMutableMarkupclasses. The bug could result in an exception being thrown, in some cases, when those classes were used outside of the context of a Qwicap web application. - The "Table" library, which is used internally by Qwicap to produce its status reports and many of its most informative logging messages, has been updated to the latest version.
Version 1.4b11 of 12-Nov-2007
- Adopted many Java 1.5-isms both internally, and in the public API.
- Qwicap can now operate within the default constraints of the Security Manager under Tomcat.
- Qwicap web applications can now run directly from their WAR files.
- Qwicap web applications that have traditionally only run in "unpacked" form, and have implicitly used direct file I/O to access their contents, can now run directly from their WAR files, without modification to their code.
- Major refactorings have been performed on
QwicapServletand the objects it creates and stores. The life-cycles of all of the static objects that were shared amongst servlets within the same class loader (with the exception of the random number generator) have been changed such that they are no longer shared. Instead, they are now specific to an instance ofQwicapServlet. Most notably, this means that thread pools are now servlet-specific, even when Qwicap is executed as a shared library. - The HTTP headers sent with all output have been adjusted to permit
client-side caching wherever possible. This reduces the number of requests not
only for static content in a web application, but for dynamically generated
Downloadableinstances. - The old
XMLCachehas been replaced by a general purpose document cache. TheXMLCacheclass remains in the library for the purpose of backward compatibility, but is now deprecated, and is omitted from the Javadocs. - Initial, and worst-case, sizes for the document and name caches are now programmatically determined based on an examination of the contents of each web application.
Qwicap.getDocument(String)will attempt to retrieve the specified document as a servlet container resource if the document name begins with a slash ('/') character. If the document name does not begin with a slash, an attempt is made to read it as a file. If that fails, a slash is added to the beginning of the name, and an attempt is made to retrieve it as a servlet container resource. (The outcome of this retrieval strategy is cached, so that future attempts to access the specified document will not have to repeat the aforementioned logic.)-
All invocations of the
Qwicap.getDocumentmethod, and all document requests made using the HTTP "GET" command, now automatically attempt to locate a version of the document that has been translated/localized in accordance with each user's localization preferences, as expressed in the HTTP "Accept-Language" header of their first request to the web application.Translated/localized versions of documents are expected to be stored in top-level directories within the web application. Those directories must be named after the language range from the "Accept-Language" header to which their translation/localization corresponds. In other words, if the "Accept-Language" header says that the user wants content localized for "en-gb", the appropriately localized versions of the web application's documents should be stored in a top-level directory named "en-gb" (lower case, with a hyphen separator).
Not all of the documents that make-up a web application require translation and/or localization. Therefore, Qwicap implements a search scheme that allows only the documents that require translation/localization to be duplicated, while others remain common to all languages/nations.
So, if a document named "mydoc.html" is requested directly by, or on behalf of, of a client whose preferred language is "en-gb", an attempt is made to retrieve the document "/en-gb/mydoc.html", then "/en/mydoc.html". If those attempts fail, the document search begins again in the directory containing the web application's default translation. If the default translation is "es-mx" (Mexican Spanish), the directory containing that translation will be named "es-mx (default)". (The postfix " (default)" marks a directory as the default translation.) Thus, the continuation of the search for the document "mydoc.html" would be: "/es-mx (default)/mydoc.html", "/es/mydoc.html", and, finally, "/mydoc.html".
The results of the search for each document translation/localization are cached, so the search is performed only once per document, per session of a web application. (Behind the session-specific search cache is an application-wide document cache, which not only caches documents that are found to exist, but caches the fact that other documents do not exist. This reduces the overhead of the searches that must be performed to populate the search caches.)
- Various user-visible items of text (input error messages, for example) that
were previously hard-coded into the various Qwicap classes are now stored in an
XML "properties" file. (The file is "Qwicap.properties.xml", which is built into
the Qwicap library as a resource in the "edu.utexas.its.eis.tools.qwicap.servlet"
package.) Web applications can override some, or all, of the values of items in
that file by providing a file of the same name in the same package. They can also
provide alternate translations, which will be used when they are appropriate to a
client's language preferences. (The same naming hierarchy scheme described for
ResourceBundle.getBundleis used, except that the extension of the files is ".properties.xml", instead of ".properties".) Web applications can also use this mechanism to isolate text in their own classes that will require translation/localization. They can access that isolated material by using the new methodQwicap.geti18nServicesForClass. - Added specific error messages for more input errors, and improved the text of many existing messages.
- Floating-point precision issues have been eliminated from the
Qwicap.getFloatandQwicap.getDoublemethods. - Integer magnitude issues have been eliminated from the
Qwicap.getIntandQwicap.getLongmethods. - Corrected an old bug in the
FormInputRejectionHelperclass that caused it to give-up too soon when searching the "form" elements in a page for a matching control. - Locale-specific decimal and grouping separators (for example "1,000,012.59" and "1.000.012,59", depending on your locale) are now acceptable in numeric input, and are used in error messages relating to that input.
- The
MutableMarkupclass has been modified such that it automatically recognizes the availability, or absence, of locale-specific services from Qwicap. In the former case, when insertingjava.util.Date,java.sql.Date,java.sql.Time, orCalendarobjects, string conversion is handled by formatters specific to the session's locale. In the latter case, things behave just as they always have - thetoStringmethod is invoked on the object, and whatever it returns is inserted into the markup. - The methods of the
Resultsclass that retrieve numbers from markup have been modified to use locale-specific services, when available, to parse those numbers. - Automatic character-set-awareness, including lie detection, is implemented for all inputs. Input may be encoded using ASCII-based character sets, EBCDIC-based character sets, UTF-8, UTF-16 (good luck finding a web browser that can construct UTF-16 input correctly, however), and any future character sets that Java elects to support.
- Corrected a failure to properly use Unicode byte-order-mark (BOM) information when examining markup.
- The
Context.getExistingResource(String)method has been added to simplify getting URLs for servlet container resources. It is based onjavax.servlet.ServletContext.getResource(String), but indicates that the requested resource is unavailable by throwing aFileNotFoundException, rather than by returning anullURL asServletContext.getResourcedoes. - Added user input de-bouncing. The problem typically arises from users accidentally clicking on a form's "submit" button more than once. Qwicap has never allowed such redundant input to reach its client applications, but it has been in the habit of showing a page navigation error message in response to redundant input, which has tended to confuse or annoy users. Redundant input is now specifically detected and silently discarded, so users get the outcomes they expect, without any indication that they accidentally submitted their input more than once.
- Automatic application URL clean-up. When POST requests whose URLs include query strings (suitable only to GET requests) are received, the browser is redirected to the "clean" version of the web application's URL, and processing of the original POST request proceeds normally, so the clean-up is transparent to the user.
- Using semicolons as synonyms for ampersands in the search portion of URLs, as suggested in RFC 1866, section 8.2.1, is now supported.
- Corrected a race condition in the tear-down of session context related to
the nulling of the reference to the associated
QwicapThreadinstance. - The rules associated with the "prompt pattern" have been relaxed in order to
allow more than one
promptinvocation within a particular implementation of the pattern. This is relevant, for example, when you want the prompt to include the previously submitted form data set in the page sent to the client in some cases, but not others, and therefore you need two different forms of thepromptinvocation (one for each case) within the same "prompt pattern" implementation. - The implementation of the
Downloadableclass has been improved. However, due to those improvements,Downloadableobjects are no longer instantiated directly. Instead, they are created by invoking the newQwicap.createDownloadablemethod. - The range of the random values that are incorporated into the URIs of
Downloadleinstances has been doubled to further ensure the uniqueness (statistically speaking) of those URIs. Also, those random values are now expressed in hexadecimal in order to reduce the length of the URIs. - The various, internal LRU caches now provide "discard" counters to track the number of items that have been removed from the caches.
- Many improvements to logging, primarily within the package "edu.utexas.its.eis.tools.qwicap.servlet". Setting the logging level to "FINE" will now provide extensive information about each hit.
- Removed a number of classes from the Javadocs that are not part of Qwicap's public API.
- Various Javadoc improvements.
Version 1.4b10 of 15-Jun-2007
- Resolves bugs in, and expands the functionality of, automatic character set detection.
- Corrects a bug associated with the new feature of
Auth2Schemeimplementations that allows them to force the destruction of a user's session. - Greatly increases the amount of information logged by the
QwicapServletclass, primarily at theFINESTlevel.
Version 1.4b9 of 31-May-2007
- The portions of Qwicap responsible for the reading and writing of XML and XHTML have been made character-set aware.
Version 1.4b8 of 22-May-2007
- Exception messages in the
MutableMarkupclass have been improved.
Version 1.4b7 of 17-May-2007
- The
Qwicap.reportExceptionmethod now logs the exception that is being reported (at the "WARNING" level). Previously, there was no logging in that method. The addition of logging greatly aids debugging when the exception being thrown is preventing the web application from reaching aQwicap.promptinvocation, and therefore is preventing Qwicap from ever reporting the exception.
Version 1.4b6 of 24-Apr-2007
- Corrected a bug in the
Hexadecimal.andASCIIFromBytesmethods (which are not a part of the public API, nor are they used by Qwicap) which could cause theOutOfMemoryErrorto be thrown due to a dramatic overestimation of the amount memory needed for the output buffer. The source of the problem was an operator precedence bug. This bug has no impact on Qwicap, but deserved to be fixed. - Changed the XHTML markup in the example applications such that the "meta" tags that specify "Content-Type" no longer include quotes around the "charset" value. Those quotes were causing Eclipse to choke.
- Changed the XHTML markup in the "guess" example application such that it is compliant with the XHTML 1.0 "Strict" specification, rather than the "Transitional" specification.
Version 1.4b5 of 18-Apr-2007
- Eliminated a case in
QwicapServletin whichHttpServletResponse.sendErrorwould throw anIllegalArgumentException, because anAuth2Schemeimplementation had refused access to the web application, and had already caused the response to be committed.QwicapServletnow invokessendErroronly when the response has not been committed.
Version 1.4b4 of 11-Apr-2007
- Corrected a stupid bug that prevented Qwicap's
SecureRandomservice provider from being accessed. Also corrected the associated Javadoc.
Version 1.4b3 of 10-Apr-2007
- Corrected a bug, introduced in version 1.4b2, that could cause a
NullPointerExceptionwhen rejecting the input from some form controls. JUnit tests have been added to ensure that this bug will not be re-introduced. - If the application server's security manager permits it, Qwicap's
"Rule 30" pseudo-random number generator (PRNG) implementation is made
available through the "Provider" mechanism of the
java.security.Securityclass. Thus, aSecureRandominstance which utilizes Qwicap's PRNG implementation, and which, by default, is seeded from Qwicap's internal instance of this PRNG, may be obtained by using the following invocation:SecureRandom.getInstance("Rule30", "Qwicap");. Note that this particular "rule 30" PRNG implementation has not been subjected to FIPS 140-2 compliance testing, though it has been subjected to similar tests, and other "rule 30" PRNG implementations appear to have satisfied FIPS 140-2 requirements.
Version 1.4b2 of 30-Mar-2007
- Upgraded the Jakarta Commons File Upload library from version 1.1.1 to 1.2, and the I/O library from 1.2 to 1.3.1.
- The
Hexadecimalutility class has been extended to support reading and writing of floating-point primitives, and the production of combined hexadecimal and ASCII representations ofbytearrays. The documentation has also been improved. QwicapServletnow overrides thetoStringmethod to provide an informative string.- The
CharactersandImRangeclasses now implement Java'sCharSequenceinterface.ImRangeis not part of Qwicap's public API, but this has implications for the public API: All pieces of immutable markup (tags, the whitespace outside of tags, individual attributes—everything) now support theCharSequenceinterface. If, for some reason, you want to take advantage of this fact, you'll have to determine that any givenRangeis immutable, by determining that it does not implement theMutableinterface. Then you'll have to typecast it toCharSequence. However, you can reliably assume that allRangeobjects in any instance ofImmutableMarkup(or any of its subclasses) are immutable without testing. - Added some defensive, and possibly unnecessary (but harmless), exception
handling to the
QwicapThreadPool.destroyAll,QwicapThreadPool.destroyOnly,QwicapThread.killThreadandQwicapServlet.destroymethods in order to ensure that servlet destruction is never interrupted. - Removed the
Qwicap.setInputFilter(FormDataSetFilter, boolean)method, which was created during the 1.4b2 development cycle, and added theQwicap.invokeInputFiltermethod as a much more elegant and readable means of dealing with the same problem. Also refined the handling of the data set that is on-hand whensetInputFilteris invoked. - After an invocation of
FormDataSetFilter, the data set (if any) that was sent with the current hit is filtered the next time an invocation of apromptmethod, or theredirectmethod, occurs, unlessinvokeInputFilteris used before then. - If, in the process of executing the actions specified by a
FormDataSetFilterResponse, aQwicapSessionDeathExceptionwas thrown, that exception would be caught and logged, rather than being allowed to propagate correctly. That has been fixed. - Deprecated the
Qwicap.rejectInput(String, Object, boolean, Object)method which, having been renamed fromrejectParameterlong ago, is a kludge leftover from the earliest days of Qwicap, before the distinction between strings and markup became apparent to me, and was properly embraced by the code. - Removed antique, deprecated "Parameter" methods from several classes,
notably the
Qwicap.rejectParametermethod. - Removed the
Qwicap.prompt(MutableMarkup, PromptFlags)method from the public API. It was a first attempt at solving a problem early in the version 1.4 development cycle, and has subsequently been solved more elegantly by theQwicap.prompt()method. Similarly, thePromptFlagsclass has been removed from the public API. - Added two methods to the
FormDataSetFilterResponseclass:clearandgoBackToFirstPage. - The
Form.addChoicemethod now throws anIllegalArgumentExceptionif the form does not contain a control of the specified name. - The
filtermethods of classes implementing theFormDataSetFilterinterface are now permitted to throwQwicapException. In fact, when they encounter such an exception, they are required to do so, because discarding such exceptions may prevent Qwicap from operating correctly. - The documents "Qwicap Introduction" and
"Comparison of Number Guess Implementations" have
been updated to use the new
Qwicap.promptmethod. Also updated both to assume that Java 1.5 is present, and therefore manual boxing of primitives is no longer required. (Qwicap itself continues to depend only on Java 1.4 features, however.) - The
Qwicap.prompt()method has been added, along with thePromptModifiersclass upon which it depends. This new method provides a much cleaner, and more readable, method of regulating the behavior of "prompt" operations than theQwicap.prompt(MutableMarkup, PromptFlags)method, which was created earlier in the version 1.4 development cycle. - Added the
Qwicap.showPageconvenience method for displaying non-interactive web pages whose input your code would ignore anyway. This is an alternative to thepromptmethod, and saves you the trouble of implementing the associated "prompt pattern". - Added
QwicapSessionAbandonedException, a non-public subclass of the publicQwicapAbandonmentExceptionclass, which is thrown when Qwicap detects that theQwicapSessionDeathExceptions it has been throwing, in an attempt to force the current session of a web application to shutdown, have been caught and thereby prevented from doing their jobs. Because of the Qwicap "prompt" pattern, this new exception is very likely to get through even in such cases. Unfortunately, without changing the "throws" declarations of a number of existing, publicQwicapmethods, this new exception can't be used everywhere thatQwicapSessionDeathExceptionis currently employed. - Added the
Null.orEmptyconvenience method. - Noticed that the documentation for
MutableMarkup.insertdoes not mention that it special-cases arrays andCollectionobjects such that "the contents will be interated through, with each element converted to a string, and commas inserted between elements. Whenever an element is found to be an array, or aCollection, the conversion process proceeds recursively, with the new material enclosed by brackets. (The elements ofbyteorBytearrays, will be displayed as unsigned decimal quantities. This seemed like it would be more useful to most developers than displaying signed quantities.)" This feature was documented in the Qwicap 1.2 change history, but it never made its way into the Javadocs. - Corrected a bug in
MutableMarkupthat could cause aNullPointerExceptionwhen inserting into the markup an array orCollectionthat includednullmembers. - The arrival of commands from Qwicap's experimental AJAX-style scripts no
longer causes the client application's (optional)
QwicapBlockingListenerto be invoked (twice) every time a command arrives. The client application should be oblivious to script command processing, so this is a useful change. - The
Qwicap.redirectmethod now acts on any input that arrives when the user returns to the web application from the redirect. This includes filtering the input, if aFormDataSetFilterhas been set. Previously,Qwicap.redirectignored input. - Added the convenience method
FormDataSet.notEmpty. - Fixed a significant bug in
Qwicap.addBlockingListenerand also improved it such that it will not add duplicate listener instances to its list. - Made public the constructors of the
FormDataSetclass. - Added the
FormDataSet.hasconvenience method. - Altered the
FormDataSetFilterinterface to simplify the parameters passed to thefiltermethod, and to include a new parameter of typeFormDataSetFilterContextwhich provides new information about the context in which the data set is being filtered. - Removed obsolete material from the
FormDataSetFilter.filterdocumentation. - It is now possible to use Qwicap in a shared library setup, for
example where Qwicap is installed in Tomcat's "shared/lib" directory,
instead of in each web application. To get around class loader
hierarchy problems, web applications intended to operate in such an
environment must subclass the
QwicapServletclass. See the documentation forQwicapServlet.init. - Found and corrected an ancient bug that caused "bad input" loops
if forms, or parameter-bearing links, were added to a page between an
invocation of
Qwicap.promptand the rejection of some of the input from that page. - Rejecting all input from a page no longer creates a log message at level "INFO". It now produces a log entry at level "FINE", just as rejecting a single input has done for some time.
- The service data recorder's hourly status reports are now logged at level "FINE", instead of "INFO".
Version 1.4b1 of 1-Mar-2007
- Filled-in some old gaps in the Javadoc, and made numerous improvements to the Javadoc markup throughout the classes of the public API.
- Added to the authentication & authorization (Auth2) system the ability to regulate access to the static content in a web application, independently of access to the application itself.
- Rearchitected the authentication & authorization
(Auth2) code.
The new implementation uses an
Auth2SchemeFactoryassociated with each servlet to produce anAuth2Schemeinstance (optionally associated with each session) which is used to authenticate & authorize each hit in a session. It returns to Qwicap anAuth2SchemeReplyinstance describing its conclusions, upon which Qwicap acts, restricting access to the web application and/or its static content accordingly. The client application may retrieve the current reply object by using the newQwicap.getAuth2SchemeReplymethod. (The oldQwicap.getAuth2Schememethod has been discontinued.) - Modified a number of core classes to reflect a better understanding
of servlet life cycles. This cleaned-up the code in a number of places,
and outright eliminated the need for the internal
QwicapContextclass. - Simplified the web application deployment descriptor (the "web.xml"
file) by eliminating the need to specify
edu.utexas.its.eis.tools.qwicap.servlet.QwicapContextas a "listener". Revised the Deployment Descriptor documentation accordingly. (Web applications using previous versions of Qwicap 1.4 will need to remove that "listener" specification from their "web.xml" files.) - Added several new methods to the
Resultsclass:getAttribute,everyNth, andIF_NOT_EMPTY.
Version 1.4b0 of 9-Feb-2007
- Corrected the handling of newline ('\n') characters within the content of HTML "textarea" tags. Previous versions of 1.4 had replaced those newlines with "br" tags, which was incorrect. Newlines in "textarea" tags are now left as they are; they are not encoded. In this respect, "pre" and "textarea" tags are now handled identically.
- Added a few more JUnit tests, and improved a few others.
- Added the
Qwicap.getRandommethod to make available to client applications Qwicap's internal pseduo-random number generator instance. - Updated the "guess" and "wumpus" example applications to use the
Qwicap.getRandommethod. Also, removed the "wumpus" application's dependence on the "servlet.jar" library file, and duly removed that file from the distribution. - Corrected a bug that may have caused Qwicap to interfere with normal Tomcat shutdown.
- It is no longer necessary to include the "qwicap.css" style sheet in Qwicap applications. Qwicap will now supply that document automatically. However, it remains necessary for an application's style sheet(s) to import the "qwicap.css" style sheet, unless it overrides all of Qwicap's styles. Applications may still override the default Qwicap styles in their own style sheets, of course, and may outright replace the default "qwicap.css" style sheet, if they prefer, by providing a document of the same name in the application's top-level directory.
- Various Javadoc improvements, chiefly in classes that are not part of Qwicap's public API.
- Corrected an error in a Javadoc block and in a separate comment
in the
QwicapServletclass. The word "send" in both cases had been transformed into "sendFile" due to some overzealous refactoring in the distant past. These corrections have no functional significance, but do make a little bit of the documentation more comprehensible.
Version 1.4a42 of 11-Dec-2006
- Tests indicate that the last, elusive race condition associated with interrupted hits (think of a user clicking on a submit button twice, before the first hit has been fully processed) has been removed.
- Revised the Qwicap Deployment Descriptors document for version 1.4a42.
The internal
ServiceDataRecorderclass now emits the data it has gathered via aLogger. It does this the first time something happens each hour (logged at theINFOlevel), and whenever the active session count drops to zero (logged atFINE). The same data can be obtained as aStringobject using the newQwicap.getStatusReportmethods. An API for programmatically accessing this highly changeable data has not yet been defined, because I am hesitant to commit to what data will be gathered, how it will be represented, etc. At the moment, no more than 72 hours of data, in one hour units, is retained (and reported) at any given time. Currently, the data is reported like this:+---------+---------+----------+-----------+---------+------------+-----------+----------+----------------+--------+------+------------------+---------------+------------------+----------+ | Pool | Threads | Threads | Threads | Threads | Threads | Sessions | Sessions | Session Length | Hits | Hits | Hit Runtime | RAM Free MB | RAM Used MB | RAM | | Size | Active | Inactive | Born/Died | Jammed | Unvailable | Completed | Expired | Min/Avg/Max s. | Total | Bad | Min/Avg/Max ms. | Min/Avg/Max | Min/Avg/Max | Total MB | +------------------+---------+---------+----------+-----------+---------+------------+-----------+----------+----------------+--------+------+------------------+---------------+------------------+----------+ | 2006-10-20 05 PM | 0-200 | 0-200 | 0-200 | 200/0 | 0 | 0 | 2,011 | 0 | 0.8/39.6/145.3 | 63,939 | 0 | 1.0/21.0/6,651.0 | 0.4/21.7/48.8 | 31.7/89.0/89.9 | 395.6 | | 2006-10-20 06 PM | 200-300 | 0-300 | 0-300 | 100/0 | 0 | 0 | 3,008 | 0 | 0.6/47.6/187.4 | 94,267 | 0 | 0.0/15.5/3,407.0 | 0.4/27.3/66.3 | 89.9/103.2/115.3 | 395.6 | +------------------+---------+---------+----------+-----------+---------+------------+-----------+----------+----------------+--------+------+------------------+---------------+------------------+----------+
- The size of the stack used by Qwicap's pooled threads can now be
configured in the web application deployment descriptor file ("web.xml").
A size of zero causes the platform's default thread stack size to be
used. Any other value is offered to the platform as a suggestion for
a thread's stack size. (That's just how the
Threadclass works; it's not up to me.) In general, I think setting the stack size is only appropriate as a server-specific deployment optimization, and web applications should ship with the stack size set to zero so that each platform's (presumably safe) default size will be used. HTMLEntityCodechas been simplified by eliminating support for the modes in which unprintable characters were omitted, or translated to hex.- Qwicap now gets all of its threads from a thread pool. The thread pool is configured in the web application deployment descriptor ("web.xml" file). The thread pool, and the individual threads, have been heavily instrumented to gather data about pool utilization, thread performance, memory usage, etc.
- The concept of "blocking listeners" has been added to Qwicap. Such
listeners, registered using the new
Qwicap.addBlockingListenermethod, are invoked just before and after Qwicap blocks to wait for user activity. This applies to thepromptmethods, and theredirectmethod, and will apply to any future blocking methods. Thus a "blocking listener" can perform actions like releasing and reacquiring limited resources like database connections, or log application activity, transparently from the perspective of a web application's code. - The code responsible for inserting strings into XHTML markup now examines the context into which the strings are being inserted. If they are inserted into pre tags, Qwicap 1.4's usual practice of encoding new-line characters as br tags is disabled.
Version 1.4a37 of 26-Jun-2006
- Deprecated all of the
Qwicap.prompt*methods except forQwicap.prompt(MutableMarkup). The functionality represented by the other variants of thepromptmethod is now supplied by theQwicap.prompt(MutableMarkup, PromptFlags)method. The newPromptFlagsclass is the means by which the various optional behaviors associated with prompting, and rejecting input, are configured. This change eliminates the growing variety ofpromptmethods, allows configuration that wasn't previously possible, and provides some future-proofing to the Qwicap API. - When the user clicked on a web page, then clicked on it again before
the page from the previous click had loaded, Qwicap was encountering an
error caused by it being too careful about checking errors when
writing pages to clients. So, Qwicap no longer invokes
checkErroron thePrintWriterobjects it uses to write pages to clients, and therefore is no longer bothered by the client-side of connections being closed prematurely. - Fixed a problem which could leave servlet threads waiting to interact with dead Qwicap threads.
- Removed the
mainmethod from theArrayToStringclass. It was leftover from testing.
Version 1.4a34 of 18-Jun-2006
- Reworked the servlet-specific session attribute naming code, and
introduced the
getSessionAttribute,setSessionAttribute, andremoveSessionAttributemethods to theContextclass. - When adding duplicate choices using
Form.addChoice, the pre-existing choices that are made redundant by the additions are removed from the form. - Provided a helpful error message when
Qwicap.getCurrentInstanceis invoked in a situation where there is no current instance ofQwicap. The automatic web application entry point discovery code, which searches all of a web application's classes for a "
public static void main(String[])" method to use as the application's initial entry point, was provokingNoClassDefFoundErrors when it examined classes that included references to missing classes. In some cases this was just revealing errors that were going to happen on their own in short order. In other cases, however, it was revealing errors that wouldn't have arisen, because the classes with unsatisfied links weren't going to be touched explicity, or implicity, by the web application. While it was simple enough to catch those errors, doing so sometimes seemed to leave the class loader, or some other part of the runtime environment, in an unstable state.In order to avoid those problems, Qwicap now has its own class file parser, so that it can examine classes without use of a class loader, or reflection. The parser also gives Qwicap the ability to examine the dependencies of the classes it is considering using as entry points, so that it can select a class which not only has a "
public static void main(String[])" method, but one that uses theedu.utexas.its.eis.tools.qwicap.servlet.Qwicapclass, as well. This should eliminate some cases where Qwicap couldn't narrow down the set of available entry points to a single, definitely-correct choice, and therefore had to give-up and throw an exception.- Fixed a concurrency-related bug in the context management code.
- Version 1.1.1 of the Jakarta Commons FileUpload library (less the portlet-oriented classes) has been incorporated into Qwicap, replacing version 1.0. (Also, because the new FileUpload library depends on it, the Commons IO library is included, though Qwicap, itself, doesn't make use of it.)
- Removed some logging that was leftover from previous testing and debugging work.
- One more way of confusing Qwicap by replacing sections of page markup
that contain active form elements has been eliminated, and
a
NullPointerExceptionalong with it. - Extended support, to all relevant control types, for multiple occurrences of single-value form controls with the same names in the same form.
- It is now much harder to confuse Qwicap by replacing the sections of
page markup that contain active form elements. If you do
find a way to confuse Qwicap in this manner, a
FormNotFoundExceptionis thrown with a message that will state the nature of the problem clearly. - The code for building comments in markup (currently used only to add strack traces to exception reports) is more conformant with the XML specification in that: (1) Sequences of two dashes ("--") are removed from comment text (they are replaced with "—" which describes the omitted material correctly, even though character entities aren't interpreted in comments). (2) Control characters other than 0x09, 0x0A and 0x0D are removed from comment text. (3) HTML entity encoding is no longer performed on comment text.
- Page navigation error reports are now removed from pages immediately after they are transmitted to a client for the first time. Consequently, the client sees any particular page navigation error report only once, even if they reload the page. This eliminates a behavior that could sometimes seem like nagging.
- Corrected a bug that resulted in the Unicode characters 0x201C and 0x201D being included in most Qwicap error messages, rather than the HTML entities that represent them ("“" and "”").
- Back-to-back input processing failures (obscure failures to load mutlipart form data sets) would result in multiple copies of the associated error message appearing in the page sent to the client. This has been fixed.
- Corrected a sign-extension related bug in
Hexadecimal.fromByte. - Attempts to reject a form control that does not actually exist in the current form now cause an exception to be thrown with an error message that specifically describes this problem. In the past, a more general error message was used, and it was too general to help developers identify this problem. The general error message, used in other cases, has also been made significantly more informative.
- Corrected a bug in reporting some obscure form input processing failures that prevented the relevant style in "qwicap.css" from applying to the error message inserted into the page.
- Improved the manner in which servlet threads and Qwicap threads synchronize.
Also, some unnecessary synchronization in the
Qwicapclass was eliminated. - Added the ability to specify a class that can pre-process all input
received from the client machine, before Qwicap acts on it, or passes it
along to the client application. See the
FormDataSetFilterinterface. - Added the
Qwicap.rejectInput(Object)method to allow all of the input from a "form" element to be non-specifically rejected. - Because we ran into the problem of
SecureRandomintermittently throwing ajava.security.ProviderExceptionwith the error message "Could not obtain session" when running under Solaris, and because it was a while before we realized there were patches to Solaris that correct that problem, Qwicap no longer uses theSecureRandomclass. Instead, Qwicap now has its own pseudo-random number generator (PRNG), inspired by Wolfram's use of the rule 30 cellular automaton as a random number generator in Mathematica. Now that we've gotten to the bottom of the Solaris bugs, Qwicap could resume use ofSecureRandom, but, according to Wolfram's analyses, the Rule 30 PRNG should be stronger than other PRNGs. Form.setDataSetwill no longer try to embed values in "input" controls of type "submit".- Added the
Match.hasAttributeOfValuemethod. - Added the
Qwicap.goodbye(String)method, which accepts a URL as a string, and redirects the client to that page while shutting down the Qwicap application. - Added the
Qwicap.redirectmethod, which redirects the client to an external web page (one that, typically, isn't part of the web application that's performing the redirect), and blocks until the client returns to this web application. Added the ability to control whether or not the
Qwicap.rejectInputmethod places quotes around the rejected control's label and value. By default, both are quoted. However, if you add the class "qwicap-no-quotes" to the element marked with the class "qwicap-label-text" in your error message markup, the label string will not be quoted. Similarly, if the class "qwicap-no-quotes" is added to the element marked with the class "qwicap-param-value", the value string will not be quoted.For example, your error message markup that once read as follows:
The input <span class='qwicap-param-value'></span> is not a valid value for the field <span class='qwicap-label-text'></span>. Please fix it.
...could be prevented from quoting the control label and value by changing it to the following:
The input <span class='qwicap-param-value qwicap-no-quotes'></span> is not a valid value for the field <span class='qwicap-label-text qwicap-no-quotes'></span>. Please fix it.- Added the
Match.hasClassmethod. - Made the Javadoc for the various flavors of
Qwicap.rejectInputmore consistent, and eliminated some typographical errors. - Eliminated the possibility of a
ClassCastExceptionin the methods that modify tag attributes when invoked on material other than start tags and empty tags. - Added the
Results.getBooleanmethod.
Version 1.4a12 of 22-Feb-2006
- Corrected a bug in
Results.ELSEand added JUnit tests for all combinations ofIF/ELSE/ENDIFinvocations, so there won't be any more bugs like it in the future. - Downloadables weren't being downloaded when their URIs included encoded characters, e.g. %20. This has been fixed.
- When a downloadable requested by a client could not be found, no error report was returned to the client. This has been fixed. The client will now receive an HTTP 404 error, and an explanatory message.
FormDataSet.printnow produces easier-to-read output, with control names and values arranged in columns. Also, the output is sorted by control name.- Javadoc improvements.
Version 1.4a10 of 7-Feb-2006
- Optimizations to the
MutableMarkupclass' internal list insertion code and related methods. - Corrected a set of namespace-related bugs in
MutableMarkupandImmutableMarkup. The fixes required that thesetNamespacemethod be removed from theNamedIteminterface, access to theImNamedItem.setNamespacemethod be reduced from public to "package", theImNamedItemclass be made "public" (it shouldn't be public, but it must be accessed across package boundaries, so there's no choice), and the addition of aclone(Namespace)method toImNamedItemin order to create copies of immutable markup elements in different namespaces than the originals (the new objects continue to share the same immutable backing store as the originals). MutableMarkup.clonenow produces a newMutableMarkupwhich cannot be affected by changes to the original object, and vice versa. The previouscloneimplementation only offered partial protection from such changes.- Optimizations added to the conversion of
MutableMarkuptoImmutableMarkup. - Removed the static member
HTMLfrom the public API ofMutableMarkup. It may still be used, however, through the newhtmlEncodeandhtmlDecodestatic methods. - Changed the configuration of the
HTMLEntityCodecobjects used byQwicapandMutableMarkupsuch that newline characters ('\n') are encoded as "<br/>", rather than being omitted, which has been the behavior until now. Note that this does NOT affect the manner in whichMutableMarkupencodes attribute values; newlines continue to be omitted from attribute values. - Removed the
Pageclass from the public API. It was never meant to be in the public API, but as long as theFormclass depended on it, it couldn't be hidden. That dependence has been eliminated, soPagewill never clutter the API documentation again. - The
Formclass no longer depends upon thePageclass. It works just as before, except that thesetFormDataSet()method is no longer available. (The methodssetFormDataSet(FormDataSet)andsetFormDataSet(HttpServletRequest)remain.) - Deprecated the
MutableMarkup.embedParametersandMutableMarkup.embedParametersIfPossiblemethods. They are replaced byMutableMarkup.embedFormDataSetandMutableMarkup.embedFormDataSetIfPossible, respectively. This brings the method names more in line with official W3C nomenclature. - Removed an old optimization from the page stack maintenance code, because I finally found a case where it produced undesirable results.
- Added the
Qwicap.printPageStackmethod as an aid to debugging and/or understanding Qwicap's page stack and the way in which it is automatically maintained. - Corrected a bug that arose while setting the value of an XML
attribute to
null. - Added
getBigIntegerandgetBigDecimalmethods to the classesQwicapandResults. - The
Form.setControlValuemethods now examine the value object to determine whether or not it is an array. If not, the methods behave as they always have. If so, and the specified control is a multi-value control, the control is given all of the values listed in the array. The array may be of any type. ThetoStringmethod will be invoked on each of its elements. - Extended the functionality of the
Formclass by adding (or exposing) static methods that represent all of the class' key functionality, but that operate on a single control identified by aMatchobject. This makes the functionality of theFormclass available in situations where you do not wish to operate on an entire form, or in which you are producing or modifying the markup for control elements outside of a "form" element. - Added a number of
enableControlsmethods to theFormclass to achieve symmetry with the existingdisableControlsmethods. - Finally implemented the full functionality originally intended
for the
Form.addToControlValuemethod. It used to handle adding values to the multi-value controls ("select" and checkboxes), and did reasonable things to radio buttons, but wasn't useful for much else. Now it will handle most other types of controls by appending the supplied value to the existing control values. An obscure operation, in my experience, but it allows the method to "do what it says" no matter what sort of control it encounters, and there's value in that sort of consistency. - Corrected recurring HTML syntax errors in the Javadoc for the
ResultsandFormclasses. - Added the convenience methods
addFirstChoiceandaddLastChoiceto theFormclass. These are the same as invoking the pre-existingaddChoicemethod with itsInsertBeforeparameter set totrueandfalse, respectively. - The method
Form.addChoiceused to assume that there was only one control (or group of controls, in the case of radio buttons and checkboxes) with the specified name in any given form. It has been updated to handle the case where there are several, and to add the new choice to each of them. Unfortunately, this only works with "select" controls, because radio buttons and checkboxes lack any enclosing element that would make it possible for groups to be individuated. - Corrected a bug in
ImmutableMarkup(MutableMarkup)that allowed namespace information to be lost when converting mutable elements into immutable elements. - Immutable documents created using
ImmutableMarkup(MutableMarkup)now inherit the names of the mutable documents from which they were created. - In order to maintain consistency with the
Resultsclass, the methodMatch.insert(boolean, Object)has been deprecated, and replaced withadd(boolean, Object). Work on method name consistency and readability in the
Resultsclass:Deprecated Replacement insert(boolean, Object)add(boolean, Object)insertBeforeaddBeforeinsertAfteraddAfteraddContentBeforeaddToStartOfContentaddContentAtStartaddToStartOfContentaddContentAfteraddToEndOfContentaddContentAtEndaddToEndOfContentadd(Match)addMatch(Match)add(Results)addResults(Results)addTo(Results)addToResults(Results)- Added
getFloat,getInt,getShort, andgetBytemethods to theResultsclass. - Added
cutandcopymethods to theResultsclass. - The methods
Results.extractandResults.extractToMarkupnow set the name of the new markup object they produce. The name will read Derivative of "Original Markup Name", where "Original Markup Name" is the name of the markup from which the new markup was extracted. This is identical to the behavior of thetoMarkupmethod, which has always behaved in this way. - Improved the error message in
MutableMatch.check, which was already one of the longest and most detailed in all of Qwicap. - The
FormControlValueclass now implements theComparableinterface, and provideshashCodeandequalsmethods. All of these methods operate on the name of the form control, and not the value. - Added the
get(Pattern),getValue(Pattern), andhasControlNamesMatching(Pattern)methods to theFormDataSetclass. Form.createChoicenow encodes the values of the attributes in the markup it produces. This also benefitsForm.addChoice, which usescreateChoice.FormDataSet.hasParameterNamesStartingWithhas been deprecated and replaced withFormDataSet.hasControlNamesStartingWith, which is more consistent with official W3C nomenclature.Match.printnow returns a reference to the instance ofMatchon which the method was invoked.- Eliminated more unused methods, and removed more constructors and methods from the public API.
- Corrected some omissions in the Javadoc class description for the
Qwicapclass.
Version 1.4a6 of 24-Jan-2006
- Added the
Qwicap.promptCompletemethod. This method allows a method that displays a page (by implementing the "prompt" pattern for it) to explicitly inform Qwicap when it has finished with the page. Qwicap then regards the page as dead, and knows to ignore input from cached copies of it. Frequently, it is isn't necessary to invoke this method, because Qwicap will automatically figure-out that a page is dead if its supporting method (the one that implemented the "prompt" pattern for it) has exited before the next invocation of one of the "prompt" methods. Nonetheless, there are situations where the automatic dead page detection is not sufficient, and this method will let you disambiguate those situations. Failure to use this method when it is necessary can lead to some sub-optimal page management, but won't lead to a crisis, so think of this method as a page navigation optimization, rather than a necessity. - Corrected a bug that sometimes allowed pages that were not "in play" to remain on the page stack, which permitted Qwicap to operate under the delusion that such pages actually were still "in play". An attempt by a user to go back to such a page would cause Qwicap to discard all pages on the stack, effectively terminating the application.
- Added support for "modal" pages. (Pages that represent a mode in
the application, and which therefore cannot be abandoned using a
browser's "back" button. This is directly analagous to modal dialogs
in GUIs, which demand that the user interact with them before the user
is once again allowed to interact with any other part of the application.)
Support for modal pages takes the form of a new "prompt" method, named
promptModalSynch, in theQwicapclass. It works exactly like the previouspromptmethods, but causes the page it displays to be treated in a modal manner. For consistency, thepromptModelessSynchmethod has been added so that applications can make explicit their choice to use modeless pages. The existingpromptmethods remain, and are considered synonymous withpromptModelessSynch. - Page navigation errors are now explained to the user. Attempts to go back to pages that are no longer "in play" (their implementing method is no longer in the call chain), and attempts to go back to pages that precede a modal page, cause explanatory error messages to be displayed. Previous versions correctly diagnosed and responded to navigation errors, but did not explain the situation to the user, which could cause confusion. In order for these errors to be displayed correctly, applications must replace their old copies of the "qwicap.css" style sheet with the new one supplied in this release.
- Removed unused methods from several classes.
- Removed unnecessary synchronization on the
Qwicap.promptmethods. - The constructors in the
QwicapAbandonmentExceptionclass have been removed from Qwicap's public API, and an unused constructor has been removed entirely. - The constructor for the
QwicapSessionDeathExceptionclass have been removed from Qwicap's public API. - More methods in the
Pageclass have been hidden. Updated the Javadocs to explain thatPageis not part of Qwicap's public API.
Version 1.4a4 of 8-Jan-2006
- Various improvements to the Javadocs.
- Added the
Qwicap.getFloatmethod, for retrievingfloatprimitives from user input. This is slightly preferable to the past practice of usinggetDoubleand typecasting the result tofloat. - The
Downloadableclass has been exposed in the public API, because it is a convenient wrapper for the information triplet representing any downloadable item (name, MIME type, and content bytes). Note thatDownloadable.toStringreturns the unique URI assigned to the downloadable, which means that aDownloadablecan be passed directly toResults.setAttribute, when creating the link to the downloadable. - The various attribute manipulation methods in the
Resultsclass (and all of the lower-level classes on which it builds) now accept arbitrary objects as the values of attributes. The ultimate value of an attribute is whatever the specified object'stoStringmethod returns. If the specified object is actuallynull, the value of the attribute is empty, e.g. "... myattr='' ...". QwicapSessionDeathExceptions now come with messages specifying the reason the session died, or is dying.- The
Qwicap.goodbyemethod now initiates the shutdown of Qwicap and its client application. Previously, it was up to the the client application to shutdown in a graceful manner. This new behavior should force applications to do the right thing, by depriving them of the use of allQwicapmethods for prompting, retrieving input, etc. - Removed some unnecessary, old code from the
Qwicapclass. - Eliminated a race condition that could occur as a Qwicap application exits.
- Many more revisions to the "Hunt The Wumpus" demonstration application. Bugs in the game have been removed, features have been added, and, more significantly, a configuration page has been added which demonstrates more Qwicap functionality.
Version 1.4a0 of 1-Jan-2006
- Dramatically revised the "Hunt The Wumpus" demonstration web application. It now presents the cave map graphically—including such state information as your present location, and which rooms you've visited in the past—using dynamically generated JPEGs. Users indicate their moves by clicking on the map image which is dynamically marked-up as a client-side image map. Shooting arrows is now a single-click operation. These changes make game play dramatically faster and easier - almost too easy, but that's the virtue of a good interface.
- Changed the algorithm for producing the URIs of downloadables, in order to work-around the problems created by Internet Explorer for Mac (and, one assumes, Windows) being unable to recognize and/or comprehend HTTP cache-control directives.
- Improved the documentation for
Qwicap.convertSubmitButtonsToInputs, which is a work-around for the hideous bugs in the "button" element handling code of Internet Explorer (Mac and Windows). - Improved the error messages produced by the XML tag hierarchy validation code such that all of them specify the name of the document in which the error was found, provided that the XML came from a document with a known name.
- Added support for links that supply parameters ("a href" and "area href", so far). Previously, Qwicap only accepted parameters from controls in forms. [Dear W3C, Can a set of parameters be called a "form data set" when they don't originate from a form?]
- Removed the constructor of the
Contextclass from the public API. Also removed from the public API the following methods:go,getSessionContextCount, andclose. Client code has no need for those. - Removed the method
Context.getfrom the public API. Client code that wants access to the currentContextobject has always been able to get it usingQwicap.getContext. - Documented the
Context.getFileandContext.getExistingFilemethods. - Deprecated the
Results.addContentBeforeandResults.addContentAftermethods, in favor of the newResults.addContentToStartandResults.addContentToEndmethods, respectively. The new methods accept exactly the same parameters as the methods they replace, the only differences are the (hopefully) more comprehensible names. - All subclasses of
Markupnow havegetMutableandgetImmutablemethods. If a markup object is already in the requested state, the methods do nothing, and return a reference to that object. If the markup object is in the opposite state, a copy is created in the requested state, and that is returned. - Added support for dynamically-generated downloadable files. Just
produce the contents of the "file" as an array of bytes and give them to the
new
Qwicap.addDownloadablemethod. That method will return a unique URI for the downloadable, which you then use as the value of an "a" tag's "href" attribute, an "img" tag's "src" attribute, or an "object" tag's "data" attribute. The downloadable is automatically associated with the next page sent to the client. When that page ceases to be "in play", the downloadable automatically becomes available for garbage collection. - As a result of the previous two changes, most Qwicap applications can now use a generic "WEB-INF/web.xml" file (as seen in the examples, and documented in the "Qwicap Deployment Descriptors" document), thereby reducing the number of possible deployment problems, and the number of things a developer has to learn in order to use Qwicap.
- Qwicap can now discover its client class in any given web application
by performing a run-time examination of the application classes, be they a
hierarchy of separate class files in "WEB-INF/classes", or just a flat group of
JAR files in "WEB-INF/lib". Specifically, Qwicap looks for a class containing a
"
public static void main(String[])" method. Provided it finds only one such class, Qwicap will automatically use that method as the web application's starting point. If your web application has more than one class containing such a method, you will have to continue setting the "QwicapClientClassName" initialization parameter in your "WEB-INF/web.xml" file. - Simplified web application setup where it concerns the "url-pattern" in the "servlet-mapping" element of the "WEB-INF/web.xml" file. Now, any application can simply set the value of "url-pattern" to "/". Ordinarily, that would prevent HTTP GET requests for the application's CSS documents, and any other static documents, from operating correctly (they'd invoke the servlet, rather than cause the requested documents to be returned). Now, Qwicap disambiguates the request itself, and, if necessary, handles the transmission of the requested document to the client. As a result, the URLs that are used to access web applications can be made simpler and more natural. For example, the URL for the Qwicap number guessing game example, a web application named "guess", can be reduced from "http://localhost:8080/guess/app" to "http://localhost:8080/guess".
Version 1.3.3 of 8-Jan-2006
All of the following changes were back-ported from Qwicap 1.4a4 in order to correct bugs, or to make simple enhancements.
- Eliminated a race condition that could occur as a Qwicap application exits.
- The
Qwicap.goodbyemethod now initiates the shutdown of Qwicap and its client application. Previously, it was up to the the client application to shutdown in a graceful manner. This new behavior should force applications to do the right thing, by depriving them of the use of allQwicapmethods for prompting, retrieving input, etc. - Added the
Qwicap.getFloatmethod, for retrievingfloatprimitives from user input. This is slightly preferable to the past practice of usinggetDoubleand typecasting the result tofloat. - The various attribute manipulation methods in the
Resultsclass (and all of the lower-level classes on which it builds) now accept arbitrary objects as the values of attributes. The ultimate value of an attribute is whatever the specified object'stoStringmethod returns. If the specified object is actuallynull, the value of the attribute is empty, e.g. "... myattr='' ...". QwicapSessionDeathExceptions now come with messages specifying the reason the session died, or is dying.- Improved the documentation for
Qwicap.convertSubmitButtonsToInputs, which is a work-around for the hideous bugs in the "button" element handling code of Internet Explorer (Mac and Windows). - Removed the constructor of the
Contextclass from the public API. Also removed from the public API the following methods:go,getSessionContextCount, andclose. Client code has no need for those. - Removed the method
Context.getfrom the public API. Client code that wants access to the currentContextobject has always been able to get it usingQwicap.getContext. - Improved the error messages produced by the XML tag hierarchy validation code such that all of them specify the name of the document in which the error was found, provided that the XML came from a document with a known name.
- All subclasses of
Markupnow havegetMutableandgetImmutablemethods. If a markup object is already in the requested state, the methods do nothing, and return a reference to that object. If the markup object is in the opposite state, a copy is created in the requested state, and that is returned. - Documented the
Context.getFileandContext.getExistingFilemethods. - Removed some unnecessary, old code from the
Qwicapclass. - Various improvements to the Javadocs.
- Bug fix in the Hunt The Wumpus example application.
Version 1.3.2 of 16-Nov-2005
- Corrected a bug in
Form.setDataSetthat could result in double-encoding of form control values. - Updated the
Hexadecimalclass to use table lookups for its conversions. That class is not a part of the Qwicap API, but is used by Qwicap and therefore is present in the Qwicap library.
Version 1.3.1 of 20-Aug-2005
- Corrected a bug in
Results.addContentthat prevented the method from doing anything when the new content being inserted was anotherResultsobject. This also affectedResults.addContentBeforeandResults.addContentAfter, and prevented the "wumpus" demo application from working correctly.
Version 1.3 of 17-Aug-2005
- Version 1.3 has been released on SourceForge.net, and all of the required paperwork has been concurrently filed with The University, as specified by the applicable UT System policy.
- A plausible 1.3 release has been assembled and is available. It is possible that the "README.txt" file and other supporting documents will require further edits, but the code is as it should be.
- Permission to open-source Qwicap has been obtained, and I finally seem to have run out of questions for the lawyers (thanks Georgia!). Copyright notices appropriate to the Lesser GPL have been added to all source files, and some further Javadoc improvements have been made. The project is now in cleanup mode prior to filing of final paperwork and the actual open-source release.
- Modified
Results.deletesuch that it now returns an emptyResultsobject. (Originally it returned nothing.) The benefit of this modification is that it permits the application to use theResults.popmethods to recover a reference to an earlierResultsinstance (ideally, one whose elements weren't just deleted) on which it wishes to perform additional operations. - Corrected a bug in
Results.xor. Up until now, it had, in effect, been performing a subtraction, rather than an XOR. In many cases, that produced the same result as an XOR, but not in all cases. - Optimizations to the
Resultsclass: The objects are now lighter-weight than they have been, fewer objects are allocated internally, they perform almost no type-casting, and should be slightly faster here and there. - Corrected a bug in
ResultsEnumerator.nextElementwhich caused it to return an object of typeRange(or one of the many subclasses/subinterfaces that implement/extend it), rather than an object of typeMatch, as the method's documentation demanded. The type-specific methodnextMatchhas always behaved correctly. - The implementation of
ResultsEnumeratorhas been simplified, and should be more efficient now. - Removed a number of internal-use-only methods from the public API of the
Pageclass. - The performance of CSS pattern searching has nearly doubled, and the tag-hierarchy validation phase of XML parsing should also be faster.
DescendantEnumeratorno longer creates objects during the course of an enumeration.- Added a
get(CSSPatterns)method to allMarkupobjects, so that searches can be conveniently performed using "pre-compiled" CSS patterns. - Changed the implementation of
CSSPatternsCachesuch that it uses aLinkedHashMapas the basis for the cache, rather than the previous hand-coded linked-list with on-the-fly, most-recently-used element re-ordering. In some cases theLinkedHashMapis actually slower than the previous linked-list cache, but, overall, it shows a modest performance gain. Also, when the cache fills, it removes the least-recently-used elements on-the-fly, rather than in a delayed pruning pass, as was the case in the previous implementation. The Internet-Explorer-is-hopeless-rubbish automatic "button" element to "input" element conversion feature now reverses the conversion before returning from the
Qwicap.promptmethods. While this isn't necessary for pages that are setup once, and only once, beforepromptis invoked, it is necessary in the case where the "button" elements of type "submit" in the page markup are modified after the firstpromptinvocation. So, to maximize the transparency of this feature under all circumstances, the conversion is automatically reversed before returning to the client.While this change greatly increases the transparency of this feature, it is still not perfectly transparent. If client code was holding references to
Matchobjects for its "button" elements, or their contents, thoseMatchobjects would no longer refer to anything after invokingprompt, because Qwicap will have deleted those buttons, replaced them with "input" elements, sent the page to the user, then deleted the "input" elements and replaced them with new "button" elements. Given the way the Qwicap API encourages people to work, this would be a very unusual way for client code to be implemented, and reimplementing such client code so that it doesn't need to hold thoseMatchobjects acrossinputinvocations would be straightforward, so no further effort will be made to increase the transparency of this auto-convert feature. There's a limit to how severely Qwicap should be hacked to work around an inexcusably broken product like Explorer, and that limit has been reached (if not exeeded).- In support of the above, added a
convertSubmitInputsToButtonsmethod to the classesFormandMutableMarkup. - Corrected a bug in the parsing of CDATA.
Major refactoring has been performed to move classes into packages such that as many classes as possible that are for internal-use-only no longer have "public" access. For the most part, I preferred the previous organization of the code, since it did a better job of grouping related classes, but until Java acquires a variant of the "package" visibility-modifier that extends visibility to classes in sub-packages, too many internal classes have to be made "public" in order to be accessed across sub-package boundaries.
One effect of these changes that will impact existing code is the move of the
Matchclass from the "css" package to the "xml" package. The class is otherwise unchanged, so it's just a matter of adjusting "import" statements.Another effect of these changes is that the number of classes visible in the Javadoc for the API has dropped from 114 to 56. Only a few classes in the "internal use only" category are still shown. Hopefully, the API documentation will be more readily comprehensible, now that there's so much less of it to comprehend.
- Fixed a bug in
Form.isControlEnabledthat caused it to return the opposite of the correct value. - Made changes to the classes in the "css" package, and sub-packages,
that resulted in lighter-weight data structures, reduced the number of
objects used, eliminated some type-casting, eliminated the
CSSPatternMatcherclass (its duties have been taken-on by the newCSSPatterns.searchmethod), and consequently identified and fixed an old, but never-encountered, bug inMatch.get(CSSPatterns, Results). - Moved the
MutableMatchclass from the "css" package to the "mutable" package, and theImmutableMatchclass to the "immutable" package. The former move allowed theMatch.setmethod to be eliminated. - After 90 development versions, 1.3 has gone alpha.
- A bug in
MutableMatch.equalshas been corrected. It prevented some functions that relied on equality tests, likeResults.xor, from working properly under certain circumstances. This bug was introduced as a side-effect of an optimization in one of the previous development versions. A side-effect of the bug fix is that methods likexor,and,oranddistinctwill be faster than ever when dealing with mutable markup. Form.getFormIDhas been demoted from "public" to package access, since it really deals only with Qwicap's internal magic, and client code should not be depending on the behavior of that magic.- Added the method
Form.deleteChoicesto allow all of the "option" controls to be conveniently removed from a "select" control, presumably so a fresh set ofaddChoicecalls can be made to populate the "select" with new options. This method also works on "input" controls of type "radio" and "checkbox", but, because of the way HTML forms are structured, deleting these "choices" means the controls vanish from the markup entirely, andaddChoicewill not be able to add new ones. - When using any of the
Form.setControlValueorForm.setControlValuesmethods, supplying anullvalue causes the control's value to be cleared usingForm.clearControlValue. They used to just set the control's value to an empty string, but this new behavior is more consistent with the behavior ofgetControlValue, and the symmetry seems like a good idea. - Changed the
Form.clearControlValuemethod to clear the value of any type of control, not just controls whose values are user-alterable, which was its previous behavior. - Added the
Form.getControlValueandForm.getControlValuesmethods. - Made
Match.hasAttributemore efficient than it was. - Added the
Match.hasNonEmptyAttributemethod to make it easy to test whether an element has an attribute of the specified name, whose value is not empty. - Added the
Match.getAncestorOfTypemethod to allow the most recent ancestor tag of a specified type to be easily determined. - Changed the access specifiers of several classes from "
public" to package, since client code didn't need access to them. [Given a more flexible access specifier mechanism (say, one that took the package hierarchy into account), I'd gladly eliminate public access to most classes, and the product would be better for it.] - The method
Form.setControlEnablenow returns a reference to theFormobject, like almost all other methods in that class. - Changed the
XMLDocument(URLConnection)andXMLDocument(URL)constructors such that they now close the connection to the URL-specified document after they've finished reading it. (Had theURLConnectiondocumentation mentioned that it didn't close its connection when it finished reading the document content, I'd've been closing the connection all along.) - Made the
XMLDocument(URLConnection)constructor public. - Removed overlapping shortcut detection code from the decoder methods in
HTMLEntityCodec. That will make them faster in some cases. Match.getAttributewasn't decoding the attribute value it returned. It is now.- An off-by-one error in
HTMLEntityCodec.decodehas been fixed. Numeric character entities are now decoded correctly. - Removed all "form parameter"-style terminology from the
Qwicapclass, and substituted "form data set"- and "form control"-style terminology as used by the W3C in the HTML specifications. This necessitated many Javadoc changes, including the correction of some old errors, and the deprecation and replacement of a number of methods:rejectParameterandrejectParametershave becomerejectInput,getParametersis nowgetFormDataSet,hasParametersis nowhasFormDataSet, andembedParametersInMostRecentFormis nowpopulateMostRecentForm. Qwicap.rejectInputand, by extension, all methods that reject form input directly or indirectly, has been modified such that when input auto-embedding is disabled, input is still embedded into the form markup for the purpose of automatically soliciting a correction from the user, but once that's been done, the original state of the form is restored, so the client application will never know it happened. Previously, the auto-embedding took place in this case, but wasn't undone after the correction was solicited, thereby leaving the form markup in a state that the client application wouldn't expect.Removed from the
Qwicapclass the methodsgetAutoEmbedParametersandsetAutoEmbedParameters(both introduced in version 1.2), because creating a mode was a bad idea. One reason that it was a bad idea was that it interfered with code re-use by implicitly embedding an assumption about that mode into any given piece of code. Another, closely related, reason was that it couldn't easily be made page-specific. So that "feature" is history.It is replaced by a new version of the
promptmethod, and an implicit change to the behavior of the original method. The newpromptmethod accepts abooleanparameter that istrueif parameter embedding should be automatic, andfalseotherwise. (In either case, parameter embedding is automatic when a parameter is rejected, but if auto-embedding is disabled, the original form control values are automatically restored after the parameter has been rejected.) The originalpromptmethod now assumes that parameter embedding is automatic, which was the old default behavior, anyway.(This new scheme isn't ideal, however; an ideal scheme would allow separate auto-embedding settings for each form on a page. That would facilitate code re-use at the "form" level. The obvious way to solve this problem would be adding custom markup to forms that would specify this behavior to Qwicap. However, that would make their markup non-standard and prevent it from validating, while also introducing meta-data into Qwicap. Neither situation is acceptable, so the scheme remains less than ideal.)
- Added the
Form.extractDataSetmethod, which does the opposite ofembedDataSet. ArrayToStringno longer producesNullPointerExceptionswhen it encountersnullelements in arrays or collections. Instead, it outputs "null" in their places.- Remodeled the growth algorithm in
RangeListandMatchListon the algorithm employed byjava.util.ArrayList. - Improved the API documentation in many places.
- Improved some markup-related exception messages.
- The
MatchEnumeratorclass has been replaced with a new, and much more efficient, class that both enumerates faster, and doesn't fill-up the relevant markup'sMatchcache as it does so. The latter behavior not only reduces memory use, but means thatMatchcache maintenance will usually be faster (and will never be slower). The new enumerator also detects changes to its markup that occur during the enumeration and throws an exception if they occur. The original enumerator wasn't able to cope with such changes, either, but didn't detect their occurrence. - The
Formclass is no longer a subclass ofMatch. Any code that requires theMatchthat corresponds to the "form" element represented by aFormobject can use the newForm.getMatchmethod. - The way in which
MuTagWithAttributeskeeps track of its attributes has been made more efficient. (Also tweaked theAttributeEnumeratorinterface, and added a new subclass of it, in order to support those changes.) - Made the
Attributeinterface extend theNamedIteminterface, just as theRangedocumentation has always said it should. Conceptually, an attribute is a range, so this makes sense. (Hopefully there wasn't some good reason I didn't do this in the first place, or, perhaps, undid it later.) - The
MarkupEnumerationinterface has been extended to include anextRangemethod, which does exactly what thenextElementmethod does, but the type of its return value isRange, which eliminates some typecasting elsewhere in the code, and promotes type-safety. - The "cloning rule" (see
MutableMarkup.insert) has been relaxed. Originally, no element could exist more than once in the same body of markup, so, for instance, duplicating a row of a table meant creating clones of all the elements in the duplicate row. However, over the course of Qwicap's evolution, a set of features have been put in place for various other reasons that make the cloning rule unnecessary where immutable elements are concerned. So, now only mutable elements are cloned, which will save memory (less redundancy), and time (less cloning). [Within this very limited context, cloning isn't necessary for mutable elements, either, but a failure to clone them would lead to very interesting behaviors that would make the Qwicap templating engine unusable in practice. And that would be bad.] - The way in which
ImTagWithAttributeskeeps track of its attributes has been made more efficient. - Documented all public methods of the
Formclass, and adapted most of the existing documentation to the recent change in terminology from "parameters" to "controls". - Changed a number of class and method names to bring Qwicap's use of HTML "form"
related terminology more in line with official W3C terminology as used in the HTML
specifications. So,
WebParameterswas renamed toFormDataSet(see "form data set" in the spec.),WebParameterwas renamedFormControlValue(not because the W3C uses that exact term, but because the closest it gets to a name for such things is "control-name/current-value pair"),FormElementInfobecameFormControlInfo, and all uses of the word "Parameter" were removed from method names in theFormclass and replaced, for the most part, with the term "Control", e.g. the methodsetParametershas becomesetControlValues, though the methodembedParametershas becomeembedDataSet. - Added the
Nullclass which provides a set of static utility methods that perform common tasks associated with the handling