Project

General

Profile

Bug #10626

DMO names can collide on case-insensitive file-system

Added by Constantin Asofiei 10 months ago. Updated 7 months ago.

Status:
Test
Priority:
Normal
Target version:
-
Start date:
Due date:
% Done:

100%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
10626a/16321
reviewer:
production:
No
env_name:
topics:

Related issues

Related to Conversion Tools - Feature #6083: schema (.df) changes in incremental conversion mode should only reconvert those programs that reference the changed schema Closed
Related to Conversion Tools - Bug #10639: Incremental conversion - unexpected DMO generation for space-only changes Review
Related to Conversion Tools - Bug #9917: Fileset not ignoring case Closed

History

#1 Updated by Constantin Asofiei 10 months ago

  • Related to Feature #6083: schema (.df) changes in incremental conversion mode should only reconvert those programs that reference the changed schema added

#2 Updated by Constantin Asofiei 10 months ago

From #10536-27:

I don't know when this was regressed, but if you have two tables named Foo_BARSomething and Foo_BAR_Something in a .df file, and you try to convert, only a .java DMO is generated; this is because the list of AST files gets built as case-insensitive; this patch forces case-sensitivity for DMO and POJO .jast files.

--- src/com/goldencode/p2j/convert/ConversionDriver.java
+++ src/com/goldencode/p2j/convert/ConversionDriver.java
@@ -989,7 +989,8 @@
       JavaPatternWorker.disableNewFileTracking();
       String[] dmoList = JavaPatternWorker.getPersistedFiles();

-      return new ExplicitFileList(dmoList);
+      // these are OS files, need to be case-sensitive
+      return new ExplicitFileList(dmoList, true);
    }

    /**
@@ -1035,7 +1036,8 @@
       // add generated JASTs to the overall list (used with brew later)
       JavaPatternWorker.disableNewFileTracking();

-      return new ExplicitFileList(JavaPatternWorker.getPersistedFiles());
+      // these are OS files, need to be case-sensitive
+      return new ExplicitFileList(JavaPatternWorker.getPersistedFiles(), true);
    }

    /**

which is a side-effect of <action>dmos = create("java.util.HashSet")</action> in p2o.xml is a case-sensitive set - it should be case-insensitive for Windows OS.

This task is meant to check the OS-filename generated for artifacts like DMOs, POJOs, frames, menus, etc, if FWD is aware of the OS where the name is generated - on Windows, collisions related to case-sensitivity must not happen.

#3 Updated by Greg Shah 10 months ago

This task is meant to check the OS-filename generated for artifacts like DMOs, POJOs, frames, menus, etc, if FWD is aware of the OS where the name is generated - on Windows, collisions related to case-sensitivity must not happen.

To clarify, we should always generate the same results regardless of whether we are running on Linux or Windows. The conversion output, including the exact same list of classes etc... should be identical. The OS on which conversion runs should not change the output of the conversion.

In the case of Windows, with its case-insensitive filesystem, we must ensure that two or more inputs do not create the same output filename. But this same behavior must always be implemented, no matter on which platform the conversion runs.

#4 Updated by Dănuț Filimon 10 months ago

  • Assignee set to Dănuț Filimon

#5 Updated by Dănuț Filimon 10 months ago

  • Related to Bug #10639: Incremental conversion - unexpected DMO generation for space-only changes added

#6 Updated by Dănuț Filimon 10 months ago

  • Related to Bug #9917: Fileset not ignoring case added

#7 Updated by Dănuț Filimon 10 months ago

I've made a similar patch to #10626-2 in #9917, it was for the frames and menus (explained the issue in #9917-10, the patch is in #9917-13). The fix reached trunk in revision 16139.

#8 Updated by Constantin Asofiei 10 months ago

Dănuț Filimon wrote:

I've made a similar patch to #10626-2 in #9917, it was for the frames and menus (explained the issue in #9917-10, the patch is in #9917-13). The fix reached trunk in revision 16139.

That patch does not solve the core issue with this task - the DMO names when converted on Windows will still collide. We need to go 'deeper' where the names of the DMO is calculated, and ensure that is unique case-insensitively.

And double-check the other .java artifacts (even converted .java code for 4GL files) that they are unique case-insensitively, and not dependent on the OS where the conversion is ran.

#9 Updated by Dănuț Filimon 9 months ago

We use opsys to determine what OS is being used (default is Unix OS). opsys can be set in p2j.cfg.xml, so there's a way to check if Windows is used in the rules. NameConverterWorker is used to create the dmo names, so I think NameConverter.convert() should take an additional parameter for the case where the name needs be case-sensitive or not.

#10 Updated by Greg Shah 9 months ago

We shouldn't change the output based on the OPSYS setting. The output should be the same always (safe for case-insensitive filesystems).

#11 Updated by Dănuț Filimon 9 months ago

Good, opsys is out of the question.

I converted the two tables, Foo_BARSomething and Foo_BAR_Something, and got a FooBarsomething dmo. The Foo_BAR_Something was split as foo_ bar_ something and then each token was replaced to get FooBarSomething (for the class type, the table type resulted in foo_bar_something). Foo_BARSomething was split as foo_ barsomething and I got FooBarsomething. The dmo names are generated correctly and the patch from #10626-2 fixes the import.

I have a windows machine setup for converting hotel, so I'll use that to check for other collisions.

#12 Updated by Dănuț Filimon 9 months ago

  • Status changed from New to WIP

Error from windows:

     [java] Source AST:  [ FooBarSomething ] DATA_MODEL/CLASS/ @0:0 {38654705762}
     [java] Copy AST  :  [ FooBarSomething ] DATA_MODEL/CLASS/ @0:0 {38654705762}
     [java] Condition :  dmoClass = imp.getDmoClass(dmoIface)
     [java] Loop      :  false
     [java] --- END RULE REPORT ---
     [java]
     [java]
     [java]
     [java]     at com.goldencode.p2j.pattern.PatternEngine.run(PatternEngine.java:1104)
     [java]     at com.goldencode.p2j.pattern.PatternEngine.main(PatternEngine.java:2226)
     [java] Caused by: com.goldencode.expr.ExpressionException: Expression execution error @1:16 [CLASS id=38654705762]
     [java]     at com.goldencode.p2j.pattern.AstWalker.walk(AstWalker.java:275)
     [java]     at com.goldencode.p2j.pattern.AstWalker.walk(AstWalker.java:210)
     [java]     at com.goldencode.p2j.pattern.PatternEngine.apply(PatternEngine.java:1698)
     [java]     at com.goldencode.p2j.pattern.PatternEngine.processAst(PatternEngine.java:1584)
     [java]     at com.goldencode.p2j.pattern.PatternEngine.processAst(PatternEngine.java:1517)
     [java]     at com.goldencode.p2j.pattern.PatternEngine.run(PatternEngine.java:1067)
     [java]     ... 1 more
     [java] Caused by: com.goldencode.expr.ExpressionException: Expression execution error @1:16
     [java]     at com.goldencode.expr.Expression.execute(Expression.java:495)
     [java]     at com.goldencode.p2j.pattern.Rule.apply(Rule.java:500)
     [java]     at com.goldencode.p2j.pattern.Rule.executeActions(Rule.java:751)
     [java]     at com.goldencode.p2j.pattern.Rule.coreProcessing(Rule.java:717)
     [java]     at com.goldencode.p2j.pattern.Rule.apply(Rule.java:537)
     [java]     at com.goldencode.p2j.pattern.Rule.executeActions(Rule.java:751)
     [java]     at com.goldencode.p2j.pattern.Rule.coreProcessing(Rule.java:717)
     [java]     at com.goldencode.p2j.pattern.Rule.apply(Rule.java:537)
     [java]     at com.goldencode.p2j.pattern.Rule.executeActions(Rule.java:751)
     [java]     at com.goldencode.p2j.pattern.Rule.coreProcessing(Rule.java:717)
     [java]     at com.goldencode.p2j.pattern.Rule.apply(Rule.java:537)
     [java]     at com.goldencode.p2j.pattern.RuleContainer.apply(RuleContainer.java:597)
     [java]     at com.goldencode.p2j.pattern.RuleSet.apply(RuleSet.java:98)
     [java]     at com.goldencode.p2j.pattern.AstWalker.walk(AstWalker.java:262)
     [java]     ... 6 more
     [java] Caused by: java.lang.ClassNotFoundException: com.goldencode.hotel.dmo.hotel.FooBarSomething
     [java]     at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
     [java]     at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
     [java]     at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
     [java]     at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
     [java]     at java.lang.Class.forName0(Native Method)
     [java]     at java.lang.Class.forName(Class.java:264)
     [java]     at com.goldencode.p2j.schema.ImportWorker$Library.getDmoClass(ImportWorker.java:2417)
     [java]     at com.goldencode.expr.CE104.execute(Unknown Source)
     [java]     at com.goldencode.expr.Expression.execute(Expression.java:398)
     [java]     ... 19 more
     [java]
This is because when we add to the pfiles set, we'll have the same FooBarSomething file for both tables (.\\cvt\\com\\goldencode\\hotel\\dmo\\hotel\\FooBarSomething.java.jast).

The output should be safe for Windows (case-insensitive), but how should it differ from the case-insensitive one? There's this rule

            <rule>tmpName != null
               <!-- check for dmo name collision -->
               <rule>dmos.contains(tmpName)
                  <rule>dmo == null
                     <action>
                        nextPTSuffix = execLib("getUniqueSuffix", nextPTSuffix, tmpName, dmos)
                     </action>
                     <action>tmpName = sprintf("%s%d", tmpName, nextPTSuffix)</action>
                     <action on="false">
                        printfln("WARNING: DMO collision because of hint: %s", dmo)
                     </action>
                  </rule>
               </rule>
               <action>dmos.add(tmpName)</action>
            </rule>
which will work if we make dmos into a case-insensitive collection for Windows.

#13 Updated by Constantin Asofiei 9 months ago

We need to generate the same .java names regardless of OS - so I think that collection needs to be case-insensitive, regardless of OS.

#14 Updated by Dănuț Filimon 9 months ago

Constantin Asofiei wrote:

We need to generate the same .java names regardless of OS - so I think that collection needs to be case-insensitive, regardless of OS.

Indeed, having different outputs between OS could cause some issues when troubleshooting other issues in the future. Is there any way to declare a case insensitive HashMap in the rules (I mean using com.goldencode.util.CaseInsensitiveHashMap)?

#15 Updated by Constantin Asofiei 9 months ago

Dănuț Filimon wrote:

Constantin Asofiei wrote:

We need to generate the same .java names regardless of OS - so I think that collection needs to be case-insensitive, regardless of OS.

Indeed, having different outputs between OS could cause some issues when troubleshooting other issues in the future. Is there any way to declare a case insensitive HashMap in the rules (I mean using com.goldencode.util.CaseInsensitiveHashMap)?

Yes, just replace the type in the create statement with the case-insensitive map or set implementation in FWD.

#16 Updated by Dănuț Filimon 9 months ago

Constantin Asofiei wrote:

Dănuț Filimon wrote:

Constantin Asofiei wrote:

We need to generate the same .java names regardless of OS - so I think that collection needs to be case-insensitive, regardless of OS.

Indeed, having different outputs between OS could cause some issues when troubleshooting other issues in the future. Is there any way to declare a case insensitive HashMap in the rules (I mean using com.goldencode.util.CaseInsensitiveHashMap)?

Yes, just replace the type in the create statement with the case-insensitive map or set implementation in FWD.

Perfect, I'll just have to implement the contains() method for CaseInsensitiveHashMap in this scenariom then check if there are any changes to the functions used in the rules regarding the new map.

#17 Updated by Dănuț Filimon 9 months ago

Dănuț Filimon wrote:

Perfect, I'll just have to implement the contains() method for CaseInsensitiveHashMap in this scenariom then check if there are any changes to the functions used in the rules regarding the new map.

Let me make a correction, I should use CaseInsensitiveHashSet, which I totally missed until now.

#18 Updated by Dănuț Filimon 9 months ago

I setup and tested POJOs on hotel and found no issues, the hotel.p2o ends up using the correct class names (FooBarSomething and FooBarsomething1) and the pojos are created using those two class names.

Looking at menus and frames now.

#19 Updated by Dănuț Filimon 9 months ago

The issue with menus starts with this piece of code:

            <action>extends = sprintf("%s%s", clspfx, "Definition")</action>
            <action>cname = classname</action>
            <action>fname = execLib("gen_fname", cname)</action>

            <action>printfln("Creating separate file: %s %s", cname, fname)</action>

            <rule>lastFile != null
               <action>execLib("gen_add_widgets", pnames, wtypes)</action>
               <action>persistJavaFile(lastFile)</action>
            </rule>

            <action>createJavaFile(fname, true)</action>

            <action>lastFile = fname</action>           

            <action>pkgname = #(java.lang.String) execLib("gen_pkg")</action>

            <action>createJavaAst(java.kw_package, pkgname, javaRootId)</action>

            <action>createImport("com.goldencode.p2j.ui.*")</action>

            <action>putNote("javaname", cname)</action>

            <action>
               tw.graft("class_def_ext",
                        null,
                        javaRootId,
                        "classname", cname,
                        "pkgname", pkgname,
                        "access" , "public",
                        "extends", extends)
            </action>
the fname can be fixed and this generates the .jast file name correctly, but cname must also match the fname so that the java file name is correct.

#20 Updated by Dănuț Filimon 9 months ago

This bit of code:

         <action>
            classname = sprintf("%s%s%s",
                                baseClass,
                                names.convert(getNoteString("name"), names.class), 
                                "Menu")
         </action>
that results in the menu name can be found in both menu_generator.xml and menu_constructions.rules..

My initial idea was to add an index at the end of the name:

            <rule>menuNames.contains(classname)
               <action>nextMenuSuffix = execLib("getUniqueSuffix", nextMenuSuffix, classname, menuNames)</action>
               <action>classname = sprintf("%s%d", classname, nextMenuSuffix)</action>
            </rule>
            <action>menuNames.add(classname)</action>
but having the classname built in two separate files can cause the index to be different and the name used in other converted procedures to be different.

#21 Updated by Dănuț Filimon 9 months ago

I thought of using another set of rules to store a case sensitive map that maps the namings, but I don't think this is the best solution.

#22 Updated by Dănuț Filimon 9 months ago

I discussed with Octavian and he mentioned I could use createString2StringMap to get a map across other rules. I have an idea where I will store the classname as a key (which s case-sensitive) and then I will calculate the key based on the existing values from the map (put those in a case insensitive set and check new postfix values until it can't be found in the set). This looks a bit expensive when I think there can be thousands of menus generated for an application, so I am trying to find something faster/less expensive.

#23 Updated by Dănuț Filimon 9 months ago

  • % Done changed from 0 to 50

Dănuț Filimon wrote:

I discussed with Octavian and he mentioned I could use createString2StringMap to get a map across other rules. I have an idea where I will store the classname as a key (which s case-sensitive) and then I will calculate the key based on the existing values from the map (put those in a case insensitive set and check new postfix values until it can't be found in the set). This looks a bit expensive when I think there can be thousands of menus generated for an application, so I am trying to find something faster/less expensive.

I'll cleanup the implementation and commit my changes, I also checked frames and the changes are much simpler since there's a map stored in frame_scoping.rules.

#24 Updated by Dănuț Filimon 9 months ago

Committed 10626a/16221. Generates names for menus, sub-menus, dmos, pojos, frames that do not collide in case-insensitive file-systems.

#25 Updated by Greg Shah 9 months ago

Is this ready for review? What is the % Done?

#26 Updated by Dănuț Filimon 9 months ago

Greg Shah wrote:

Is this ready for review? What is the % Done?

I looked into the ChUI project for some other cases where names are built and found procedure with names like <name>Debug, <name>Debug0 and other suffixes like SeDate, FIn, FPrinter. I am trying to understand if this will be an issue and what I need to fix next.

#27 Updated by Dănuț Filimon 9 months ago

Dănuț Filimon wrote:

Greg Shah wrote:

Is this ready for review? What is the % Done?

I looked into the ChUI project for some other cases where names are built and found procedure with names like <name>Debug, <name>Debug0 and other suffixes like SeDate, FIn, FPrinter. I am trying to understand if this will be an issue and what I need to fix next.

I didn't find any place where this might be generated, so 10626a can be reviewed as is.

#28 Updated by Dănuț Filimon 9 months ago

  • % Done changed from 50 to 100
  • Status changed from WIP to Review
  • reviewer Greg Shah added

Greg, please review.

#29 Updated by Greg Shah 9 months ago

Code Review Task Branch 10626a Revision 16221

I don't have a problem with the changes. Please help me understand why frame_generator and frame_construction don't need to be backed by the H2Map implementation.

#30 Updated by Dănuț Filimon 9 months ago

Greg Shah wrote:

Code Review Task Branch 10626a Revision 16221

I don't have a problem with the changes. Please help me understand why frame_generator and frame_construction don't need to be backed by the H2Map implementation.

Because frame names are created in frame_scoping.rules and the framePool Map from frame_generator.xml is populated with the javaname created in the mentioned rules set. Since there's a single place where the frame name is created, there's no need to store an additional H2Map.

#31 Updated by Greg Shah 9 months ago

  • Status changed from Review to Internal Test

#32 Updated by Dănuț Filimon 9 months ago

I did a conversion with a customer application and forwarded the jars to Artur for testing, where he found 3 tests failing during harness. I used trunk/16220 for the conversion.

#33 Updated by Dănuț Filimon 9 months ago

Dănuț Filimon wrote:

I did a conversion with a customer application and forwarded the jars to Artur for testing, where he found 3 tests failing during harness. I used trunk/16220 for the conversion.

I'll redo the conversion using 10164_main and see if the issue is the same.

#34 Updated by Dănuț Filimon 7 months ago

The bare-metal machine for the application that failed was updated recently and I've been running conversions on it with no issues. I plan to retest the conversion and add another application to the list.

Rebased 10626a to latest trunk/16312, the branch is now at revision 16313.

#35 Updated by Dănuț Filimon 7 months ago

All testing passed! 10626a can be merged!

#36 Updated by Greg Shah 7 months ago

  • Status changed from Internal Test to Merge Pending

You can merge to trunk now.

#37 Updated by Dănuț Filimon 7 months ago

  • Status changed from Merge Pending to Test
  • version_resolved set to 10626a/16321

Branch 10626a was merged into trunk as rev. 16321 and archived.

Also available in: Atom PDF