Version 1.4b27[TEST-8] of 12-Nov-2012
- Altered the signatures of the two
QwicapServlet.init
methods such that both are allowed to throw the standardServletException
, like any other servlet. - Corrected a crashing bug that appeared when running Qwicap under Apple's Java 1.6 distribution for Mac OS X 10.8.2. The problem was the stack size of the small entropy-generating threads of the pseudo random number generator. Because the threads are very simple, their stack size was set at 64 KB, rather than allowing a stack of an unknown size (but somewhere around 1.5 MB) to be allocated by default. That 64 KB stack had been fine, but now results in crashes. Consequently, the entropy thread stack sizes have been doubled to 128 KB, and testing shows that to be sufficient. There's no way to be certain that this will always be an adequate stack size, or that it is currently sufficient for all platforms (though there've been no problem reports), so this issue can only be provisionally designated as fixed.
- Small change to the
StackTrace
class to make its output more consistent with Java's, but without any of Java's bad habits, like stacktrace truncation. - Corrected a grammatical error in the
Results.setAttributes
Javadocs. - Improvements to the
FormControlInfo
Javadocs, along with a further tweak to allow for the fact that the javadoc generator, either by default, or in all cases, doesn't produce output that can handle all UTF-8 characters properly, probably because the awful HTML it generates does not specify the character set/encoding employed in its HTML output. - Some improved features, like the ability of the
FormInputRejectionHelper
class to mark unlabelled text fields (both "input" and "textarea") in red when they supply bad input, so that the field that is the source of the bad input can be made obvious to the user even in the absence of labels. - Made an accumulation of small changes throughout the code base largely due to various
utility classes, which will eventually be made available as stand-alone libraries, being
moved into packages of their own, thus changing
import
statements wherever they are used in Qwicap classes. - Corrected an oversight in the date format used by the reports produced by the
ServiceDataRecorder
class. It had been using hours expressed as 0-11 along with an AM/PM indicator. However, in the presence of an AM/PM indicator, hours should be expressed as 1-12. And now they are. - Improvements to the wording and look of the Qwicap "dialog boxes" that are displayed when a web application session terminates for any reason.
- Reduced access from
public
toprotected
for the internal "IntraElementContentMatch
class' constructor. (The class has to bepublic
because uses of it span package boundaries, but it is not part of the Qwicap public API.) - Various improvements to the Javadocs.
- Reduced logging priority from "SEVERE" to "WARNING" for the log message: "The character set of the form data set could not be identified; defaulting to ISO-8859-1."
- Corrected a bug in the plural numeric "get" methods of the
Qwicap
class, for examplegetInts
,getDoubles
, etc. The bug was that, when theAllowedToBeBlank
parameter wastrue
, a blank input value was not always being replaced with the corresponding value from theDefaultValues
parameter, and would instead cause the input to be rejected. - Minor additions and modifications to the "qwicap.css" style sheet to support new, but not yet finished, user input error reporting capabilities. Changed the name of the style sheet used by the various Qwicap problem pages (for cases like a crash, unexpected exit, or app restart) to something more general to avoid confusing myself. Altered the CSS reference in the problem pages accordingly.
- Added the missing
Qwicap.getStrings
methods. (This is a historical oversight caused by the fact that all of the numeric retrieval methods could easily be "pluralized", because they all built on a single method for retrieving and validating multiple numeric values. Non-numeric retrieval methods couldn't build on that common numeric retrieval method, and were therefore left-out of the "pluralization" effort.) Still required: plural forms of theQwicap.getBoolean
methods. - Made the message in the "qwicap-exit.html" page more user friendly.
- Changed the access control modifier on the
BlockingDescription
constructor from "package" toprotected
. - Added a
clone
method to theALStack
class. Modified theremove
method of theArrayIterator
method such that it throws anUnsupportedOperationException
when invoked, instead of doing nothing at all. - Minor refinements to the Ant build scripts.
- Added a typecast to a
FormDataSet.addData
invocation in theForm
class in order to avoid a compiler warning. - In the
i18nDocumentAccessor
class, tweaked a variable type fromClass
toClass<?>
to make IntelliJ IDEA's code sense checks happy.
Version 1.4b26 of 27-Apr-2011
- Extended the
Auth2Scheme
interface such that itsqwicapAuth2SchemeHit
method now receives aFormDataSet
instance as its final parameter, in caseAuth2Scheme
implementations want to risk altering their behaviors based on user input (which could be bogus). Note: This extension alters the pre-existingAuth2Scheme
interface, and therefore breaks any existingAuth2Scheme
implementations. The fix is trivial, however: Add a parameter of typeFormDataSet
to the end of the parameter lists of yourAuth2Scheme.qwicapAuth2SchemeHit
methods. Since the parameter didn’t exist before now, and pre-existingAuth2Scheme
implementations therefore have no use for it, they can simply ignore it. So, it’s a one line fix, with no logic changes. Trivial. - The
Auth2SchemeReply.qwicapShouldDiscardThisSession
method has Javadocs, at long last. For some reason, it had escaped being documented until now. - Changed the default URI attribute separator used by the
FormDataSet.toWWWFormURLEncoded...
methods from a semicolon (';') to an ampersand ('&'), because too much software is ignorant of the semicolon recommendation (see section "B.2.2 Ampersands in URI attribute values" of the HTML 4.01 Specification, where it states "We recommend that HTTP server implementors, and in particular, CGI implementors support the use of ';' in place of '&' to save authors the trouble of escaping '&' characters [....]"). This reverses a change made in Qwicap version 1.4b13. - Altered the
QwicapServlet
,QwicapApplicationServices
andQwicap
classes to pass arguments to a web application's entry point (its "public static void main(String[] args)
" method) for the first time. The first argument is the deployed name of the web application. The arguments that follow are alternating names and values from, first, the "context-param", and then the "init-param", elements in the web application deployment descriptor ("web.xml" file). The order in which the name and value pairs obtained from the "context-param" and "init-param" elements appear in the argument list is undefined, because the order of retrieval by theServletContext.getInitParameterNames
andServlet.getInitParameterNames
methods is unspecified. However, this much can be said: In the argument list, the names and values obtained from "context-param" elements will appear prior to the names and values obtained from the "init-param" elements. - The Javadocs associated with the
Qwicap.rejectInput
methods have been revised in order to explicitly describe their blocking behavior, and the flow control imposed on the caller when the methods unblock and always throw aQwicapException
in order to restart the caller’s input processing logic (an outcome ensured by the use of the Qwicap “prompt pattern”). This does not represent a change in the behavior of Qwicap (it has always worked this way). It is merely an improvement to the Javadocs that may be of some assistance to developers. - Improved some of the grammar in the Javadoc for the
Qwicap.convertSubmitButtonsToInputs
method. - Added the
edu.utexas.its.eis.tools.qwicap.Version
class to provide the current version and build number information (see theVersion.getString
static method), so that that information is no longer stored in theQwicap
class (it can still be accessed through theQwicap.getVersionString
method, however). Updated the Ant build script, "build.xml", to automatically update the version information in theVersion
class, including its Javadocs, rather than modifying theQwicap
class. - Found that the "qwicap-crash.html" page was using a different HTML element class to identify elements (typically "span" tags) whose contents should be replaced with the "incident codes" used to opaquely identify individual errors. It now uses the same HTML element class, "qwicap-incident-code", that is used in all other pages.
- Eliminated the code that set the URL of the "action" attributes of the "form"
elements in the pages used by the
QwicapServlet
class’ internal methodsshowCrashPage
(page: "qwicap-crash.html"),showExitPage
(page: "qwicap-exit.html"), andshowRestartPage
(page: "qwicap-restart.html"). While it seems logical to set those attribtues to point to the current web application in cases where they're simply left blank (which they are in the default pages embedded in Qwicap), it so happens that by virtue of being blank, they automatically refer to the current web application. Therefore, what seemed like a useful feature actually turned out to be either unnecessary, or counterproductive, and therefore that feature has been eliminated. The "action" attributes of the "form" elements in those pages (or any developer-supplied substitute pages) will now be left unmodified. - Ant build file ("build.xml") improvements, including: updated library Javadoc URLs (Oracle has been relocating Java documentation); the ability to keep the "dist" directory and its contents between builds so that binaries (JARs) can be included in the repository; and the generation of compressed JARs, in all cases.
- Moved the
XMLCharacterSetDetector
class, and all associated classes, into theedu.utexas.its.eis.tools.qwicap.template.xml.util.xcsd
package, so that it can be built as a stand-alone library for use independent of Qwicap. (It is built using the new "build-xcsd.xml" Ant script, which is automatically run by the "project-dist" task of the overall Qwicap build script, "build.xml".) - For XML that includes a byte-order-mark (BOM), added a test for consistency between the character set identified by the BOM and the encoding identified in the XML declaration (if any). If they are found to be inconsistent, a "SEVERE" log message is generated, and the markup is read using the character set identified by the BOM.
- Added some extra, apparently redundant, but (at worst) harmless, code to remove the registration of Qwicap’s “Rule30” secure pseudo random number generator. Since that registration creates the potential for a memory leak in a web application server, ensuring that the registration is removed when Qwicap is shutdown is important enough to merit some apparently redundant code.
- Modified the
Rule30RandomProvider.engineGenerateSeed
method such that it actually generates a new seed value using the internalEntropy
class, rather than using a stored instance of theRule30Random
PRNG to generate the seed value. - Generally improved the internal
Entropy
class that provides seeds for theRule30Random
PRNG class. Also, memory use has been reduced, timings have been adjusted to allow for microsecond counters (like the one in Java 6 on Mac OS X 10.6.1) that don't use their full precision, and a sign-extension issue has been corrected. Rule30RandomProvider
now registers the Qwicap’s Rule 30 PRNG provider with a version number corresponding to Qwicap’s major and minor version numbers (1.4 at the moment).- Minor optimizations to the Rule 30 pseudo-random number generator code.
- The internal
edu.utexas.its.eis.tools.qwicap.servlet.QwicapGlobalServices
class now logs all Security Providers at the "FINE" level. - Added
@Override
annotations throughout the code to improve maintainability by making it possible for IDEs and the Java compiler to catch mistakes to which they would otherwise have been oblivious. - Improved the operation of the
FormDataSetFilterResponse.run
method (and the non-public class,FilterActionRun
, which implements that functionality) by making them indifferent to an empty page stack. Thus,FormDataSetFilterResponse.run
can operate correctly before a web application has displayed any pages. - Improved the Javadocs for the
FormDataSetFilterResponse
class. - Modified the
Form(Match)
constructor to verify that the suppliedMatch
instance refers to a "form" element. If not, aFormNotFoundException
is thrown. - The
Form.getDataSet
method will now include a solitary "submit" control (whether it's an "input" or a "button" element), even if that control lacks a name. - Corrected a bug in the
Form.getControlValue(String)
method which prevented it from returning the value of a "select" element when none of the child "option" elements had a "selected" attribute. In such cases, the first option is considered to be selected (and "successful") and it is now the value of the first option that is returned. Previously,null
was returned. Added corresponding JUnit tests. - Corrected a bug in
Form.setControlValue
that sometimes prevented the previous value of the control from being cleared if it was a checkbox, radio button, or "select" control. - The
Form.printAllLabels
method has been deprecated, and a newForm.getControlsTable
method has been added. (This continues the process of deprecating the old "print
..." methods that were intended as developer aids, and replacing them with equivalent, or better, methods that don’t send their output to the console.) Significantly, the new method not only returns aMutableTable
instance containing the information (rather than printing anything), but it improves on the old method by: listing the controls in the order in which they are found in the markup; by including "select" controls (instead of just "option" controls); and by listing the name and value(s), if any, of each control. All subclasses of theTable
class will, of course, convert themselves to nicely formatted strings, so developers can print this table directly to the console, log it, etc. Since the table is mutable, developers may also sort its rows according to whatever columns are most important to them. - Updated the Javadoc class description for the
Form
class. - Improved the JUnit tests of the
Form
class. - Modified the
FormControlInfo
class such that the label string built for a control will never include information from any label-bearing element more than once. Such redundancy in labels was previously possible in the case of a form control located inside a "label" element whose "for" attribute referenced the control. Since a control located inside a label element is automatically associated with that label, associating the label with the control using a "for" attribute is redundant. However, it is possible, so the revisedFormControlInfo
class will detect and avoid such redundancy. - Improved the
FormControlInfo.toString
method. - Updated the URL production in the
FormInputRejectionHelperJUnit
class such that the URL produced for the "BaseDir" used in the test is produced using the approved means of invoking.toURI().toURL()
on it, rather than just.toURL()
which can produce invalid URLs. - Added support for UTF-32 (big- and little-endian) to the form data set character set detector code.
- Added
@Deprecated
annotations to theFormDataSet
class methods that were already marked as deprecated by their Javadocs. - Improved the Javadocs for several methods in the
FormDataSet
class. - Added the
Match.toForm
method to increase parity between the functionality provide by theResults
class and theMatch
class. (And also because the workaround,Match.toResults().toForm
, looks ridiculous, which is a sign of poor API design.) - Modified the
Results.toForm
method to search the list ofMatch
objects contained within theResults
object and return aForm
object describing the first "form" element that is discovered. This represents a change of behavior. Previously, only the firstMatch
object in the list would be used in an attempt to create aForm
object. The virtue of this change is that it allows code likeMarkup.get("button[name=\"logout\"]").getAncestors().toForm()
to work, which adds a convenient new way to locate a "form" element and to instantiate aForm
object to represent it. When no "form" element is present in theResults
object, aFormNotFoundException
is thrown. (The behavior of the oldResults.getForm
method remains unchanged for backward compatibility.) - The
Results.toForm
method now allows itself to be invoked onImmutableMarkup
. Previously, it could only be used onMutableMarkup
. Needless to say, the methods of theForm
class that modify markup in any way will fail if used onImmutableMarkup
, but the methods used merely to obtain data from markup will work. - The
Results.getForm
method has been deprecated, and a more appropriately named method,Results.toForm
, has taken its place. - Improved the Javadocs of
Results.getForm
(deprecated) to document thatnull
is returned when the first item in aResults
object does not contain a reference to a "form" element. This has always been the behavior, but it was not documented. - Improved the Javadocs of the
Results
class, and marked its deprecated methods with@Deprecated
annotations. - The
FormNotFoundException
is now, officially, a part of Qwicap’s public API, and has been changed from a subclass ofQwicapException
to a subclass ofTagException
. SinceTagException
is, itself, a subclass ofQwicapException
the practical implications of this change should be nil. - Updated the internal
DocumentCache
class to replace uses of the deprecatedFile.toURL()
method, which can produce invalid URLs, withFile.toURI().toURL()
invocations, which always produce valid URLs. No known bugs resulted from the prior implementation (the cases in whichFile.toURL
could produce invalid URLs shouldn’t have arisen withinDocumentCache
), but the new implementation is assured to be correct, and is definitely the way to go forward. - Updated the internal
DocumentSource
class to use new "Content-Type" parsing code, to keep MIME type and character set data separate, and to supply character set data to the XML parser, when available. (Otherwise, the XML parser continues to makes the character set determination itself.) - Added new document search logic that attempts to retrieve an otherwise unfound document as a resource of all of the application classes in the current stack trace.
- Updated the internal
LingeringDownloadables
class to use a synchronizedHashMap
, instead of the obsoleteHashtable
class. - Updated the internal
PageStack
class to improve the Javadocs, substitute a synchronizedHashMap
for a use of the obsoleteHashtable
class, and to add comments to the code, including comments that document the validity conditionals that depend on reference equality. - The
RangeListEnumerator
methodsnext
,nextElement
andnextRange
have been modified such that they throw theNoSuchElementException
when the end of the enumeration/iteration is passed. - In the
MutableMarkup.setCharacterSet
method, improved the handling of the optional, XHTML-specific <meta http-equiv='Content-Type' content='subtype/type;charset=...'/> element. - Improved the
Page
class to perform better handling of "Content-Type" information. - The complete range of syntax supported by the HTTP/MIME "Content-Type" is now supported. (To the extent that default character set identifications are document or protocol specific, document type and protocol specific classes have also been added to encapsulate that knowledge.) The "Content-Type" field seems to be widely and wildly underestimated in its complexity. One problem with it is that its capabilities are not set out in any single RFC, but are a combination of the capabilities discussed in RFCs 822, 2045, 2046, and 2616. This yields a field whose values can look like this: “text/plain; thought="Say \"Hello\" to Bob, please."; charset=us-ascii (Plain text)”, or can contain arbitrarily more data, quoted and unquoted, escaped and non-escaped, with comments and without, as appropriate to the standards and as necessary to the application. Any code that processes content types and cannot handle an example like that, is not standards-compliant. As far as I can tell, Qwicap is now capable of handling every aspect of content type specifiers. On the other hand, it was very difficult arriving at this level of understanding of all their possible formats, encodings, etc., and the possibility that there are details as yet overlooked cannot be entirely dismissed.
- Content read via HTTP whose "Content-Type" header identifies it as some type of text, but does not identify its character encoding, is treated as if it were encoded using IS0-8859-1, as the HTTP standard (RFC 2616) requires. However, that HTTP behavior is flatly contradicted by RFC 3023, section 3.1, when the content type is "text" and the subtype identifies the text as XML. In that case, RFC 3023 asserts precedence over RFC 2616 and requires that the default character encoding be regarded as "US-ASCII". Qwicap now respects both requirements, with RFC 3023 taking precedence over RFC 2616, when appropriate.
- If the
XMLDocument
class, or any of its subclasses, is provided with access to a document through anInputStreamReader
, the character set data in theInputStreamReader
is used as the identification of the document's character set. - Modified the
write(PrintWriter)
methods ofMarkup
andImmutableMarkup
to return thePrintWriter
that is passed-in. - Improved the Javadoc for the
XMLDocument(Reader, long, String)
constructor in order to clarify the meaning of theLengthHint
parameter. - Added the
@Deprecated
annotation to theXMLCache
class (its Javadoc has marked it as deprecated for years, so the deprecation is nothing new). Also added to the Javadocs a lengthy discussion about why this class was deprecated, and where Qwicap supplies automatic caching. BecauseXMLCache
is no longer considered to be part the Qwicap API (and hasn't been for some time), it is not included in the standard Javadocs. Interested people will need to refer to the source code for theXMLCache
class to see the explanation. - Reduced the priority of the log messages that report when a valid "action" URL
cannot be constructed for a
FormDataSet
. - Improvements to the
HTMLEntityCodec
class. - Corrected a typographical error in a log message in the
QwicapServlet
class. - Removed contractions from a pair of exception messages in order to increase readability for people who are not native English speakers.
- Corrected grammatical errors in a few log messages.
- Upgraded the "table" library from version 1.0a46 to 1.0a50. Version 1.0a48 added the
ability to create tables from primitive arrays and arbitrary objects. Version 1.0a49
corrected a bug in padding table cells that contain other tables when the width of
any of those contained tables is one character less than the width of the column that
contains them. Version 1.0a50 fixes bugs associated with
null
numeric and date values. - Upgraded the Apache Commons I/O library from version 1.4 to 2.0.1.
- Updated the "servlet-api.jar" library from whatever version was being used to the version supplied with Tomcat version 6.0.32.
Version 1.4b25 of 26-Sep-2008
- Added the
Form.getControlByIndex
andForm.getControlByIndexAndValue
methods, for getting information about one control among many that share the same name. - Added the
FormDataSet.getActionURL
andFormDataSet.setActionURL
methods. - Added the
Form.getAction
,Form.getActionURL
, andForm.getMethod
methods. - 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.getSubmitControls
method to return information about all of the "submit" controls in a form. - Modified the
Form.getControlValues
method to return values for graphical submit buttons ("input" controls of type "image"), when theIncludeSubmitControls
parameter istrue
. The values returned for such controls are always two zeros ({ "0", "0" }
). - Added two new
goodbye
methods: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
FormDataSet
class. - Added the
FormControlValue.setValues
method, added theFormDataSet.setData
method, and improved theForm.getDataSet
method. - Modified the code to use the new
ReadOnlyTable
class 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.getInputBytes
method that could prevent some form data sets from being read completely. - Resolved floating-point precision issues in the
Qwicap.getFloat
andQwicap.getDouble
methods. These methods have usedBigDecimal
internally 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
CSSPatterns
objects. This eliminates a lot of redundant CSS pattern parsing. - Added the missing
Match.get(CSSPatterns)
method. - Removed obsolete code from the internal
ServiceData
class. - 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'sClassLoader
any more likely to be garbage-collected. - Fixed an obscure bug in the internal
MatchEnumerator
class that could cause aNullPointerException
to be thrown during someMatch.getText
invocations. - 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
MuTagWithAttributes
class'toString
andwrite
methods 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
TagHierarchy
class 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
QwicapServlet
methodsdoGet
,doHead
, anddoPost
to "protected
".
Version 1.4b21 of 18-Jun-2008
- Corrected a mistake that would prevent a web application's
ClassLoader
from 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
NullPointerException
when 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
QwicapThreadPool
class will now make a list-ditch effort to kill any lingering threads of classjava.util.TimerThread
that 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'sClassLoader
from being garbage-collected. - Added support for an experimental tool that monitors garbage collection
of
ClassLoader
s 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
geti18nServices
methods of the classesResults
andSmartStringConverter
. - Minor improvement of terminology in the Javadoc for the
Qwicap.getCurrrentInstance
method.
Version 1.4b19 of 2-Jun-2008
- The portion of the
ClassPreloaderAndHolder
class 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 theJarInputStream
class. - Improvements to the implementation of the
geti18nServices
methods of the classesResults
andSmartStringConverter
. - Corrected an error in the Javadoc for the
Qwicap.getCurrrentInstance
method. - 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_VALUE
toInteger.MIN_VALUE
when 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,
IOException
s, especiallySocketException
s (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.getDeclarations
method. - Classes that allow themselves to be enumerated now also implement the
Iterable
interface. Classes that implement theEnumeration
interface now also implement theIterator
interface. - Upgraded the Table library from 1.0a32 to 1.0a36.
- Revised the
ServiceDataRecorder
class to populate the service data report tables with raw data (instead ofString
objects) 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 rethrowQwicapSessionDeathException
andQwicapSessionWillNotDieError
, 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
MutableMarkup
class 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
FINE
or 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
Downloadables
in 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. The page used for the prompt is named "qwicap-restart.html" and is embedded in Qwicap's "edu.utexas.its.eis.tools.qwicap.servlet" package. The message on that page reads (subject to change without notice): "Really Start [Web Appplication Name]? If you want to begin using the web application '[Web Application Name]' again, click on the 'Start' button below. If not, please close this window, or navigate elsewhere." The page may be overridden in order to substitute a custom page. See "Overriding Qwicap's Built-In Pages" below.
- Added 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.goodbye
methods. 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 also 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. The page that displays incident codes is "qwicap-crash.html" and its title and header both read: "The web application '[Web Application Name]' has unexpectedly quit". The page that appears when the application exits without invoking one of theQwicap.goodbye
methods is "qwicap-exit.html" and its title and header both read: "The web application '[Web Application Name]' has quit". Both pages are buit into Qwicap's "edu.utexas.its.eis.tools.qwicap.servlet" package. Either page may be overridden in order to substitute a custom page. See "Overriding Qwicap's Built-In Pages" below. - Overriding Qwicap's Built-In Pages – Qwicap's built-in web pages, "qwicap-restart.html", "qwicap-exit.html" and "qwicap-crash.html" (see above) are all stored as resources in the package "edu.utexas.its.eis.tools.qwicap.servlet". Each of those pages may be overridden by a web application, simply by including a page of the same name among the other pages of the web application. Qwicap will find them automatically, and use them instead of its built-in pages of the same name. Further, Qwicap will: (1) replace the contents of all "span" elements having a "class" attribute that includes the class name "web-app-name", with the name of the web application; (2) set the content of the page's "title" element to the text contained in its "h1" element; (3) set the value of the "action" attribute of all "form" elements to the URL received in the request that triggered the display of the "qwicap-restart.html" page; (4) set the HTTP content type of the connection that will transmit the page to the client to "text/html;charset=UTF-8". Also, the "qwicap-crash.html" page will: (A) have the contents of any "span" element of class "incident-code" replaced with the incident code string; and (B) have the stack trace of the exception that describes the crash replace the contents of any "span" tag of class "exception" that appears within any element of class "show-exception", if (and only if) "development" mode is enabled.
Changed the error reporting mechanism of the
Qwicap.reportException
method 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.reportException
is 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.reportProblem
method as an additional means of easily reporting errors to users. It differs fromQwicap.reportException
in 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.reportProblem
should 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
Qwicap
class 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
toWWWFormURLEncodedString
andtoWWWFormURLEncodedBytes
to theFormDataSet
class. These variants accept aURLAttributeSeparator
parameter. 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 theFormDataSet
class, 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
FormDataSet
class (but doesn't necessarily succeed). - Reduced the
QwicapApplicationServices
class to package-level access. - Extended the XML engine to support manipulation of CDATA, comments and declarations.
- The internal
CharacterSetFamilyUTF16
class 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
NoClassDefFoundError
when using Qwicap's XML engine outside of a servlet environment. - Added some tests to
ResultsJUnit
, and tweaked theResults.getBigInteger
method. - Created the
QwicapBlockingListenerStates
class to remove clutter from theQwicap.synchronize
method 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.actionRefersToThisWebApp
method, 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
Form
class 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
QwicapAJAX
class 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
NoClassDefFoundError
s during execution of the servlet'sdestroy
method. This appears to apply only to those classes that have not been loaded prior to the execution ofdestroy
, but which are used by thedestroy
code (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
destroy
is invoked. TheQwicapServlet.init
method, through use of the newClassPreloaderAndHolder
class, now performs such loading for several internal packages on which thedestroy
implementation 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.destroy
method 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.goodbye
method 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.destroy
method 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.destroy
method. (There was already a similar log message announcing the completion of thedestroy
method.) - Added to
QwicapThreadPool.destroy
a 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.destroy
method, 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
QwicapThreadList
to 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
kQwicapVersionStr
variable 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 ofQwicap
is 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
Results
andMutableMarkup
classes. 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
QwicapServlet
and 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
Downloadable
instances. - The old
XMLCache
has been replaced by a general purpose document cache. TheXMLCache
class 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.getDocument
method, 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.getBundle
is 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.getFloat
andQwicap.getDouble
methods. - Integer magnitude issues have been eliminated from the
Qwicap.getInt
andQwicap.getLong
methods. - Corrected an old bug in the
FormInputRejectionHelper
class 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
MutableMarkup
class 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
, orCalendar
objects, string conversion is handled by formatters specific to the session's locale. In the latter case, things behave just as they always have - thetoString
method is invoked on the object, and whatever it returns is inserted into the markup. - The methods of the
Results
class 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 anull
URL asServletContext.getResource
does. - 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
QwicapThread
instance. - The rules associated with the "prompt pattern" have been relaxed in order to
allow more than one
prompt
invocation 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 theprompt
invocation (one for each case) within the same "prompt pattern" implementation. - The implementation of the
Downloadable
class has been improved. However, due to those improvements,Downloadable
objects are no longer instantiated directly. Instead, they are created by invoking the newQwicap.createDownloadable
method. - The range of the random values that are incorporated into the URIs of
Downloadle
instances 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
Auth2Scheme
implementations that allows them to force the destruction of a user's session. - Greatly increases the amount of information logged by the
QwicapServlet
class, primarily at theFINEST
level.
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
MutableMarkup
class have been improved.
Version 1.4b7 of 17-May-2007
- The
Qwicap.reportException
method 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.prompt
invocation, and therefore is preventing Qwicap from ever reporting the exception.
Version 1.4b6 of 24-Apr-2007
- Corrected a bug in the
Hexadecimal.andASCIIFromBytes
methods (which are not a part of the public API, nor are they used by Qwicap) which could cause theOutOfMemoryError
to 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
QwicapServlet
in whichHttpServletResponse.sendError
would throw anIllegalArgumentException
, because anAuth2Scheme
implementation had refused access to the web application, and had already caused the response to be committed.QwicapServlet
now invokessendError
only when the response has not been committed.
Version 1.4b4 of 11-Apr-2007
- Corrected a stupid bug that prevented Qwicap's
SecureRandom
service 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
NullPointerException
when 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.Security
class. Thus, aSecureRandom
instance 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
Hexadecimal
utility class has been extended to support reading and writing of floating-point primitives, and the production of combined hexadecimal and ASCII representations ofbyte
arrays. The documentation has also been improved. QwicapServlet
now overrides thetoString
method to provide an informative string.- The
Characters
andImRange
classes now implement Java'sCharSequence
interface.ImRange
is 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 theCharSequence
interface. If, for some reason, you want to take advantage of this fact, you'll have to determine that any givenRange
is immutable, by determining that it does not implement theMutable
interface. Then you'll have to typecast it toCharSequence
. However, you can reliably assume that allRange
objects 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.killThread
andQwicapServlet.destroy
methods 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.invokeInputFilter
method 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 whensetInputFilter
is 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 aprompt
method, or theredirect
method, occurs, unlessinvokeInputFilter
is used before then. - If, in the process of executing the actions specified by a
FormDataSetFilterResponse
, aQwicapSessionDeathException
was 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 fromrejectParameter
long 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.rejectParameter
method. - 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, thePromptFlags
class has been removed from the public API. - Added two methods to the
FormDataSetFilterResponse
class:clear
andgoBackToFirstPage
. - The
Form.addChoice
method now throws anIllegalArgumentException
if the form does not contain a control of the specified name. - The
filter
methods of classes implementing theFormDataSetFilter
interface 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.prompt
method. 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 thePromptModifiers
class 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.showPage
convenience method for displaying non-interactive web pages whose input your code would ignore anyway. This is an alternative to theprompt
method, and saves you the trouble of implementing the associated "prompt pattern". - Added
QwicapSessionAbandonedException
, a non-public subclass of the publicQwicapAbandonmentException
class, which is thrown when Qwicap detects that theQwicapSessionDeathException
s 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, publicQwicap
methods, this new exception can't be used everywhere thatQwicapSessionDeathException
is currently employed. - Added the
Null.orEmpty
convenience method. - Noticed that the documentation for
MutableMarkup.insert
does not mention that it special-cases arrays andCollection
objects 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 ofbyte
orByte
arrays, 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
MutableMarkup
that could cause aNullPointerException
when inserting into the markup an array orCollection
that includednull
members. - The arrival of commands from Qwicap's experimental AJAX-style scripts no
longer causes the client application's (optional)
QwicapBlockingListener
to 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.redirect
method now acts on any input that arrives when the user returns to the web application from the redirect. This includes filtering the input, if aFormDataSetFilter
has been set. Previously,Qwicap.redirect
ignored input. - Added the convenience method
FormDataSet.notEmpty
. - Fixed a significant bug in
Qwicap.addBlockingListener
and also improved it such that it will not add duplicate listener instances to its list. - Made public the constructors of the
FormDataSet
class. - Added the
FormDataSet.has
convenience method. - Altered the
FormDataSetFilter
interface to simplify the parameters passed to thefilter
method, and to include a new parameter of typeFormDataSetFilterContext
which provides new information about the context in which the data set is being filtered. - Removed obsolete material from the
FormDataSetFilter.filter
documentation. - 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
QwicapServlet
class. 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.prompt
and 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
Auth2SchemeFactory
associated with each servlet to produce anAuth2Scheme
instance (optionally associated with each session) which is used to authenticate & authorize each hit in a session. It returns to Qwicap anAuth2SchemeReply
instance 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.getAuth2SchemeReply
method. (The oldQwicap.getAuth2Scheme
method 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
QwicapContext
class. - Simplified the web application deployment descriptor (the "web.xml"
file) by eliminating the need to specify
edu.utexas.its.eis.tools.qwicap.servlet.QwicapContext
as 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
Results
class: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.getRandom
method 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.getRandom
method. 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
QwicapServlet
class. 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
ServiceDataRecorder
class now emits the data it has gathered via aLogger
. It does this the first time something happens each hour (logged at theINFO
level), and whenever the active session count drops to zero (logged atFINE
). The same data can be obtained as aString
object using the newQwicap.getStatusReport
methods. 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
Thread
class 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. HTMLEntityCodec
has 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.addBlockingListener
method, are invoked just before and after Qwicap blocks to wait for user activity. This applies to theprompt
methods, and theredirect
method, 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 theprompt
method is now supplied by theQwicap.prompt(MutableMarkup, PromptFlags)
method. The newPromptFlags
class is the means by which the various optional behaviors associated with prompting, and rejecting input, are configured. This change eliminates the growing variety ofprompt
methods, 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
checkError
on thePrintWriter
objects 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
main
method from theArrayToString
class. 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
, andremoveSessionAttribute
methods to theContext
class. - 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.getCurrentInstance
is 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 provokingNoClassDefFoundError
s 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.Qwicap
class, 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
NullPointerException
along 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
FormNotFoundException
is 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
Qwicap
class 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
FormDataSetFilter
interface. - 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
SecureRandom
intermittently throwing ajava.security.ProviderException
with 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 theSecureRandom
class. 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.setDataSet
will no longer try to embed values in "input" controls of type "submit".- Added the
Match.hasAttributeOfValue
method. - 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.redirect
method, 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.rejectInput
method 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.hasClass
method. - Made the Javadoc for the various flavors of
Qwicap.rejectInput
more consistent, and eliminated some typographical errors. - Eliminated the possibility of a
ClassCastException
in the methods that modify tag attributes when invoked on material other than start tags and empty tags. - Added the
Results.getBoolean
method.
Version 1.4a12 of 22-Feb-2006
- Corrected a bug in
Results.ELSE
and added JUnit tests for all combinations ofIF
/ELSE
/ENDIF
invocations, 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.print
now 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
MutableMarkup
class' internal list insertion code and related methods. - Corrected a set of namespace-related bugs in
MutableMarkup
andImmutableMarkup
. The fixes required that thesetNamespace
method be removed from theNamedItem
interface, access to theImNamedItem.setNamespace
method be reduced from public to "package", theImNamedItem
class 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 toImNamedItem
in 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.clone
now produces a newMutableMarkup
which cannot be affected by changes to the original object, and vice versa. The previousclone
implementation only offered partial protection from such changes.- Optimizations added to the conversion of
MutableMarkup
toImmutableMarkup
. - Removed the static member
HTML
from the public API ofMutableMarkup
. It may still be used, however, through the newhtmlEncode
andhtmlDecode
static methods. - Changed the configuration of the
HTMLEntityCodec
objects used byQwicap
andMutableMarkup
such 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 whichMutableMarkup
encodes attribute values; newlines continue to be omitted from attribute values. - Removed the
Page
class from the public API. It was never meant to be in the public API, but as long as theForm
class depended on it, it couldn't be hidden. That dependence has been eliminated, soPage
will never clutter the API documentation again. - The
Form
class no longer depends upon thePage
class. It works just as before, except that thesetFormDataSet()
method is no longer available. (The methodssetFormDataSet(FormDataSet)
andsetFormDataSet(HttpServletRequest)
remain.) - Deprecated the
MutableMarkup.embedParameters
andMutableMarkup.embedParametersIfPossible
methods. They are replaced byMutableMarkup.embedFormDataSet
andMutableMarkup.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.printPageStack
method 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
getBigInteger
andgetBigDecimal
methods to the classesQwicap
andResults
. - The
Form.setControlValue
methods 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. ThetoString
method will be invoked on each of its elements. - Extended the functionality of the
Form
class by adding (or exposing) static methods that represent all of the class' key functionality, but that operate on a single control identified by aMatch
object. This makes the functionality of theForm
class 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
enableControls
methods to theForm
class to achieve symmetry with the existingdisableControls
methods. - Finally implemented the full functionality originally intended
for the
Form.addToControlValue
method. 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
Results
andForm
classes. - Added the convenience methods
addFirstChoice
andaddLastChoice
to theForm
class. These are the same as invoking the pre-existingaddChoice
method with itsInsertBefore
parameter set totrue
andfalse
, respectively. - The method
Form.addChoice
used 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
Results
class, the methodMatch.insert(boolean, Object)
has been deprecated, and replaced withadd(boolean, Object)
. Work on method name consistency and readability in the
Results
class:Deprecated Replacement insert(boolean, Object)
add(boolean, Object)
insertBefore
addBefore
insertAfter
addAfter
addContentBefore
addToStartOfContent
addContentAtStart
addToStartOfContent
addContentAfter
addToEndOfContent
addContentAtEnd
addToEndOfContent
add(Match)
addMatch(Match)
add(Results)
addResults(Results)
addTo(Results)
addToResults(Results)
- Added
getFloat
,getInt
,getShort
, andgetByte
methods to theResults
class. - Added
cut
andcopy
methods to theResults
class. - The methods
Results.extract
andResults.extractToMarkup
now 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 thetoMarkup
method, 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
FormControlValue
class now implements theComparable
interface, and provideshashCode
andequals
methods. 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 theFormDataSet
class. Form.createChoice
now encodes the values of the attributes in the markup it produces. This also benefitsForm.addChoice
, which usescreateChoice
.FormDataSet.hasParameterNamesStartingWith
has been deprecated and replaced withFormDataSet.hasControlNamesStartingWith
, which is more consistent with official W3C nomenclature.Match.print
now returns a reference to the instance ofMatch
on 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
Qwicap
class.
Version 1.4a6 of 24-Jan-2006
- Added the
Qwicap.promptComplete
method. 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 theQwicap
class. It works exactly like the previousprompt
methods, but causes the page it displays to be treated in a modal manner. For consistency, thepromptModelessSynch
method has been added so that applications can make explicit their choice to use modeless pages. The existingprompt
methods 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.prompt
methods. - The constructors in the
QwicapAbandonmentException
class have been removed from Qwicap's public API, and an unused constructor has been removed entirely. - The constructor for the
QwicapSessionDeathException
class have been removed from Qwicap's public API. - More methods in the
Page
class have been hidden. Updated the Javadocs to explain thatPage
is not part of Qwicap's public API.
Version 1.4a4 of 8-Jan-2006
- Various improvements to the Javadocs.
- Added the
Qwicap.getFloat
method, for retrievingfloat
primitives from user input. This is slightly preferable to the past practice of usinggetDouble
and typecasting the result tofloat
. - The
Downloadable
class 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.toString
returns the unique URI assigned to the downloadable, which means that aDownloadable
can be passed directly toResults.setAttribute
, when creating the link to the downloadable. - The various attribute manipulation methods in the
Results
class (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'stoString
method returns. If the specified object is actuallynull
, the value of the attribute is empty, e.g. "... myattr='' ...". QwicapSessionDeathException
s now come with messages specifying the reason the session died, or is dying.- The
Qwicap.goodbye
method 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 allQwicap
methods for prompting, retrieving input, etc. - Removed some unnecessary, old code from the
Qwicap
class. - 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
Context
class 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.get
from the public API. Client code that wants access to the currentContext
object has always been able to get it usingQwicap.getContext
. - Documented the
Context.getFile
andContext.getExistingFile
methods. - Deprecated the
Results.addContentBefore
andResults.addContentAfter
methods, in favor of the newResults.addContentToStart
andResults.addContentToEnd
methods, 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
Markup
now havegetMutable
andgetImmutable
methods. 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.addDownloadable
method. 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.goodbye
method 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 allQwicap
methods for prompting, retrieving input, etc. - Added the
Qwicap.getFloat
method, for retrievingfloat
primitives from user input. This is slightly preferable to the past practice of usinggetDouble
and typecasting the result tofloat
. - The various attribute manipulation methods in the
Results
class (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'stoString
method returns. If the specified object is actuallynull
, the value of the attribute is empty, e.g. "... myattr='' ...". QwicapSessionDeathException
s 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
Context
class 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.get
from the public API. Client code that wants access to the currentContext
object 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
Markup
now havegetMutable
andgetImmutable
methods. 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.getFile
andContext.getExistingFile
methods. - Removed some unnecessary, old code from the
Qwicap
class. - 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.setDataSet
that could result in double-encoding of form control values. - Updated the
Hexadecimal
class 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.addContent
that prevented the method from doing anything when the new content being inserted was anotherResults
object. This also affectedResults.addContentBefore
andResults.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.delete
such that it now returns an emptyResults
object. (Originally it returned nothing.) The benefit of this modification is that it permits the application to use theResults.pop
methods to recover a reference to an earlierResults
instance (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
Results
class: 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.nextElement
which 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 methodnextMatch
has always behaved correctly. - The implementation of
ResultsEnumerator
has been simplified, and should be more efficient now. - Removed a number of internal-use-only methods from the public API of the
Page
class. - The performance of CSS pattern searching has nearly doubled, and the tag-hierarchy validation phase of XML parsing should also be faster.
DescendantEnumerator
no longer creates objects during the course of an enumeration.- Added a
get(CSSPatterns)
method to allMarkup
objects, so that searches can be conveniently performed using "pre-compiled" CSS patterns. - Changed the implementation of
CSSPatternsCache
such that it uses aLinkedHashMap
as 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 theLinkedHashMap
is 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.prompt
methods. While this isn't necessary for pages that are setup once, and only once, beforeprompt
is invoked, it is necessary in the case where the "button" elements of type "submit" in the page markup are modified after the firstprompt
invocation. 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
Match
objects for its "button" elements, or their contents, thoseMatch
objects 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 thoseMatch
objects acrossinput
invocations 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
convertSubmitInputsToButtons
method to the classesForm
andMutableMarkup
. - 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
Match
class 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.isControlEnabled
that 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
CSSPatternMatcher
class (its duties have been taken-on by the newCSSPatterns.search
method), and consequently identified and fixed an old, but never-encountered, bug inMatch.get(CSSPatterns, Results)
. - Moved the
MutableMatch
class from the "css" package to the "mutable" package, and theImmutableMatch
class to the "immutable" package. The former move allowed theMatch.set
method to be eliminated. - After 90 development versions, 1.3 has gone alpha.
- A bug in
MutableMatch.equals
has 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
,or
anddistinct
will be faster than ever when dealing with mutable markup. Form.getFormID
has 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.deleteChoices
to allow all of the "option" controls to be conveniently removed from a "select" control, presumably so a fresh set ofaddChoice
calls 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, andaddChoice
will not be able to add new ones. - When using any of the
Form.setControlValue
orForm.setControlValues
methods, supplying anull
value 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.clearControlValue
method 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.getControlValue
andForm.getControlValues
methods. - Made
Match.hasAttribute
more efficient than it was. - Added the
Match.hasNonEmptyAttribute
method to make it easy to test whether an element has an attribute of the specified name, whose value is not empty. - Added the
Match.getAncestorOfType
method 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.setControlEnable
now returns a reference to theForm
object, 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 theURLConnection
documentation 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.getAttribute
wasn't decoding the attribute value it returned. It is now.- An off-by-one error in
HTMLEntityCodec.decode
has been fixed. Numeric character entities are now decoded correctly. - Removed all "form parameter"-style terminology from the
Qwicap
class, 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:rejectParameter
andrejectParameters
have becomerejectInput
,getParameters
is nowgetFormDataSet
,hasParameters
is nowhasFormDataSet
, andembedParametersInMostRecentForm
is nowpopulateMostRecentForm
. Qwicap.rejectInput
and, 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
Qwicap
class the methodsgetAutoEmbedParameters
andsetAutoEmbedParameters
(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
prompt
method, and an implicit change to the behavior of the original method. The newprompt
method accepts aboolean
parameter that istrue
if parameter embedding should be automatic, andfalse
otherwise. (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 originalprompt
method 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.extractDataSet
method, which does the opposite ofembedDataSet
. ArrayToString
no longer producesNullPointerExceptions
when it encountersnull
elements in arrays or collections. Instead, it outputs "null" in their places.- Remodeled the growth algorithm in
RangeList
andMatchList
on the algorithm employed byjava.util.ArrayList
. - Improved the API documentation in many places.
- Improved some markup-related exception messages.
- The
MatchEnumerator
class has been replaced with a new, and much more efficient, class that both enumerates faster, and doesn't fill-up the relevant markup'sMatch
cache as it does so. The latter behavior not only reduces memory use, but means thatMatch
cache 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
Form
class is no longer a subclass ofMatch
. Any code that requires theMatch
that corresponds to the "form" element represented by aForm
object can use the newForm.getMatch
method. - The way in which
MuTagWithAttributes
keeps track of its attributes has been made more efficient. (Also tweaked theAttributeEnumerator
interface, and added a new subclass of it, in order to support those changes.) - Made the
Attribute
interface extend theNamedItem
interface, just as theRange
documentation 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
MarkupEnumeration
interface has been extended to include anextRange
method, which does exactly what thenextElement
method 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
ImTagWithAttributes
keeps track of its attributes has been made more efficient. - Documented all public methods of the
Form
class, 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,
WebParameters
was renamed toFormDataSet
(see "form data set" in the spec.),WebParameter
was 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"),FormElementInfo
becameFormControlInfo
, and all uses of the word "Parameter" were removed from method names in theForm
class and replaced, for the most part, with the term "Control", e.g. the methodsetParameters
has becomesetControlValues
, though the methodembedParameters
has becomeembedDataSet
. - Added the
Null
class which provides a set of static utility methods that perform common tasks associated with the handling ofnull
values. - Finally documented the
HTMLEntityCodec
class, and also changed itssetEncoding
method to support method invocation chaining by having it return a reference to its instance of theHTMLEntityCodec
class. (Previously, it returned nothing.) - The
Form.clearValues
method's purpose was to clear the values of all controls in a particular form whose values were user-alterable. To that end, it did not clear the values of buttons, and hidden input controls. Its failing was that it did clear the values of disabled controls (controls with a "disabled" attribute). Since those controls aren't user-alterable, that behavior contradicted the stated purpose of the method. So, the method has been eliminated, and replaced with a new method,Form.clearControlValues
that makes its behaviors more explicit, and controllable. - Fixed a bug, introduced earlier in the 1.3 development cycle as part of the
Internet-Explorer-is-hopeless-rubbish work-around for "button" elements, that
caused the method
Form.embedParameters
to be overzealous and embed parameter values into "button" elements. Since "button" elements don't have user-modifiable values, this was unnecessary, and had destructive effects if multiple buttons had the same name. - When passed an error message object that is any subclass of
Markup
, the variousQwicap.rejectParameter
methods will now insert the rejected parameter's value into the error message anywhere a tag is found with the class "qwicap-param-value". Specifically, the content of such tags is replaced with the string representation of the parameter value(s). - Corrected a bug in
Results.setContent
that prevented it from working correctly when the content to be inserted was identified by aResults
object containing more than one match. - Added a
print
method to theMarkup
class to facilitate debugging. MutableMarkup.insert
will now acceptResults
objects as a means of specifying the new material to be inserted. Ordinarily, such cases are specially handled by various methods in theResults
class, e.g.setContent
,addContent
. This change means that the expected insert functionality is available even when you're not going through aResults
object.- Wherever it can be done quickly,
HTMLEntityCodec
pre-screens material to be encoded and decoded to determine whether the encoding/decoding is unnecessary and can be skipped. This can save time and completely eliminate memory allocations from applicable invocations. - Added the methods
getLong
andgetDouble
to theMatch
class. They do just whatgetText
already does, but they attempt to interpret the text as an integer, or floating-point, value. - Finally got around to dealing with the character encoding issues associated with attribute values. (However, this new implementation might be performing encoding that isn't absolutely necessary.) The new code only acts on attributes that you've created or modified since the document was loaded. So, if you have invalid attribute values in your original document, and you don't alter them before writing-out the document, they'll be invalid in the output, too.
- Made the
Qwicap.htmlEncode
method static, because there was no reason to have made it an instance method in the first place, and added a statichtmlDecode
method in the name of symmetry. - Corrected an omission in the tag hierarchy validation code that caused it to attempt to pop from an empty stack when it encountered an entirely isolated end tag.
- The
ALStack
class now throwsEmptyStackException
when attempting topeek
orpop
from an empty stack. Previously, a less informative exception was thrown from the depths of theArrayList
class. - Reduced typical memory usage by
ImmutableMarkup
and its descendants, notablyXMLString
. - Added a
length
method toXMLString
. It returns the number of characters in the markup-bearing object that was passed toXMLString
's constructor. - Increased the efficiency of the mutable content
write
method. - Corrected a bug in
Results.getText
that could produce aStringIndexOutOfBoundsException
. - Corrected an omission in the tag hierarchy validation code that prevented it from complaining about a document that ends before a full complement of end tags were found.
- Added to
ImmutableMarkup
a new constructor that accepts aMutableMarkup
object as its sole parameter. The new constructor uses as-is all of the immutable elements present in the mutable document, and converts the mutable elements to new immutable representations. - Reimplemented
MutableMarkup.getImmutable
to use the aforementioned, newImmutableMarkup
constructor. - Corrected a problem that led to a
NullPointerException
when rejecting parameters on a page that had no current form, a situation that doesn't arise in normal usage. - Fixed a bug that prevented a form parameter value from being automatically embedded into page markup when a rejected parameter value was corrected by the user. Obviously, this only applies in situations where automatic parameter embedding is enabled, but since it's enabled by default these days, that's quite a lot of situations.
- Removed some obsolete code from the various parameter-oriented "get" methods
of the
Qwicap
class. - Implemented CSS pattern caching for all markup objects. Previously, everytime
a CSS pattern
string was passed to
Markup.get
orResults.get
it had to be parsed and a set of objects created to implement the pattern (for lack of a better term, call this "compiling"). Now, however, a cache of "compiled" patterns is maintained for each body of markup, so parsing and compiling takes place only on the first occasion a CSS pattern is used on any given markup object. While performance without pattern caching was good, it should be better now, especially whereget
invocations occur in loops. - Improved the performance of
ImmutableMarkup
and, especially,MutableMarkup
by replacing theArrayList
objects they'd been using internally with custom objects which are optimized for their respective data types and purposes. - Added a new constructor to
XMLString
which accepts an arbitraryObject
as the source of the XML markup string that is to be parsed. Specifically, the object'stoString
method is invoked, and theString
it returns is parsed. - Added a new constructor to
XMLDocument
which accepts aURL
from which the XML markup should be retrieved. Previously, it was necessary to use theQwicap.getDocument(URL)
, orXMLCache.getDocument(URL)
methods to conveniently instantiate markup from aURL
. - Added a new constructor to
ImmutableMarkup
which accepts only one parameter: a character array. The entire array is parsed. - Overrode the
toString
andwrite
methods inImmutableMarkup
to make them more efficient than the general-purpose implementations of those methods that were inherited from theMarkup
class. - Added new Javadoc documentation to a number of markup-related classes, and made a small improvement to the "Qwicap Templating Introduction" document.
- Added the
ArrayToString
utility class. It converts an array orCollection
(or any object) to a pleasantly human-readable string, but defers that conversion work until thetoString
method is called, which makes this class a very efficient way to include arrays in log entries produced by theLogger
class; if the log-level is such that the log entry is discarded, the nitty, gritty work of converting the array orCollection
to a string never takes place. - No one should use Internet Explorer for a lot of reasons, including
that it's buggy and not standards-compliant. However, because it's hard
to ensure that one's users will be running high-quality browsers, Qwicap
now includes a workaround for a large Internet Explorer bug: its inability
to correctly handle forms with more than one "button" element of type
"submit". To work around this problem without forcing developers to
rewrite, or dumb-down, their pages, the
Qwicap
class now provides theconvertSubmitButtonsToInputs
method. - Rudimentary namespace support has been added to Qwicap's XML parser. Namespaces in immutable markup are handled correctly. Namespace support in mutable markup is incomplete. For instance, inserting markup from one namespace into an area of a document that is assigned to another namespace will work correctly in the sense that the insert will take place, and namespace-aware selectors used on the document will yield correct results, but when the markup is converted to text, Qwicap won't notice the transition from one namespace to another and won't therefore generate a new namespace declaration attribute where the transition between namespaces occurs.
- Two elements of CSS3 syntax have been embraced in order to support namespaces: (1) The "@namespace" rule specifies a mapping between a namespace URI and an abbreviated name to represent it. (2) The "|" delimiter in CSS selectors for elements (not attributes at this time) which separates an abbreviated namespace name, as specified in one of the aforementioned namespace "at rules" from the rest of the CSS selector. So, a namespace aware selector string to select all of the XHTML paragraph elements in a document would look like: "@namespace xhtml url(http://www.w3.org/1999/xhtml); xhtml|p".
Version 1.2.3 of 28-Sep-2004
- Altered the way in which Qwicap embeds its hidden form- and page-ID input elements into forms. Previously they were inserted immediately before the form's first control element. If that first control element was wrapped in a "label" element, the "label" element would end-up wrapping two hidden "input" elements in addition to the control element it was supposed to be wrapping. Unfortunately, that confused the Firefox browser. Now, if the first control element of a form is wrapped in a "label" element, the hidden form- and page-IDs are embedded immediately before the "label" element.
Version 1.2.2 of 28-Sep-2004
- Improved the class
documentation for the
Results
class. It now provides a break-down of the methods grouped by their purposes. - Improved the error messages supplied by many exceptions.
- Corrected a bug in some file caching logic.
- Added the
IF
,ELSE
, andENDIF
methods to theResults
class in order to support in-line logic within method invocation chains. Whentrue
is passed toIF
, it returns an equivalent to the currentResults
object, but whenfalse
is passed, it returns an emptyResults
. TheELSE
method reverses that outcome, and theENDIF
method returns theResults
object on whichIF
was invoked. NestedIF
invocations are not supported. Also unsupported is use of theELSE
andENDIF
methods either out-of-sequence, or without a precedingIF
invocation. - The Intellij IDEA project files included with the Qwicap source have been upgraded from version 3 to version 4.5 format.
- Added the
Form.setParameters
methods to provide some symmetry with the pre-existingResults.setContents
andResults.setAttributes
methods. - Changed all of the parameter-oriented methods of the
Qwicap
andForm
classes such that where they used to accept parameter values asString
objects, they now accept any type of object. Since the values are inevitably sent and received as text, it is a given that whatever type of object is passed as a parameter value, Qwicap will end-up converting it to aString
by calling itstoString
method. Nonetheless, by accepting values asObject
s, things should occasionally be more convenient for application developers, and auto-boxing should further increase the convenience level, when it arrives. - Removed the
Qwicap.checkException
method which was useless to clients, and unused by any of the Qwicap code. - Added the
Qwicap.getBoolean
methods to retrieve parameters that may have at most two values and translate them into the primitiveboolean
type. - Modified the various parameter retrieval methods in
Qwicap
such that the error messages they generate use curved left- and right-double quotes to enclose their values, instead of the conventional, straight double-quote character. - Improved the class
documentation for the
Qwicap
class. It now provides a break-down of the methods grouped by their purposes. - Improved the
MutableMatch
class such that it throws an exception (NoSuchElementException
) with a long, and hopefully informative, error message whenever an operation is attempted on a markup element that no longer exists. (It used to throw the same exception, but without any message.) One way to encounter this error is to perform a multi-pattern search, e.g."*.these, *.those"
, on a body of markup where the search patterns produce aResults
object containing overlapping sets of matches, and then to invokeResults.delete
. Among the overlapping matches, the first delete of any given element will succeed, but the next one will throw the aforementioned exception, since the element to be deleted no longer exists. This is a rare situation, and easily avoided by using theResults.distinct
method before thedelete
, but was very confusing in the absence of an explanatory error message. - Added the
Qwicap.rejectParameters(String[] ParamNames, String[] ParamValues, Object ErrorMessage)
method, and recoded all of the pre-existingQwicap.rejectParameter
methods so that they are merely front-ends for the newrejectParameters
method. Thus, there is only one body of parameter-rejection logic. - Removed the
Qwicap.rejectParameters(String[] ParamNames, Object ErrorMessage)
method that was introduced in version 1.2. Use the newQwicap.rejectParameters(String[] ParamNames, String[] ParamValues, Object ErrorMessage)
method instead. You can passnull
as theParamValues
parameter to achieve the same result. - Enhanced the code that searches-out the (potential) hierarchy of labels
associated with any control in a form. It now searches outside of the
form
element that contains a control, just in case theform
is contained within afieldset
element. (When the code was originally written, I hadn't realized that usingfieldset
outside of aform
was legal, which it is, even in XHTML 1.0 Strict.) - Improved the parameter rejection logic such that the error messages are
inserted just before the outer-most enclosing element (
form
orfieldset
) of the controls that supplied the rejected parameters. - Improved the parameter rejection logic such that parameters that did not originate in the most recently submitted form can also be rejected, provided that the current page contains at least one form that could have supplied them. This is a big help with pages that contain multiple forms which are used together.
Version 1.2.1 of 30-Jul-2004
- The
Qwicap.getInt
andQwicap.getLong
methods weren't displaying their bad-parameter error messages properly in some situations. This has been fixed. - In the Qwicap API documentation, and in some comments in the Qwicap source code, instances of the word "get" had been replaced by the word "getInstance", due to the inattentive application of an aggressive refactoring tool. These have been corrected.
Version 1.2 of 29-Jul-2004
- The
Qwicap.getVersion
method has been added to provide developers an indication of which version of Qwicap they're using. IncompleteTagException
now provides an informative error message, instead of no message at all.- Added the
Qwicap.getForm
method which returns aForm
object for manipulating the form that supplied the current parameters (the parameters available by callingget
,getString
,getInt
,getDouble
, etc.). - Added the
Qwicap.rejectParameters
method to handle cases where multiple form elements contain the data that caused the form input to be rejected. Added theForm.getFormElements
method to supportQwicap.rejectParameters
. The
Qwicap.rejectParameter
method has been changed such that the error message parameter it accepts can be any class of object, not justString
as used to be the case. Internally, the error message is inserted usingMutableMarkup.insert
which has a number of useful behaviors, including automatic HTML-encoding ofString
objects, and embedding of the stack-traces fromThrowable
objects, such as exceptions. The one drawback of this change is that it eliminates the feature of the previousrejectParameter
implementation that allowed the supplied error message string to be an XHTML fragment into which things like the name of the form field that supplied the bad parameter could be automatically embedded. That embedding functionality survives, but only when the supplied object is a subclass ofMarkup
(XMLString
can be quite convenient in this situation). In order to regain the convenience of passing XHTML fragments asString
objects, use the newQwicap.rejectParamter(String ParamName, String ParamValue, boolean ErrorMsgIsXHTMLFragment, String ErrorMsg)
method with the parameterErrorMsgIsXHTMLFragment
set totrue
.The previous
rejectParameter
implementation suffered from two shortcomings: (1) a lack of flexibility in that it only accepted error messages as strings, and (2) by making the HTML-encoding of the error message string the responsibility of the developer, it was likely to give rise to situations where strings were accidentally passed without the necessary encoding, an oversight which could result in XML parsing exceptions, or cross-site scripting attacks. A developer could still create either problem by passing a bad error message string to the newrejectParameter
method with itsErrorMsgIsXHTMLFragment
parameter set totrue
, but at least they'll have to explicitly assert that they're supplying a valid XHTML fragment (which indicates to Qwicap that HTML-encoding is not to be performed), rather than accidentally overlooking the issue.- The
Qwicap.embedParametersInMostRecentForm
method is now called automatically byQwicap.prompt
after each set of form parameters is received. I believe this will be more consistent with developer expectations and/or convenience than making developers invoke it manually. Where this automatic behavior might be inappropriate, or useless, it can be controlled using the newQwicap.setAutoEmbedParameters
method. The state of the behavior can be determined using the newQwicap.getAutoEmbedParameters
method. - Setting the value of an "input" form element of type "checkbox" or "radio" now works correctly. Previously, the value of those elements was first cleared by deleting the "checked" (correct) and "value" (incorrect) attributes of the specified group of those elements (all those with matching "name" attributes), then setting the "checked" attribute of the approiate radio/checkbox item. Unfortunately, with the "value" attribute deleted, the code would never find the appropriate radio/checkbox item, and even if it had, the item would have been useless as a form element, since it no longer had a value to supply.
- The CSS2 parser has been made more correct. The CSS2 specification appears to be ambiguous on a number of subtle points, so there doesn't seem to be any way to say with certainty that the parser is correct even now, but it is more correct than it was. The most prominent improvement in the CSS2 parser is that escape sequences are now supported.
- The ":lang()" pseudo-class is now supported in CSS2 selectors.
- The
Form.disableParameter
andForm.enableParameter
methods have been added to provide abstract form element disabling/enabling functionality. - Methods like
Results.setContent
that ultimately invokeMutableMarkup.insert
, will now acceptnull
in place of a valid content object. The string "null" will be inserted in such cases. Previously, aNullPointerException
was thrown. - Methods like
Results.setContent
that ultimately invokeMutableMarkup.insert
, will now accept arrays and objects that implement theCollection
interface. In both cases, 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 ofbyte
orByte
arrays, will be displayed as unsigned decimal quantities. This seemed like it would be more useful to most developers than displaying signed quantities.) - Methods like
Results.setContent
that ultimately invokeMutableMarkup.insert
, will now acceptThrowable
objects, and all subclasses thereof, notablyException
. If theThrowable
has a message, that message is inserted. If it does not, the fully-qualified name of theThrowable
's class is inserted. In either case, theThrowable
's stack trace is then marked-up as an XHTML comment block and inserted, so the end-user will not see it, but the developer can view the page source to retrieve the stack trace. - The
Qwicap.reportException
method has been added. When you encounter anException
(or anyThrowable
) that you want to catch and report to the user, pass it toreportException
and the next time you invokeQwicap.prompt
orQwicap.goodbye
an error message describing the exception will automatically be inserted as the first item in the document's "body" element. (Also, the associated stack trace will be embedded in a comment block within that error message.) If the same document object is subsequently passed toQwicap.prompt
orQwicap.goodbye
, the error message will be removed before the document is transmitted to the client. - The
Qwicap.hasParameters
method has been added. It returnstrue
if any form parameters are available, orfalse
otherwise.
Version 1.1 of 29-Apr-2004
- "Page Abandonment" - It is now possible to use a browser's "back" button to return to a previous page generated by a Qwicap application and to successfully interact with that page, provided that the method that supports the page is still in the call chain, and the page in question is the most recent version of itself. This process is handled transparently to client code. Until now, going back to previous pages wasn't possible.
- "Form Abandonment" - It is now possible, on multi-form pages, to interact with a different form even while the form with which you had been interacting is in an input correction loop. This process is handled transparently to client code.
- The
Qwicap.parameterRejected
method has been removed. Use the new Prompt Pattern in place of it and all associated logic. This change was required to make transparent form and page abandonment possible. - HTTP file upload is integrated into Qwicap, thanks to the Apache Jakarta Project's
Commons FileUpload library.
Just set a "form" element's "enctype" attribute to
"multipart/form-data", and include an "input" element whose
"type" attribute is "file", and you're in business. Uploaded files are handled like any
other form parameters, so their contents can be retrieved, where appropriate, with
pre-existing parameter retrieval methods like
Qwicap.getString
, while more complete functionality is available from the newQwicap.getUploadedFile
method. By default, files up to 16 K are accepted and stored in memory, while larger files are rejected. TheQwicap.setUploadedFileLimits
method is used to alter upload-related settings. - The
Qwicap.has
method was added. It tests for the presence of a particular form parameter in the current parameter set, returningtrue
if it exists, andfalse
otherwise. - The
Form.addChoice
method was added. It adds a choice to a pre-existing "select" element, group of radio buttons, or checkboxes. To supportaddChoice
, theForm.createChoice
method was added. It creates the markup for a new choice ("option", "radio", or "checkbox"). - Improved white-space handling when using methods that extract text from a section
of XHTML markup, for instance
Results.getText
. - The previous HTML character encoder has been replaced by a new HTML character codec.
The codec handles all
character entities defined in the HTML 4 spec. This alone is a significant
improvement, but, because the codec also does decoding (or it wouldn't be a codec),
methods like
Results.getText
, which extract text from markup, now use it to map encoded characters to their Unicode equivalents. This is important because it allows such extracted text, or any portions thereof, to be inserted back into markup without becoming double-encoded. - A
getType
method was added to several classes dealing with XHTML markup includingMatch
andResults
. It returns the type of the referenced tag, for example: "a", "img", "table", "form". - The
MutableMarkup.getImmutable
method was added. It convertsMutableMarkup
to a newImmutableMarkup
object by rendering the mutable material to a new backing store, and creating a newImmutableMarkup
object to represent its contents. This provides a pleasant symmetry with the pre-existingImmutableMarkup.getMutable
method, and is probably terribly useful for something. - Automatic document titling - Because markup isn't allowed in the content of XHTML "title" tags, the Qwicap templater can't be used to do convenient things like inserting material into "span" elements in titles. To work around this problem, Qwicap now automatically sets the contents of a document's "title" tag to the text of all tags in the body of a document that have been assigned a class of "qwicap-title". (If no tags with that class are found, the contents of the "title" element are left untouched.) One way to utilize this feature is to assign the document's "h1" tag the class "qwicap-title", then use the templater to build its contents. Just before sending the document to the client, Qwicap will automatically set the "title" tag to the text of the "h1" tag. Alternately, if it weren't appropriate for the "h1" tag and title to be identical, something like an invisible paragraph could be used instead of the "h1".
Qwicap.clearMostRecentForm
andQwicap.embedParametersInMostRecentForm
used to throw an exception when the internal page stack was empty; now, they do nothing in that case.- Added the method
Qwicap.getDocument(URL)
to make loading documents from URLs convenient. - Many internal changes to support page and form abandonment.
- Ant build scripts improved. They now handle compilation of the source.
- Sample code updated.
- Many improvements to the documentation.
Version 1.0.2 of 13-Mar-2004
-
XMLCache
can now read documents fromURL
s, which provides a work-around for security manager prohibitions against local file-system access. Note that while the cache automatically updates when a cached file is found to have been modified, the same is not true for documents retrieved from URLs; changes to them are not detected. -
XMLDocument
can now read documents fromInputStream
s. Previously, it could only read them from files. -
Results.or
,Results.and
, andResults.xor
methods added, for computing the union, intersection, and, um, whatever the opposite of an intersection is called, for any two Results objects. The resultant set is returned in a new Results object. -
Convenience method
Results.setAttributes
added (it parallels the existingResults.setContents
method). - Corrected an omission that could prevent forms containing one or more "button" elements from being handled correctly.
-
Exposed the internal
Form
class such that it can be utilized in code that uses only the Qwicap templater, rather than the complete Qwicap system. TheForm
class greatly simplifies certain aspects of the manipulation of forms. See theForm
class, along with methodsMutableMarkup.getForm
andResults.getForm
. (Also had to expose theWebParameters
class.) - When inapplicable parameters are sent to the current page's form, typically because the user clicked the "back" button in their browser and then attempted to interact with a form in one of the earlier pages, an explanation of the problem is logged, the parameters are discarded, and the current page is automatically re-sent to the client. Previously, an exception was thrown and the client received no page at all.
-
Results.addContentAfter
was doing exactly the same thing asResults.addContentBefore
. It now does what it's supposed to do. -
HTMLEntityMap
no longer regards tabs as unprintable characters. - Minor tweaks and corrections to the API documentation.
Version 1.0.1 of 13-Nov-2003
-
Authentication & Authorization harness added. See the
Auth2Scheme
interface documentation for details. (Ask about Fat Cookie support.) -
Replaced all calls to
System.out.println
with calls to thejava.util.logging
package. - Changed the roots of package names from "edu.utexas.its.tn.qwicap" to "edu.utexas.its.eis.tools.qwicap".
- Broke-out the example code into separate projects that are smaller, and more-comprehensible than the original all-in-one distribution.
- Improved the associated Ant build scripts (they now produce WAR files, for instance), but you still have to perform the actual "building" of the code by using the IntelliJ "Make Project" feature before running the Ant scripts. (Yes, this ought to be fixed one of these days.)
- A few, small bug fixes.
Version 1.0 of 30-Sep-2003
- First release.
Version 1.0d2 of 10-Jun-2003
- Work begins on the CSS selector engine.
Version 1.0d1 of 6-Jun-2003
- Work begins on the XML templating engine.
Version 1.0d0 of 4-Jun-2003
- Work begins with code to prove the thread-for-each-session, block-to-prompt, unblock-on-form-data-set-arrival concept.