FactoryParmManager Description

The FactoryParmManager annotation may be applied to the class definition for a subclass of NamedObjectFactory, and will be ignored if applied to other classes. If the subclass of NamedObjectFactory is a generic class, the corresponding ParmManager will also be a generic class with the same type parameters. The class name of the ParmManager is specified by this annotation's value element.

Additional elements can be provided for CompoundParmType in order to specify resource bundles used for tips, labels, and parameter documentation for the class being annotated. The resource bundles are defined by property files that use annotation value elements as keys. Annotations that provide such keys are PrimitiveParm, KeyedPrimitiveParm, CompoundParm, and KeyedCompoundParm.

For a string associated with a key in a label or tip resource bundle to contain HTML constructs, the string must start with <html> and end with </html>. For the HTML case when the lsnof program is used, each <br> element will be replaced with a space for these two resource bundles, and the </html> and </html> elements will be removed from the start and end of the string respectively. Strings associated with parameter-documentation resource bundles are assumed to be HTML fragments with one additional element. These can be inserted as-is into HTML documents and must be formatted so that they can fit between a <DIV> element and a matching </DIV>. The additional element is named JDOC and its contents use the same convention as the Javadoc @link directive. The class name and optional method or field will be turned into a link to the corresponding API documentation.

In some cases, the parameter name consists of those provided by multiple annotations, with a delimiter ("." by default) separating each component. It is worth noting that the simulation and animation classes in the BZDev class library, when used with a scripting environment, assume that the delimiter will be ".".

The ParmManager class that is generated will have the same type parameters as the factory it annotates. These must be replicated literally when an instance is defined. For example,


    @FactoryParmManager(value="AbstractFooFactoryPM")
    public abstract class AbstractFooFactory<OBJ extends Foo> {
       ...
       AbstractFooFactory<OBJ> pm;
       protected AbstractFooFactory(Animation2D a2d) {
          pm = new AbstractFooFactoryPM<OBJ>(this);
          initParms(pm, AbstractFooFactory.class);
       }
    }
If this is not done, type-erasure errors will occur at compile time.

In actual use, one will also specify various resource bundles. These are used to internationalized documentation. The resource bundles specify

  • labels. A label is a name that might be displayed by a GUI (Graphical User Interface).
  • tips. A tip is a short description suitable for a tool tip - text that will appear when a mouse 'hoovers' over a control.
  • documentation. Documentation consists of extended HTML text that can be used for a detailed description.
Each resource bundle defines a series of properties whose keys are the factory's parameter names. With resource bundles, the previous example becomes

    @FactoryParmManager(value="AbstractFooFactoryPM",
                   labelResourceBundle="*.lpack.FooFactoryLabels",
                   tipResourceBundle="*.lpack.FooFactoryTips",
                   DocumenationResourceBundle="*.lpack.FooFactoryDocs")
    public abstract class AbstractFooFactory<OBJ extends Foo> {
       ...
       AbstractFooFactoryPM<OBJ> pm;
       protected AbstractFooFactory(Animation2D a2d) {
          pm = new AbstractFooFactoryPM<OBJ>(this);
          initParms(pm, AbstractFooFactory.class);
       }
    }
The wildcards expands to the current package. When wildcards are used the properties must be placed in a subpackage whose first component is "lpack". With java modules, this package must be an open package: otherwise the resource will not be visible where it is needed. If the factory class definition contains multiple type parameters, those type parameters must be used for the parameter manager in the same order, and the last one in the list must refer to the type of the named object being created.

A FactoryParmManager declaration will typically be used for abstract factories. When the type of the object such a factory initializes is not an abstract class, there should be a corresponding factory to actually create the object. In most (but not all) cases the code for these additional factories is similar. For the typical case, one can add an element, stdFactory, to the FactoryParmManager annotation so that this factory will be automatically generated. For example,


    @FactoryParmManager(value="AbstractFooFactoryPM",
                   labelResourceBundle="*.lpack.FooFactoryLabels",
                   tipResourceBundle="*.lpack.FooFactoryTips",
                   DocumenationResourceBundle="*.lpack.FooFactoryDocs",
                   stdFactory="FooFactory",
                   namerVariable="a2d",
                   namerDocumentation="the animation")
    public abstract class AbstractFooFactory<OBJ extends Foo> {
       ...
       AbstractFooFactory<OBJ> pm;
       protected AbstractFooFactory(Animation2D a2d) {
          pm = new AbstractFooFactoryPM<OBJ>(this);
          initParms(pm, AbstractFooFactory.class);
       }
    }
In this example, the type of factory that creates a 'Foo' object is FooFactory, its single-argument constructor has an argument named "sim", and the Javadoc comment for "sim" is "the simulation". The namerVariable and namerDocumentation elements are optional, but should generally be provided to make the Javadoc API documentation clearer. When the stdFactory element is included, the type of the named object being created must be provided as the last type parameter listed.

In some unusual cases, one may want to use a FactoryParmManager annotation when no ParmManager is needed (e.g., when creating a subclass that removes a factory parameter defined by a superclass. In this case, the value element can be set to an empty string:

    @FactoryParmManager(value="",
                   stdFactory="Foo1Factory",
                   namerVariable="a2d",
                   namerDocumentation="the animation")
    public abstract class AbstractFoo1Factory<OBJ extends Foo1>
    extends AbstractFooFactory<Obj>
    {
       protected AbstractFoo1Factory(Animation2D a2d) {
          super(a2d);
          removeParm("foobar");
       }
    }

Recommended options for the java compiler (we assume the command-line syntax used in Sun Microsystem's implementation) for non-modular jar files are


 javac -d CLASSES -s TMPSRC \
        -classpath /usr/share/java/libbzdev.jar:CLASSES \
        FILES...
where CLASSES is the name of a directory containing the class files (with subdirectories matching the package hierarchy), TMPSRC is a directory for files created by the annotation processor, and FILES... is a list of source files (with directories matching the package hierarchy). Without CLASSES in the class path, you may get a warning about implicitly compiled files. Without the '-s' flag, automatically generated java files will appear in the CLASSES directory. One should also list the fully qualified class names of each non-abstract factory provided in a JAR file, one per line, in the file
META-INF/services/org.bzdev.obnaming.NamedObjectFactory
that will appear in the same JAR file (this uses the same conventions as those used by Java's service-provider interface). In particular, the program lsnof uses the information contained in this file. When creating javadoc files (for the non-modular case) one can use the following commands

    javadoc -d TARGET -sourcepath .:TMPSRC \
       -classpath CLASSES \
       FILES...
where TARGET is the directory that will contain the API documentation generated by javadoc and FILES are the files to document, and should include the source files in TMPSRC.

When modules are used, one will typically create a directory named mods and a subdirectory mods/MODULE where MODULE is the name of the module (e.g., com.foo.bar). One will also create a directory tmpsrc and a corresponding subdirectory tmpsrc/MODULE. A typical compiler command, assuming the source code is in a directory src, is


   javac -d mods/MODULE -p /usr/share/bzdev -s tmpsrc/MODULE \
         --processor-module-path /usr/share/bzdev \
         src/MODULE/module-info.java src/MODULE/DIR/*.java
where DIR is the directory corresponding to a package name following the usual Java conventions (e.g., com/foo/bar for the package com.foo.bar). Placing generated source files in tmpsrc/MODULE and the source tree in src/MODULE will make it easy to use javadoc to generate documentation: for javadoc the options

   -d TARGET
   --module-path PATH
   --module-source-path src:tmpsrc
   --add-modules MODULES
   --module MODULE
and possibly

   --exclude PACKAGES
are useful, where
  • TARGET is the directory that will hold the API documentation
  • PATH is a list of directories separate by the path separator (":" for Linux or Unix, ';' for Windows), with each containing modular JAR files (a path entry may also be a modular JAR file)
  • MODULES is a comma-separated list of modules that should be included in the documentation.
  • PACKAGES is a colon-separated list of package names listing packages that should be excluded (fully qualified package names are necessary). The BZDev class library has a number of packages for which the last component of their names is "lpack". These packages contain Java "properties" files and are used for localization. As such, they should not be documented.
The module-info file should contain a 'provides' clause (which is necessary for the program lsnof to recognize factories):

module ... {
     provides org.bzdev.obnaming.NamedObjectProcessor with
        FACTORY_LIST;
}
where FACTORY_LIST is a comma-separated list of the factories in the module that are not abstract classes. One will typically want to use the program lsnof as well. For example lsnof corresponding the javadoc options shown above are

   lsnof -d TARGET --module-path PATH CLASSNAME...
where TARGET and PATH match the valued provided for the javadoc command shown above. Multiple class names should be provided, one for each factory. lsnof allows wildcards in the class name, but in any case, all the factories being documented should be listed matching fully-qualified class names.

The API documentation describing factory parameters will be places in the directory TARGET/factories-api and it is useful to include this documentation the factory's full API documentation by using an HTML IFRAME. If the factory's fully qualified class name is org.foo.pkg.Factory, then the SRC attribute for an IFRAME in this factory's javadoc comments would be


 SRC="../../../../../../factories-api/org/foo/pkg/Factory.html"
If lsnof is used to generate documentation the FactoryParmManager elements labelResourceBundle and tipResourceBundle must be defined. In many cases,docResourceBundle bundle will be needed as well.