I don't want to change any FOP code! And if I have
to change any FOP sources to add an extension, then FOP doesn't
support extension with the meaning of extension as I understand it.

[Glen]

From what I understand a program may not change its
own source code while it is running so we may not have
complete freedom for everything.

I don't know exactly what you mean. I don't think that such a thing is required to have extensible validation for extensions.


An extension mechanism where I can put an unmodified
fop.jar and myextension.jar on the CLASSPATH and have it work is
a defining issue to me.

OK, this looks like a nice feature to have, and the modifications made to FOP in this regard can be helpful to others who have similar work to do.

Here's what I see:

Option #1:

1.) myextension.jar will need a FOElementMapping [1]
subclass that will reroute fo:Block from Block.java to
FinnBlock.java. Have FinnBlock.java override the
vCN() for the new validation rules.

This would eventually cause a conflict with the GlenBlock.java from an extension written by you.



My own unfinished thinking goes more along the lines of viewing the validation between parent and child node as a lookup into a 2-dimensional table where each row is the parent and each column is the child id. The cell then contains the code snippet to check if the child is valid.


           |  fo:root  | fo:layout-master-set | fo:block   |  fo:inline
--------------------------------------------------
fo:root       invalid            valid           invalid       invalid
fo:block      invalid           invalid           valid         valid
...

This way an extension can extend the table by putting its own validation code into the intersection between fo:block and my:extension.

The state values that is collected during the vCN should be stored in validation context that is associated with the node and passed into the validation snippet.

The validation for Block could then be implemented with something like this:

class BlockValidation implements Validation {
    public void validated(Locator loc, FObj parent, int childNode,
                          ValidationContext ctxt) throws Exception
    {
        BlockValidationContext bctxt = (BlockValidationContext) ctxt;
        if (childNode == FO_MARKER) {
             if (bctx.blockOrInlineItemFound ||
                 bctxt.initialPropertySetFound) {
               nodesOutOfOrderError(loc, "fo:marker",
                    "initial-property-set? (#PCDATA|%inline;|%block;)");
            }
        else if (childNode == FO_INITIAL_PROPERTY_SET) {
            if (bctxt.initialPropertySetFound) {
                tooManyNodesError(loc, "fo:initial-property-set");
            } else if (bctxt.blockOrInlineItemFound) {
                nodesOutOfOrderError(loc, "fo:initial-property-set",
                    "(#PCDATA|%inline;|%block;)");
            } else {
                bctxt.initialPropertySetFound = true;
            }
        } else if (isBlockOrInlineItem(childNode)) {
            bctxt.blockOrInlineItemFound = true;
        } else {
            invalidChildError(loc, nsURI, localName);
        }
    }
}

Here the BlockValidation is a singleton instance that is placed into each cell along the fo:block row in the table. And the BlockValidationContext is a class that hold the state variables for a block.

I have not look at enough of the new validation code to know if my approach is powerful enough.

regards,
finn

Reply via email to