2 Replies Latest reply on Jul 18, 2014 11:02 AM by Ralf Battenfeld

    New Descriptor API Proposal

    Ralf Battenfeld Apprentice

      Dear friends, I am pleasant to provide you the Descriptor refactoring work I did since I visited DevNation.

       

      The work is not finished but I got the feeling that you guys should see the proposal and can give valuable inputs or better, work on it too:-)

       

      The main goal of the refactoring was:

      • Eliminate the generic based jump to the parent node. Most people didn't liked it from the beginning. So this is gone:-) The replacement is a factory based approach which allows to create descriptor objects easily.
      • Allowing to create custom objects with a convenient behavior as was in place in version 1. An example is when you create a filter then it creates automatically the filter mappings too.
      • Some little enhancements like passing class objects in addition to strings.

       

      How does it look like? Here is an example:

       

        final ApplicationDescriptor app6Descr = create();

        app6Descr.addDefaultNamespaces()

               .version("6")

               .applicationName("application-name0")

               .description("description0")

               .displayName("display-name0")

               .addIcon(app6Descr.factory().iconType6()

                  .smallIcon("small-icon0")

                  .largeIcon("large-icon0"))

               .initializeInOrder("true")

               .addModule(app6Descr.factory().moduleType6()

                  .ejb("ejb0")

                  .altDd("alt-dd0"))

               .addSecurityRole(app6Descr.factory().securityRoleType6()

                  .description("description1")

                  .roleName("role-name0"))

               .libraryDirectory("library-directory0")

               .addEnvEntry(app6Descr.factory().envEntryType6()

                  .description("description2")

                  .envEntryName("env-entry-name0")

                  .envEntryType("env-entry-type0")

                  .envEntryValue("env-entry-value0")

                  .mappedName("mapped-name0")

                  .addInjectionTarget(app6Descr.factory().injectionTargetType6()

                     .injectionTargetClass("injection-target-class0")

                     .injectionTargetName("$"))

                  .lookupName("lookup-name0")) ....


      The concept allows also the create the objects separately and to pass it later to the descriptor instance. Note

      there is a factory class for each of the three namespaces we currently have; javaee, jboss and misc.


      The extension proposal is just reusing the factory approach. In each of the three namespaces I introduced along with the src/main/java path as well the path src/ext/java. This path is static and allows

      to add new convenient classes. The factory builder includes everything found here and makes it then available in the same way as the generated classes.


      Some words how the classes are generated. XSLT is gone. The classes are now generated by using CodeModel. CodeModel is an outcome of the JAXB project. And, its quite common used. Andrew mentioned once a template based code generation. I was not really sure what that means:-) But I introduced in some way a template based code generation. All methods are generated via string templates.

      Here is an example:


          private static final String METHOD_SET_SINGLE_ELEMENT = "\n"

             + "    /**\n"

             + "     * If not already created, a new <code>ELEMENTNAME_O</code> element with the given value will be created.\n"

             + "     * Otherwise, the existing <code>ELEMENTNAME_O</code> element will be returned.\n"

             + "     * @return  a new or existing instance of <code>CLASSNAME_P</code> \n"

             + "     */\n"

             + "    public CLASSNAME_P ELEMENTNAME_C(final ELEMENTTYPE_P value) {\n"

             + "        if (value instanceof ChildNodeInitializer) {\n"

             + "            if (getNode().getSingle(\"ELEMENTNAME_O\") == null) {\n"

             + "                ((ChildNodeInitializer)value).initialize(\"ELEMENTNAME_O\", getNode());\n"

             + "                org.jboss.shrinkwrap.descriptor.impl.base.extension.ExtensionProvider.handleSet(this, getNode(), \"ELEMENTNAME_O\", value);\n"

             + "            } else {\n"

             + "                throw new IllegalArgumentException(\"Single child already assigned\");\n"

             + "            }\n"

             + "        }\n"

             + "        return this;\n"

             + "    }\n";

       

      This is very simple and supported by CodeModel. As you can see, there are placeholders which are replaced by real values during the generation process. All code generation classes are in org.jboss.shrinkwrap.descriptor.metadata.codegen located.

       

      I believe that this approach makes our life easier. Even for the mutual/unmutual descriptors or the common descriptors. A yes, the common descriptors are not included in this proposal. I believe that how I implemented the common descriptors in 2.0.0.x is improvable.

      This comes later.

       

      Ok, the most important thing is here. This is the link to the new proposal: https://github.com/rbattenfeld/descriptors/tree/newPrototype


      Have fun! And let me know what you think.

      Ralf