DocWriterNew to generate the
XML configuration schema used by Frank developers.See: Description
| Interface | Description |
|---|---|
| CumulativeChildHandler<T extends ElementChild> |
Callback interface for
FrankElement to walk all declared as well as all inherited attributes or config children. |
| Class | Description |
|---|---|
| AttributeEnum | |
| AttributeEnumValue | |
| ConfigChild | |
| ConfigChildSet |
Holds the list of all cumulative config children sharing some role name, say R, but
only if there is no ancestor having the same config children for role name R.
|
| DigesterRule |
Java representation of a digester rule specified in the digester-rules.xml file.
|
| DigesterRulesHandler |
Parses file digester-rules.xml.
|
| ElementChild |
Base class of FrankAttribute and ConfigChild.
|
| ElementRole | |
| ElementRole.Key | |
| ElementType |
Models a collection of FrankElement.
|
| FrankAttribute | |
| FrankDocGroup | |
| FrankDocModel | |
| FrankElement |
Models a Java class that can be referred to in a Frank configuration.
|
| FrankElementFilters | |
| FrankElementStatistics | |
| ObjectConfigChild | |
| ParsedJavaDocTag | |
| TextConfigChild |
| Enum | Description |
|---|---|
| AttributeType | |
| ConfigChildGroupKind | |
| MandatoryStatus |
DocWriterNew to generate the
XML configuration schema used by Frank developers. Please note that DocWriterNew is
presently not used; this class is under development.
Class FrankElement models a Java class of the Frank!Framework that can be accessed from a
Frank config. An example is FrankElement nl.nn.adapterframework.parameters.Parameter,
which you can reference in a Frank config with the tag <Param>. The modeled Java class
can have a superclass, which is expressed by the link named "parent".
A tag in a Frank config can contain other tags. A <Receiver> can
for example contain <DirectQuerySender> or
DirectQueryErrorSender. These two tags reference the same Java class, namely
nl.nn.adapterframework.jdbc.DirectQuerySender, but the first tag uses
it as a Sender while the second tag uses it as an ErrorSender. The model expresses a set
of allowed child tags by relating a containing FrankElement to an ElementRole.
An ElementRole has a property roleName to express the role and references
an ElementType to define what child FrankElement objects can appear. Each
ElementType has one or more FrankElement objects as members.
There are two
flavors of ElementType objects. Some ElementType objects model a Java
interface. In this case, the members are the FrankElement objects that model
the Java classes that implement the Java interface. Please note that not every Java interface
that appears in the Java source code is modeled by an ElementType object. An
ElementType object appears only for Java interfaces that are relevant for nesting
tags in a Frank config. Some ElementType objects model Java interfaces that have
an inheritance relation. This inheritance is expressed in the model using the "highest common interface"
relation. This relation is needed for some corner cases of generating the XML schema file.
Other ElementType objects
just model a single Java class, which is expressed by a reference to the corresponding
FrankElement as the only member.
There is no direct relation between FrankElement an ElementRole, because the
relation between a parent tag and a child tag requires some additional information.
DocWriterNew requires information on how often a child tag can appear, whether
usage of the child tag is deprecated, and some other information. This additional information
is included in class ConfigChild, which also references the FrankElement of
the parent tag and the ElementRole for a set of allowed child tags.
Tags in Frank configs can have attributes, which are modeled by class FrankAttribute.
Attributes have a type that is modeled by AttributeType (not in diagram).
String attributes can have their values restricted by a Java enum type. In that case, the list of allowed values is stored in a
AttributeEnum, which can be shared by multiple FrankAttribute.
The tag in which the attribute occurs is modeled by its FrankElement, see relation
"attribute of". The documentation of an attribute may appear in a Java class that differs
from the attribute owning Java class (the IbisDocRef Java annotation). This is expressed
by the relation "described by".
FrankElement only hold the attributes and config children that are
declared by the modeled Java class. Attributes or config children owned by inheritance are not modeled
directly as children. FrankElement has methods to browse
inherited children, which need a callback object of type CumulativeChildHandler.
This functionality works the same for attributes and config children. Therefore,
FrankAttribute and ConfigChild
have a common superclass ElementChild. That class also
parses IbisDoc annotations, which is done the same way for config children and attributes.
The model is not only used to generate the XML Schema file (ibisdoc.xsd). It is also
used to generate a website with reference documentation. That website documents all tags
(FrankElement objects) that can be used. The FrankElement objects are grouped
by the implemented Java interface (interface-implementing ElementType objects). There
is an additional group "Other" for all FrankElement that belong to a non-interface-based
ElementType (e.g. nl.nn.adapterframework.core.PipeForward). These table-of-contents (TOC)
groups are modeled by model class FrankDocGroup.
Class FrankDocModel holds the entire model (not shown in the diagram). Two model classes
have not been explained yet: ConfigChildSet and
ElementRoleSet. These have been introduced to avoid conflicts
in the XML schema file. These conflicts are explained in the next section.
FrankElement models a Java class that Frank
developers reference using an XML tag. Method FrankElement.getXsdElementName(ElementRole)
calculates the name of this XML element. Remember that XML elements in Frank configs not only
express the referenced Java class but also the role in which this Java class is used. This is
why the method has an ElementRole argument.
FrankElement-s in
FrankDocGroup "Other",
like <Forward> and <Param>, are
named in a special way. They usually belong to a single
ElementRole. Their name is
based on the syntax 1 name of that ElementRole.
This way of naming introduces potential conflicts when deprecated
FrankElement-s are included. These potential conflicts
are explained in the following subsections, with the solutions applied to prevent them. There are
also some other potential conflicts. These are explained as well.
nl.nn.adapterframework.core.PipeLine.addPipe(nl.nn.adapterframework.core.IPipe).
The resulting config child has an ElementRole
that we can express as (IPipe, pipe), IPipe representing the
ElementType and "pipe" is the syntax 1 name.
The members of this element role include the following:
nl.nn.adapterframework.pipes.FixedResult and nl.nn.adapterframework.pipes.FixedResultPipe.
Method FrankElement.getXsdElementName(ElementRole) gives
them the same name, which is FixedResultPipe.
To avoid this type of conflicts, element role member conflicts, we do the following for each
ElementRole.
We collect all members (FrankElement) and group them by
the XML element name that these members get for the role. When an XML element name
is shared by multiple FrankElement-s, we assume
that the conflict has arisen because the core team intended to rename the Java class behind
the element name. The old Java class is needed for backwards compatibility,
but it has been deprecated to support resolving the conflict. This assumption allows us
to omit the deprecated FrankElement-s. We
emit a warning in case the conflict remains unresolved.
<Listener className="nl.nn....">.
This element is allowed as a child of each XML element that is allowed already
to contain a particular listener as child, for example as a child of <Receiver>.
We say that <Listener> is the generic element option of
<Receiver>.
Our XML schemas should specify which
FrankElement-s are allowed as
children of a generic element option. These FrankElement-s
do not have to be written out explicitly, because we can reference
XML schema groups that are based on ElementRole-s,
the member children. The member children of an ElementRole
are found by collecting all config children of all members, and taking
the ElementRole of each
ConfigChild. The generic element
option is defined by adding a group reference for each relevant member child, the
set of relevant member children depending on the XML schema version being created.
In some cases, multiple ElementRole-s have to
share a generic element option. The example is
nl.nn.adapterframework.batch.StreamTransformerPipe. It has
config children with the followin ElementRole-s:
<Child>,
the XML schema would be invalid. If the parser would encounter <Child>, it
would not know which definition to apply.
This potential conflict is resolved by merging config children. When a
FrankElement has cumulative
config children sharing a syntax 1 name, then these config children
are merged. This check is done by method FrankElement.hasOrInheritsPluralConfigChildren(java.util.function.Predicate, java.util.function.Predicate),
which takes Predicate arguments that express
the XML schema version being created. Config children sharing a common
syntax 1 name for the XML schema version being created are called "plural config children".
To be able to handle plural config children, we introduce model entity ConfigChildSet.
All cumulative config children of a FrankElement are grouped
by syntax 1 name, and each group results in a ConfigChildSet.
We use ConfigChildSet-s instead of ConfigChild-s
to fill XSD element groups, resulting in common code for plural and non-plural config children.
nl.nn.adapterframework.core.IListener.
There is a potential conflict because there are Java interfaces that inherit from
nl.nn.adapterframework.core.IListenernl.nn.adapterframework.pipes.PostboxRetrieverPipe with
ElementRole (IPostboxListener, listener).
We also have nl.nn.adapterframework.pipes.SenderPipe with
ElementRole (ICorrelatedPullingListener, listener).
These two pipes are members of role (IPipe, pipe). There is a generic element
option <Pipe> that can have an element <Listener>.
But if both listener ElementRole-s
(IPostboxListener, listener) and (ICorrelatedPullingListener, listener) would
be used to define the <Listener>, a conflict would result.
If the parser would encounter <Listener>, it would not know
which of the two definitions to use.
This conflict is resolved by promoting the two ElementRole-s
to (IListener, listener). Every ElementRole
is used only once and thus this promotion resolves the conflict. We call it the
"highest common interface", which is calculated by method
ElementRole.getHighestCommonInterface().
ElementRole
(IErrorMessageFormatter, errorMessageFormatter) which has
FrankElement
nl.nn.adapterframework.errormessageformatters.ErrorMessageFormatter
as member. Element groups including a generic element option
<ErrorMessageFormatter> cannot also define
XML element <ErrorMessageFormatter> to reference
Java class nl.nn.adapterframework.errormessageformatters.ErrorMessageFormatter.
This conflict with the element name of the generic element option is found
by method ElementRole.getDefaultElementOptionConflict()
by that XML element.
FrankElement
nl.nn.adapterframework.batch.AbstractRecordHandler. It has the following
ElementRole-s:
ElementRole-s, so these
would both define XML element <Child>. This is not possible. Syntax 2
does not provide the option to reference Java class InputfieldsPart
or OutputfieldsPart in role "child". This is not a big issue, because
they are available in roles "inputFields" and "outputFields". Furthermore, they can
still be expressed in syntax 1: <Child className="...InputfieldsPart">.
The config child setters for (InputfieldsPart, child) and (OutputfieldsPart, child)
are deprecated. One could wonder why we do not try to resolve the conflict by
omitting deprecated config children. In theory, a FF! version could have
existed in which the config child setter for (InputfieldsPart, child) was not deprecated.
Then that version could define <Child> to reference
Java class InputfieldsPart in role "child". We do not want this, however,
because it threats backward compatibility. We would have old Frank configs including
<Child>, but they would be incorrect now because of the conflict.
To detect member conflicts in shared generic element options, the model has entity
ElementRoleSet. Each
ConfigChildSet is linked to an ElementRoleSet
that has the element roles of the config children of the ConfigChildSet
as members. When multiple ConfigChildSet-s reference the
same set of ElementRole-s, then they reference
a common ElementRoleSet object. Each
ElementRole knows the ElementRoleSet-s
it belongs to. ElementRole uses this information to
omit members that would conflict with a shared generic element option. Class
ElementRoleSet is not public, because
ElementRole takes care of calling
ElementRoleSet.
org.frankframework.frankdoc.testtarget.exotic. There is a class
Master with ElementRole
(IMember, part). This role has no FrankElement-members
with plural config children, but there is still a conflict. All child members of this role should
be used to find child XML elements of <Master><Part>.... We have
FrankElement-s Member1 and
Member2 that have config children with the following ElementRole-s:
(Child1, child) and (Child2, child). These are not interface-based, but we cannot
define element <Master><Part><Child> to reference
them both. We would have two conflicting definitions, because it is not clear whether this
XML element would reference to Child1 or Child2.
We solve this issue by omitting syntax 2 elements for Java classes Child1 and Child2.
These classes are only available through syntax 1: <Child className="...">.
This is implemented in two places. First, we introduce more ElementRole
objects. For each ConfigChildSet-based
ElementRoleSet, we introduce new
ElementRoleSet-s by calculating the member
children and grouping them by syntax 1 name. We do this recursively. The recursion
will stop because the recursion will find sets of element roles that correspond
to existing ElementRoleSet objects.
Omitting syntax 2 elements for these conflicts is also done in DocWriterNew.
The example shows that the contents of a generic element option does not
necessarily correspond to a ConfigChildSet.
To fill a generic element option, we need to get a Set of
ElementRole holding the roles that are
selected for the XML version being created. Then we have to calculate member children
recursively from these element role sets. The model provides static method
ConfigChildSet.getMemberChildren(java.util.List, java.util.function.Predicate, java.util.function.Predicate, java.util.function.Predicate)
to support this. We cannot use ElementRoleSet
for this in DocWriterNew, because DocWriterNew
has to filter roles for the chosen version of the XML schema. Class ElementRoleSet
works without filtering role. That class has to find conflicting FrankElement,
the conflicts not being affected by the version of the XML schema being created.
Copyright © 2022 Ibissource.org. All rights reserved.