Hey Ondra,

I'm moving this discussion to windup-dev@lists.jboss.org - please use windup-dev for all non-confidential development discussion.

In general I support your idea to replace the GraphVisitor interface - I don't think any of us is suggesting that we continue with that approach. But I am concerned that it is more complicated than necessary, and I do have a few concerns about what you've mocked up below:

#1) Your concept of replacing nodes is interesting, but what is stopping a rule from replacing a node, then subsequently overwriting or being overwritten by another replacement? I see potential for multiple rules to interfere with each other's types in this way.

#2) I'm also not sure that the graph would allow you to dynamically replace nodes of one type with nodes of another. Can you verify that?

#3) You asked: "Forge UI could be mapped to XML elements. I.e.  <aaa foo="bar"/> could invoke command "aaa" with given params.
I believe Forge already has this way of input, right?"

I'm not completely following your example here, but in theory you could map XML elements and their attributes to forge commands and their options in this way; nonetheless, I don't think that this is a good use of the Forge command model. You're better off just mapping to Java objects of some type.

#4) This seems more complicated than the example Visitor you linked. Now instead of one Java file containing the rule, and two java interfaces to encapsulate the data storage in the graph, you have two very convoluted XML files. I actually think that the JAXB bit is fairly nice, but the code required to do that in your example would work in the current approach anyway because it would still need to be implemented somewhere.

This is similar to what I am prototyping in the config addon, but in XML not in Java. If you want to continue with this idea of reducing the operations to operate more closely with the graph, I support that, but let's please try to find a way to mock it up using the config DSL instead.

As far as implementing this goes - the syntax you've described below would probably work by mapping to our Java DSL using Reflection, but that's to be done once the java config API is established.

Java first. Then XML (or whatever).

~Lincoln


From: "Ondrej Zizka" <ozizka@redhat.com>
To: jboss-migration@redhat.com
Sent: Thursday, May 1, 2014 12:05:23 AM
Subject: Re: Let's replace the GraphVisitor interface concept with something        generic

I've put it to this doc so we can edit/comment there.

https://docs.google.com/document/d/1UOihPv_zryFilCb7T0k8992wPUt3YNP4goh9rxTC7ng/edit#

Ondra



On 1.5.2014 04:35, Ondrej Zizka wrote:
Hi,

as we discussed before, I'd like to replace the GraphVisitor interface with something generic.
Seriously, having hard-coded interface with methods specific for e.g. MessageDrivenBean, EjbEntity, SpringConfiguration, etc. is IMO not the way to go. It is hard to extend. A rule system created around this would be cumbersome.

    public void visitEjbEntity(EjbEntityFacet entry);
    public void visitEjbService(EjbSessionBeanFacet entry);
    public void visitMessageDrivenBean(MessageDrivenBeanFacet entry);
    public void visitEjbEntity(SpringBeanFacet entry);
    ...



Instead, we should focus on the graph, and have just very few node types in the core -  FileNode, and the rest would be subtypes defined in addons. Addons would, through rules:
     *  replace a node with a subclass, e.g.
              FileNode => XmlFileNode => MavenPomNode,
              FileNode => JavaFileNode => AnnotationNode
          
     *  add properties, e.g.
              XmlFileNode's "doctype",
              ClassNode's "blacklisted"
     *  connect nodes to them, e.g.
              MavenPom ---contains---> MavenDependencyNode
              JavaFile --- imports --> [ ClassNode, ClassNode, ... ]

This approach would:
    * Leverage of Forge modularity (e.g. Maven addon depending on XmlFile addon)
    * Improve extendability (no need to squeeze everything into the GraphVisitor interface's methods or extend it)
    * Lead to much more straightforward rules implementation - all rules would reduce to:
         * matching graph information (Gremlin?)
         * using DAO's / Services (for mining data from the files/..., and for writing them during active migration)
                 1) Bundled - XPath, AST query, properties, Maven remote fetch, ...
                 2) User's:  .class packed within the addon or a Groovy class
         * writing back to the graph
         * rendering pieces of HTML for the report.

Who's in? I need some scenarios where this wouldn't work. But from what I can tell, this would be more generic, but still simpler, than current "God-object" suffering GraphVisitor.

As an example, take e.g. MavenRemoteFetchVisitor.  https://github.com/windup/windup/blob/master/engine/rules/impl/src/main/java/org/jboss/windup/engine/visitor/inspector/MavenRemoteFetchVisitor.java

All that is doable using few simple building blocks, directed by few lines of a rule like this:

------------------------------------------------------------------

<var name="pomNS" val="http://maven.apache.org/POM/4.0.0">

Rule 1) which would process all POM files and load the info into the graph.

<rule id="maven.pomFiles" desc="   Analyze Maven POM files  "
          phase="StaticConfigAnalysis">
    <graph match="XmlFileNode[doctype='http://maven.apache.org/POM/4.0.0']" toVar="xmls">
    <for var="pom" in="xmls">
          <graph:replaceSingle ref="pom" with="MavenPomFileNode">
               <properties>
                    <!-- <jaxb> would invoce a call to a Service.
                           <properties> hander would take returned object's bean props.
                           toClass would load the class from CL or compile from .groovy coming with the migrator (addon).
                     -->
                    <jaxb toClass="PomJaxb.groovy" fromFile="${pom.path}">
                           <ns name="pom" uri="${pomNS}"/>
                    </jaxb>
                </properties>
          </graph>
      </for>
</rule>

@XmlRoot
class PomJaxb {
       @XmlXPath("/pom:project/pom:modelVersion")        String modelVersion;
       @XmlXPath("/pom:project/pom:name")                     String name;
       @XmlXPath("/pom:project/pom:description"              String description;
       @XmlXPath("/pom:project/pom:url"                           String url;
}


Rule 2) which would load the dependencies and describe them into Nodes and Edges.

<rule id="maven.pomDependencies" desc="   Analyze Maven POM file dependencies  "
          phase="StaticConfigAnalysis">
     <after rule="maven.pomFiles">

     <graph match="MavenPomFileNode" toVar="pomVertexes">
     <for var="pomV" in="pomVertexes">
        
          <xpath toVar="deps" fromFile="${pomV.path}" match="/pom:project/pom:dependencies/pom:dependency"/>
          <for var="depElement" in="deps">
              <jaxb toVar="dep" toClass="MavenDepencencyJaxb.groovy" fromElement="depElement" ns="pom ${pomNS}"/>
              <graph:query toVar="isBlacklisted"
                   q=" /*  I don't know Gremlin so far, imagine an equiv of this XPath: */
                       MavenDependencyNode[
                             g=${dep.groupId} and a=${dep.artifactId} and v=${dep.version}
                       ]@blacklisted
              " />
              <continue if="isBlacklisted /* var, or Groovy (or EL) expression */" />
              <!-- This would be useful for blacklists and filters in general, which appear often in real life rules. -->

              <graph:insertIfNotExists type="MavenDependencyNode" toVar="depVertex>
                   <properties from="dep"/>
              </graph>
              <graph:edge type="dependsOn" from="pomV" to="depVertex"/>
                            <!-- Maybe Gremlin could replace this? -->
          </for>
    </for>
</rule>

@XmlRoot
class MavenDepencencyJaxb {
      // GraphKeyProperty identifies those which are compared for insertIfNotExists.
      @GraphKeyProperty  @XmlXPath("./pom:groupId")   String groupId;
      @GraphKeyProperty  @XmlXPath("./pom:artifactId")   String artifactId;
      @GraphKeyProperty  @XmlXPath("./pom:version")   String version;
}
------------------------------------------------------------------

As you can see, It creates independent rules which only communicate indirectly through the graph.
You can also see how nicely Java classes fit into this, and how Groovy could make this easier.

SERVICES INVOCATION
Forge UI could be mapped to XML elements. I.e.  <aaa foo="bar"/> could invoke command "aaa" with given params.
I believe Forge already has this way of input, right?

GRAPH OPERATION
There would be several <graph:...> operations - CRUD plus some special.

EXECUTION FLOW
The flow would be simple, from top to bottom, creating variables along the way, containing objects or iterable collections of objects. Those iterable could be used in <for>.

Does Lincoln's executor fit this? I haven't still looked how it works. This tree would likely be executed classically with a stack and using tree reduction for operation arguments.

For more complex logic, users would break the task into multiple rules, storing data into the graph intermediately.

I'll check few more visitors to see if this is powerful enough to satisfy all the baneeds.


.............................

Also, I'd like to eradicate any mention of an archive from most of the code - archives should be totally transparent for the migrators. There should be just FileNodes, connected with ArchiveNodes, and whoever needs an information that a file came from an archive, may look that up. See https://docs.google.com/drawings/d/1IMnds3Qu8Wwcf7_mr7NJ9a3YgtcGJ7dejl09EhWl7Vc  for illustration.

Ondra