Bug #10626
DMO names can collide on case-insensitive file-system
100%
Related issues
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
#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.
#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
createstatement 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
createString2StringMapto 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.
#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>Debug0and other suffixes likeSeDate,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.
#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_generatorandframe_constructiondon'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.
#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!
#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.