mxrb 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.de-DE.md +108 -0
  4. data/README.md +172 -0
  5. data/README.pt-BR.md +109 -0
  6. data/bin/mxrb +1613 -0
  7. data/docs/README.md +10 -0
  8. data/docs/de-DE/README.md +24 -0
  9. data/docs/de-DE/architectural-patterns.md +26 -0
  10. data/docs/de-DE/architectural-standard.md +48 -0
  11. data/docs/de-DE/architecture.md +76 -0
  12. data/docs/de-DE/compiler.md +162 -0
  13. data/docs/de-DE/conventions.md +19 -0
  14. data/docs/de-DE/design-system.md +52 -0
  15. data/docs/de-DE/entity-dsl.md +53 -0
  16. data/docs/de-DE/native-runtime-quality-report.md +74 -0
  17. data/docs/de-DE/oql-sql.md +211 -0
  18. data/docs/de-DE/platform-api-integration.md +36 -0
  19. data/docs/de-DE/platform-operations.md +243 -0
  20. data/docs/de-DE/project-structure.md +32 -0
  21. data/docs/de-DE/ruby-first-roadmap.md +116 -0
  22. data/docs/de-DE/scaffolds.md +59 -0
  23. data/docs/de-DE/semantic-refactoring.md +56 -0
  24. data/docs/de-DE/team-server.md +33 -0
  25. data/docs/de-DE/validation-matrix.md +64 -0
  26. data/docs/de-DE/vetclinic-acceptance.md +24 -0
  27. data/docs/de-DE/writing.md +138 -0
  28. data/docs/en-US/README.md +24 -0
  29. data/docs/en-US/architectural-patterns.md +151 -0
  30. data/docs/en-US/architectural-standard.md +89 -0
  31. data/docs/en-US/architecture.md +170 -0
  32. data/docs/en-US/compiler.md +157 -0
  33. data/docs/en-US/conventions.md +82 -0
  34. data/docs/en-US/design-system.md +163 -0
  35. data/docs/en-US/entity-dsl.md +53 -0
  36. data/docs/en-US/native-runtime-quality-report.md +73 -0
  37. data/docs/en-US/oql-sql.md +201 -0
  38. data/docs/en-US/platform-api-integration.md +36 -0
  39. data/docs/en-US/platform-operations.md +244 -0
  40. data/docs/en-US/project-structure.md +49 -0
  41. data/docs/en-US/ruby-first-roadmap.md +186 -0
  42. data/docs/en-US/scaffolds.md +57 -0
  43. data/docs/en-US/semantic-refactoring.md +198 -0
  44. data/docs/en-US/team-server.md +32 -0
  45. data/docs/en-US/validation-matrix.md +257 -0
  46. data/docs/en-US/vetclinic-acceptance.md +23 -0
  47. data/docs/en-US/writing.md +655 -0
  48. data/docs/pt-BR/README.md +24 -0
  49. data/docs/pt-BR/architectural-patterns.md +25 -0
  50. data/docs/pt-BR/architectural-standard.md +533 -0
  51. data/docs/pt-BR/architecture.md +300 -0
  52. data/docs/pt-BR/compiler.md +162 -0
  53. data/docs/pt-BR/conventions.md +19 -0
  54. data/docs/pt-BR/design-system.md +65 -0
  55. data/docs/pt-BR/entity-dsl.md +116 -0
  56. data/docs/pt-BR/native-runtime-quality-report.md +73 -0
  57. data/docs/pt-BR/oql-sql.md +208 -0
  58. data/docs/pt-BR/platform-api-integration.md +36 -0
  59. data/docs/pt-BR/platform-operations.md +260 -0
  60. data/docs/pt-BR/project-structure.md +32 -0
  61. data/docs/pt-BR/ruby-first-roadmap.md +239 -0
  62. data/docs/pt-BR/scaffolds.md +104 -0
  63. data/docs/pt-BR/semantic-refactoring.md +55 -0
  64. data/docs/pt-BR/team-server.md +59 -0
  65. data/docs/pt-BR/validation-matrix.md +86 -0
  66. data/docs/pt-BR/vetclinic-acceptance.md +50 -0
  67. data/docs/pt-BR/writing.md +177 -0
  68. data/examples/sudoku_evaluation.rb +14 -0
  69. data/examples/sudoku_functional_test.rb +28 -0
  70. data/lib/mxrb/architecture/graph.rb +124 -0
  71. data/lib/mxrb/architecture/validator.rb +98 -0
  72. data/lib/mxrb/benchmark.rb +33 -0
  73. data/lib/mxrb/compare.rb +390 -0
  74. data/lib/mxrb/compiler/adapter.rb +96 -0
  75. data/lib/mxrb/compiler/artifact_document_compiler.rb +102 -0
  76. data/lib/mxrb/compiler/artifact_materializer.rb +53 -0
  77. data/lib/mxrb/compiler/client_model_materializer.rb +42 -0
  78. data/lib/mxrb/compiler/code_action_document_compiler.rb +64 -0
  79. data/lib/mxrb/compiler/code_action_materializer.rb +35 -0
  80. data/lib/mxrb/compiler/code_action_type_compiler.rb +32 -0
  81. data/lib/mxrb/compiler/combo_box_bundle_compiler.rb +314 -0
  82. data/lib/mxrb/compiler/compatibility_analyzer.rb +169 -0
  83. data/lib/mxrb/compiler/constants_materializer.rb +111 -0
  84. data/lib/mxrb/compiler/data_grid_bundle_compiler.rb +290 -0
  85. data/lib/mxrb/compiler/database_connector_action_compiler.rb +280 -0
  86. data/lib/mxrb/compiler/deployment_asset_copier.rb +60 -0
  87. data/lib/mxrb/compiler/deployment_bootstrapper.rb +208 -0
  88. data/lib/mxrb/compiler/deployment_materializer.rb +43 -0
  89. data/lib/mxrb/compiler/deployment_metadata.rb +64 -0
  90. data/lib/mxrb/compiler/domain_document_compiler.rb +153 -0
  91. data/lib/mxrb/compiler/domain_model_materializer.rb +35 -0
  92. data/lib/mxrb/compiler/domain_security_compiler.rb +82 -0
  93. data/lib/mxrb/compiler/gallery_bundle_compiler.rb +190 -0
  94. data/lib/mxrb/compiler/generic_widget_bundle_compiler.rb +281 -0
  95. data/lib/mxrb/compiler/image_bundle_compiler.rb +216 -0
  96. data/lib/mxrb/compiler/java_proxy_generator.rb +509 -0
  97. data/lib/mxrb/compiler/legacy_data_grid_compiler.rb +267 -0
  98. data/lib/mxrb/compiler/legacy_page_builder.rb +287 -0
  99. data/lib/mxrb/compiler/mda.rb +99 -0
  100. data/lib/mxrb/compiler/microflow_document_compiler.rb +85 -0
  101. data/lib/mxrb/compiler/microflow_materializer.rb +48 -0
  102. data/lib/mxrb/compiler/microflow_node_compiler.rb +250 -0
  103. data/lib/mxrb/compiler/model_package.rb +116 -0
  104. data/lib/mxrb/compiler/model_values.rb +67 -0
  105. data/lib/mxrb/compiler/nanoflow_program_compiler.rb +483 -0
  106. data/lib/mxrb/compiler/navigation_document_compiler.rb +93 -0
  107. data/lib/mxrb/compiler/packager.rb +100 -0
  108. data/lib/mxrb/compiler/page_bundle_builder.rb +56 -0
  109. data/lib/mxrb/compiler/page_bundle_compiler.rb +2004 -0
  110. data/lib/mxrb/compiler/page_document_compiler.rb +77 -0
  111. data/lib/mxrb/compiler/portable_packager.rb +356 -0
  112. data/lib/mxrb/compiler/project_jar_archive.rb +84 -0
  113. data/lib/mxrb/compiler/project_jar_builder.rb +121 -0
  114. data/lib/mxrb/compiler/project_materializer.rb +139 -0
  115. data/lib/mxrb/compiler/project_model_orderer.rb +52 -0
  116. data/lib/mxrb/compiler/runtime_data_types.rb +31 -0
  117. data/lib/mxrb/compiler/runtime_model_schema.rb +90 -0
  118. data/lib/mxrb/compiler/schemas/runtime-10.24.0.73019.json +1052 -0
  119. data/lib/mxrb/compiler/schemas/runtime-11.json +1215 -0
  120. data/lib/mxrb/compiler/schemas/runtime-6.10.8.json +1148 -0
  121. data/lib/mxrb/compiler/schemas/runtime-7.17.0.json +1144 -0
  122. data/lib/mxrb/compiler/schemas/runtime-7.5.0.json +1215 -0
  123. data/lib/mxrb/compiler/schemas/runtime-9.6.1.29396.json +868 -0
  124. data/lib/mxrb/compiler/schemas/system-model-10.24.0.73019.b64 +1135 -0
  125. data/lib/mxrb/compiler/schemas/system-model-11.12.1.b64 +815 -0
  126. data/lib/mxrb/compiler/schemas/system-model-6.10.8.b64 +497 -0
  127. data/lib/mxrb/compiler/schemas/system-model-7.17.0.b64 +519 -0
  128. data/lib/mxrb/compiler/schemas/system-model-7.5.0.b64 +504 -0
  129. data/lib/mxrb/compiler/schemas/system-model-9.6.1.29396.b64 +816 -0
  130. data/lib/mxrb/compiler/security_materializer.rb +104 -0
  131. data/lib/mxrb/compiler/settings_document_compiler.rb +45 -0
  132. data/lib/mxrb/compiler/settings_materializer.rb +25 -0
  133. data/lib/mxrb/compiler/source_model.rb +128 -0
  134. data/lib/mxrb/compiler/system_model_seed.rb +88 -0
  135. data/lib/mxrb/compiler/system_queue_materializer.rb +54 -0
  136. data/lib/mxrb/compiler/system_text_materializer.rb +49 -0
  137. data/lib/mxrb/compiler/translation_materializer.rb +95 -0
  138. data/lib/mxrb/compiler/web_bundle_builder.rb +155 -0
  139. data/lib/mxrb/compiler/web_list_data_source.rb +139 -0
  140. data/lib/mxrb/compiler/web_operation_compiler.rb +614 -0
  141. data/lib/mxrb/compiler/web_shell_materializer.rb +194 -0
  142. data/lib/mxrb/compiler/widget_package_extractor.rb +63 -0
  143. data/lib/mxrb/doctor.rb +116 -0
  144. data/lib/mxrb/dsl/builder.rb +1636 -0
  145. data/lib/mxrb/errors.rb +18 -0
  146. data/lib/mxrb/evaluation.rb +131 -0
  147. data/lib/mxrb/exporter.rb +1716 -0
  148. data/lib/mxrb/frontend/migrator.rb +775 -0
  149. data/lib/mxrb/functional.rb +307 -0
  150. data/lib/mxrb/github/annotator.rb +161 -0
  151. data/lib/mxrb/initializer.rb +257 -0
  152. data/lib/mxrb/integrity/validator.rb +136 -0
  153. data/lib/mxrb/io/bson_codec.rb +145 -0
  154. data/lib/mxrb/io/mpr_file.rb +558 -0
  155. data/lib/mxrb/io/mxunit_codec.rb +42 -0
  156. data/lib/mxrb/marketplace.rb +380 -0
  157. data/lib/mxrb/model/association.rb +98 -0
  158. data/lib/mxrb/model/attribute.rb +100 -0
  159. data/lib/mxrb/model/connector.rb +17 -0
  160. data/lib/mxrb/model/design_materializer.rb +133 -0
  161. data/lib/mxrb/model/design_migration.rb +126 -0
  162. data/lib/mxrb/model/design_system.rb +111 -0
  163. data/lib/mxrb/model/domain_model.rb +51 -0
  164. data/lib/mxrb/model/entity.rb +180 -0
  165. data/lib/mxrb/model/menu.rb +38 -0
  166. data/lib/mxrb/model/microflow.rb +100 -0
  167. data/lib/mxrb/model/module.rb +142 -0
  168. data/lib/mxrb/model/navigation.rb +127 -0
  169. data/lib/mxrb/model/page.rb +410 -0
  170. data/lib/mxrb/model/project.rb +187 -0
  171. data/lib/mxrb/model/unit.rb +48 -0
  172. data/lib/mxrb/module_initializer.rb +75 -0
  173. data/lib/mxrb/official_marketplace/content_api.rb +292 -0
  174. data/lib/mxrb/official_marketplace/dependency_resolver.rb +329 -0
  175. data/lib/mxrb/official_marketplace/lifecycle.rb +367 -0
  176. data/lib/mxrb/official_marketplace/module_package_importer.rb +318 -0
  177. data/lib/mxrb/official_marketplace/widget_package_installer.rb +414 -0
  178. data/lib/mxrb/official_marketplace.rb +720 -0
  179. data/lib/mxrb/oql/analyzer.rb +155 -0
  180. data/lib/mxrb/oql/index_advisor.rb +85 -0
  181. data/lib/mxrb/oql/plan_analyzer.rb +185 -0
  182. data/lib/mxrb/oql/server.rb +132 -0
  183. data/lib/mxrb/oql/sql_server_plan_analyzer.rb +190 -0
  184. data/lib/mxrb/oql/sql_server_workload_analyzer.rb +80 -0
  185. data/lib/mxrb/oql/workload_analyzer.rb +175 -0
  186. data/lib/mxrb/oql/workload_baseline.rb +60 -0
  187. data/lib/mxrb/oql.rb +424 -0
  188. data/lib/mxrb/project_lifecycle.rb +76 -0
  189. data/lib/mxrb/protocols/plan.rb +86 -0
  190. data/lib/mxrb/protocols.rb +123 -0
  191. data/lib/mxrb/runtime/database_workspace.rb +677 -0
  192. data/lib/mxrb/runtime/docker_executor.rb +41 -0
  193. data/lib/mxrb/runtime/docker_workspace.rb +29 -0
  194. data/lib/mxrb/runtime/executor.rb +169 -0
  195. data/lib/mxrb/runtime/java_locator.rb +26 -0
  196. data/lib/mxrb/runtime/native.rb +474 -0
  197. data/lib/mxrb/runtime/sql_server_database.rb +146 -0
  198. data/lib/mxrb/runtime/toolchain.rb +82 -0
  199. data/lib/mxrb/scaffold/cli.rb +113 -0
  200. data/lib/mxrb/scaffold/generator.rb +246 -0
  201. data/lib/mxrb/scaffold/help.rb +80 -0
  202. data/lib/mxrb/scaffold/page_templates.rb +54 -0
  203. data/lib/mxrb/scaffold/recipes.rb +198 -0
  204. data/lib/mxrb/scaffold/registry.rb +82 -0
  205. data/lib/mxrb/scaffold/templates.rb +723 -0
  206. data/lib/mxrb/scaffold/transaction.rb +84 -0
  207. data/lib/mxrb/schema/tables.rb +55 -0
  208. data/lib/mxrb/semantic/analyzer.rb +473 -0
  209. data/lib/mxrb/semantic/batch_plan.rb +68 -0
  210. data/lib/mxrb/semantic/domain_mutator.rb +419 -0
  211. data/lib/mxrb/semantic/embedder.rb +51 -0
  212. data/lib/mxrb/semantic/extractor.rb +290 -0
  213. data/lib/mxrb/semantic/index.rb +623 -0
  214. data/lib/mxrb/semantic/inliner.rb +216 -0
  215. data/lib/mxrb/semantic/mover.rb +153 -0
  216. data/lib/mxrb/semantic/onnx_embedder.rb +34 -0
  217. data/lib/mxrb/semantic/remover.rb +70 -0
  218. data/lib/mxrb/semantic/renamer.rb +211 -0
  219. data/lib/mxrb/semantic/tfidf_embedder.rb +46 -0
  220. data/lib/mxrb/semantic/vec_store.rb +75 -0
  221. data/lib/mxrb/team_server.rb +390 -0
  222. data/lib/mxrb/templates/project/10.24.0.73019.json +32 -0
  223. data/lib/mxrb/templates/project/11.12.1.json +32 -0
  224. data/lib/mxrb/templates/project/6.10.8.json +50 -0
  225. data/lib/mxrb/templates/project/7.17.0.json +50 -0
  226. data/lib/mxrb/templates/project/7.5.0.json +50 -0
  227. data/lib/mxrb/templates/project/9.6.1.29396.json +50 -0
  228. data/lib/mxrb/version.rb +5 -0
  229. data/lib/mxrb/widget_package.rb +338 -0
  230. data/lib/mxrb/widget_synchronizer.rb +31 -0
  231. data/lib/mxrb/writer.rb +3775 -0
  232. data/lib/mxrb.rb +188 -0
  233. data/marketplace/catalog.json +10 -0
  234. data/marketplace/modules/shared-kernel/domain/README.md +4 -0
  235. data/marketplace/modules/shared-kernel/module.rb +5 -0
  236. data/marketplace/modules/shared-kernel/mxrb-module.json +9 -0
  237. metadata +447 -0
@@ -0,0 +1,509 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+
5
+ module Mxrb
6
+ module Compiler
7
+ # Materializes the subset of Studio Pro generated Java proxies required by project sources.
8
+ # Proxy syntax is intentionally kept together so generated Java remains auditable.
9
+ # rubocop:disable Metrics/AbcSize, Metrics/ClassLength, Metrics/CyclomaticComplexity
10
+ # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity
11
+ class JavaProxyGenerator
12
+ include ModelValues
13
+
14
+ TYPE_MAP = {
15
+ 'DomainModels$StringAttributeType' => 'java.lang.String',
16
+ 'DomainModels$HashStringAttributeType' => 'java.lang.String',
17
+ 'DomainModels$HashedStringAttributeType' => 'java.lang.String',
18
+ 'DomainModels$IntegerAttributeType' => 'java.lang.Integer',
19
+ 'DomainModels$LongAttributeType' => 'java.lang.Long',
20
+ 'DomainModels$AutoNumberAttributeType' => 'java.lang.Long',
21
+ 'DomainModels$DecimalAttributeType' => 'java.math.BigDecimal',
22
+ 'DomainModels$BooleanAttributeType' => 'java.lang.Boolean',
23
+ 'DomainModels$DateTimeAttributeType' => 'java.util.Date',
24
+ 'DomainModels$BinaryAttributeType' => 'byte[]'
25
+ }.freeze
26
+
27
+ CONSTANT_TYPE_MAP = {
28
+ 'DataTypes$StringType' => 'java.lang.String', 'DataTypes$IntegerType' => 'java.lang.Long',
29
+ 'DataTypes$DecimalType' => 'java.math.BigDecimal', 'DataTypes$BooleanType' => 'java.lang.Boolean',
30
+ 'DataTypes$DateTimeType' => 'java.util.Date'
31
+ }.freeze
32
+
33
+ def initialize(mpr_path, project_root: File.dirname(File.expand_path(mpr_path)))
34
+ @source = SourceModel.read(mpr_path)
35
+ @project_root = File.expand_path(project_root)
36
+ @system_seed = SystemModelSeed.for(@source.version)
37
+ @domain_units = @source.units_of('DomainModels$DomainModel') + [system_domain_unit]
38
+ @entities = entity_index
39
+ end
40
+
41
+ def generate
42
+ generated = write_user_actions_registrar ? 1 : 0
43
+ source_text = java_source_text
44
+ generated += microflow_modules.count do |mod|
45
+ microflows_referenced?(source_text, mod) && write_microflows(mod, source_text)
46
+ end
47
+ source_text = java_source_text if generated.positive?
48
+ requested = requested_entities(source_text)
49
+ entity_count = requested.count { |name| write_entity(name) }
50
+ generated += entity_count
51
+ source_text = java_source_text if entity_count.positive?
52
+ generated += enumeration_units.count { |unit| referenced?(source_text, proxy_name(unit)) && write_enum(unit) }
53
+ generated += constant_modules.count { |mod| constants_referenced?(source_text, mod) && write_constants(mod) }
54
+ generated
55
+ end
56
+
57
+ private
58
+
59
+ def java_source_text
60
+ Dir.glob(File.join(@project_root, 'javasource', '**', '*.java')).sort.map { File.read(_1) }.join("\n")
61
+ end
62
+
63
+ def write_user_actions_registrar
64
+ classes = user_action_classes
65
+ return false if classes.empty?
66
+
67
+ path = File.join(@project_root, 'javasource', 'system', 'UserActionsRegistrar.java')
68
+ write_missing(path, user_actions_registrar_source(classes))
69
+ end
70
+
71
+ def user_action_classes
72
+ @source.units_of('JavaActions$JavaAction').filter_map do |unit|
73
+ name = document_name(unit.document).to_s
74
+ package_name = java_package(unit.module_name)
75
+ source = File.join(@project_root, 'javasource', package_name, 'actions', "#{name}.java")
76
+ "#{package_name}.actions.#{name}" if !name.empty? && File.file?(source)
77
+ end.sort.uniq
78
+ end
79
+
80
+ def user_actions_registrar_source(classes)
81
+ registrations = classes.map do |class_name|
82
+ " registrator.registerUserAction(#{class_name}.class);"
83
+ end.join("\n")
84
+ <<~JAVA
85
+ // Generated natively by mxrb from Java action documents and sources.
86
+ package system;
87
+
88
+ public class UserActionsRegistrar {
89
+ public void registerActions(com.mendix.core.actionmanagement.IActionRegistrator registrator) {
90
+ #{registrations}
91
+ }
92
+ }
93
+ JAVA
94
+ end
95
+
96
+ def entity_index
97
+ @domain_units.each_with_object({}) do |unit, index|
98
+ array(unit.document['Entities']).each do |entity|
99
+ index[entity_qualified_name(unit, entity)] = [unit, entity]
100
+ end
101
+ end
102
+ end
103
+
104
+ def system_domain_unit
105
+ document = @system_seed.domain_document
106
+ SourceModel::Unit.new(
107
+ id: identifier(document['$ID']), container_id: SystemModelSeed::MODULE_ID,
108
+ containment: 'DomainModel', document:, module_name: 'System'
109
+ )
110
+ end
111
+
112
+ def entity_qualified_name(unit, entity)
113
+ entity['QualifiedName'] || "#{unit.module_name}.#{entity.fetch('Name')}"
114
+ end
115
+
116
+ def entity_name(entity) = entity['Name'] || entity['UnqualifiedName']
117
+
118
+ def requested_entities(text)
119
+ result = @entities.keys.select { referenced?(text, java_proxy_name(_1)) }.to_set
120
+ loop do
121
+ before = result.length
122
+ result.to_a.each { add_entity_dependencies(_1, result) }
123
+ break if result.length == before
124
+ end
125
+ result.to_a
126
+ end
127
+
128
+ def add_entity_dependencies(name, result)
129
+ unit, entity = @entities.fetch(name)
130
+ parent = generalization(entity)
131
+ result << parent if @entities.key?(parent)
132
+ associations_for(unit, entity).each do |association|
133
+ child = association_child_qualified(unit, association)
134
+ result << child if @entities.key?(child)
135
+ end
136
+ end
137
+
138
+ def referenced?(text, java_name)
139
+ text.match?(/(?<![A-Za-z0-9_])#{Regexp.escape(java_name)}(?![A-Za-z0-9_])/)
140
+ end
141
+
142
+ def java_proxy_name(qualified)
143
+ mod, name = qualified.split('.', 2)
144
+ "#{java_package(mod)}.proxies.#{name}"
145
+ end
146
+
147
+ def proxy_name(unit) = "#{java_package(unit.module_name)}.proxies.#{document_name(unit.document)}"
148
+ def java_package(mod) = mod.to_s.downcase
149
+
150
+ def write_entity(qualified)
151
+ unit, entity = @entities.fetch(qualified)
152
+ path = proxy_path(unit.module_name, "#{entity_name(entity)}.java")
153
+ write_missing(path, entity_source(unit, entity))
154
+ end
155
+
156
+ def entity_source(unit, entity) # rubocop:disable Metrics/MethodLength
157
+ name = entity_name(entity)
158
+ qualified = entity_qualified_name(unit, entity)
159
+ java_name = java_proxy_name(qualified)
160
+ parent = generalization(entity)
161
+ local_parent = @entities.key?(parent) ? java_proxy_name(parent) : nil
162
+ members = attributes(entity).map { [_1['Name'], _1['Name']] }
163
+ members += associations_for(unit, entity).map do |association|
164
+ [association_name(association), association_qualified_name(unit, association)]
165
+ end
166
+ inheritance = if local_parent
167
+ "extends #{local_parent}"
168
+ else
169
+ 'implements com.mendix.systemwideinterfaces.core.IEntityProxy'
170
+ end
171
+ storage = local_parent ? '' : <<~JAVA
172
+ private final com.mendix.systemwideinterfaces.core.IMendixObject mendixObject;
173
+ private final com.mendix.systemwideinterfaces.core.IContext context;
174
+ JAVA
175
+ constructor_body = local_parent ? 'super(context, mendixObject);' : root_constructor_body
176
+ accessors = attributes(entity).map { attribute_methods(unit, _1) }.join("\n")
177
+ accessors += associations_for(unit, entity).map { association_methods(unit, _1) }.join("\n")
178
+ base_methods = local_parent ? '' : base_entity_methods
179
+ <<~JAVA
180
+ // Generated natively by mxrb from the MPR model.
181
+ package #{java_package(unit.module_name)}.proxies;
182
+
183
+ public class #{name} #{inheritance} {
184
+ #{storage}
185
+ public static final java.lang.String entityName = "#{qualified}";
186
+ public enum MemberNames {
187
+ #{members.map { |member, meta| "#{member}(\"#{meta}\")" }.join(",\n ")};
188
+ private final java.lang.String metaName;
189
+ MemberNames(java.lang.String value) { metaName = value; }
190
+ @java.lang.Override public java.lang.String toString() { return metaName; }
191
+ }
192
+
193
+ public #{name}(com.mendix.systemwideinterfaces.core.IContext context) {
194
+ this(context, com.mendix.core.Core.instantiate(context, entityName));
195
+ }
196
+ protected #{name}(com.mendix.systemwideinterfaces.core.IContext context,
197
+ com.mendix.systemwideinterfaces.core.IMendixObject mendixObject) {
198
+ #{constructor_body}
199
+ }
200
+ public static #{java_name} initialize(com.mendix.systemwideinterfaces.core.IContext context,
201
+ com.mendix.systemwideinterfaces.core.IMendixObject mendixObject) {
202
+ return new #{java_name}(context, mendixObject);
203
+ }
204
+ public static #{java_name} load(com.mendix.systemwideinterfaces.core.IContext context,
205
+ com.mendix.systemwideinterfaces.core.IMendixIdentifier id) throws com.mendix.core.CoreException {
206
+ return initialize(context, com.mendix.core.Core.retrieveId(context, id));
207
+ }
208
+ #{accessors}
209
+ #{base_methods}
210
+ public static java.lang.String getType() { return entityName; }
211
+ }
212
+ JAVA
213
+ end # rubocop:enable Metrics/MethodLength
214
+
215
+ def root_constructor_body
216
+ <<~JAVA.chomp
217
+ if (mendixObject == null)
218
+ throw new java.lang.IllegalArgumentException("The given object cannot be null.");
219
+ this.mendixObject = mendixObject;
220
+ this.context = context;
221
+ JAVA
222
+ end
223
+
224
+ def base_entity_methods
225
+ <<~JAVA
226
+ @java.lang.Override public com.mendix.systemwideinterfaces.core.IMendixObject getMendixObject() { return mendixObject; }
227
+ public com.mendix.systemwideinterfaces.core.IContext getContext() { return context; }
228
+ @java.lang.Override public boolean equals(Object other) {
229
+ return other == this || (other != null && getClass().equals(other.getClass()) &&
230
+ mendixObject.equals(((com.mendix.systemwideinterfaces.core.IEntityProxy) other).getMendixObject()));
231
+ }
232
+ @java.lang.Override public int hashCode() { return mendixObject.hashCode(); }
233
+ JAVA
234
+ end
235
+
236
+ def attribute_methods(unit, attribute)
237
+ name = attribute['Name']
238
+ type = attribute['NewType'] || attribute['Type'] || {}
239
+ java_type = attribute_java_type(unit, type)
240
+ read = if type['$Type'] == 'DomainModels$EnumerationAttributeType'
241
+ enum_attribute_reader(name, java_type)
242
+ else
243
+ "return (#{java_type}) getMendixObject().getValue(context, MemberNames.#{name}.toString());"
244
+ end
245
+ value = if type['$Type'] == 'DomainModels$EnumerationAttributeType'
246
+ 'value == null ? null : value.toString()'
247
+ else
248
+ 'value'
249
+ end
250
+ <<~JAVA
251
+ public final #{java_type} get#{name}() { return get#{name}(getContext()); }
252
+ public final #{java_type} get#{name}(com.mendix.systemwideinterfaces.core.IContext context) {
253
+ #{read}
254
+ }
255
+ public final void set#{name}(#{java_type} value) { set#{name}(getContext(), value); }
256
+ public final void set#{name}(com.mendix.systemwideinterfaces.core.IContext context, #{java_type} value) {
257
+ getMendixObject().setValue(context, MemberNames.#{name}.toString(), #{value});
258
+ }
259
+ JAVA
260
+ end
261
+
262
+ def enum_attribute_reader(name, java_type)
263
+ "Object value = getMendixObject().getValue(context, MemberNames.#{name}.toString());\n" \
264
+ " return value == null ? null : #{java_type}.valueOf((java.lang.String) value);"
265
+ end
266
+
267
+ def attribute_java_type(unit, type)
268
+ unless type['$Type'] == 'DomainModels$EnumerationAttributeType'
269
+ return TYPE_MAP.fetch(type['$Type'],
270
+ 'java.lang.Object')
271
+ end
272
+
273
+ reference = type['Enumeration'].to_s
274
+ reference = "#{unit.module_name}.#{reference}" unless reference.include?('.')
275
+ java_proxy_name(reference)
276
+ end
277
+
278
+ def associations_for(unit, entity)
279
+ id = identifier(entity['$ID'])
280
+ associations = array(unit.document['Associations']) + array(unit.document['CrossAssociations'])
281
+ associations.select { identifier(_1['ParentPointer']) == id }
282
+ end
283
+
284
+ def association_methods(unit, association)
285
+ name = association_name(association)
286
+ child_type = association_child_type(unit, association)
287
+ return reference_methods(name, child_type) if association['Type'] == 'Reference'
288
+ return '' unless association['Type'] == 'ReferenceSet'
289
+
290
+ <<~JAVA
291
+ public final java.util.List<#{child_type}> get#{name}() throws com.mendix.core.CoreException { return get#{name}(getContext()); }
292
+ public final java.util.List<#{child_type}> get#{name}(com.mendix.systemwideinterfaces.core.IContext context) throws com.mendix.core.CoreException {
293
+ java.util.List<com.mendix.systemwideinterfaces.core.IMendixIdentifier> ids = getMendixObject().getValue(context, MemberNames.#{name}.toString());
294
+ if (ids == null) return java.util.Collections.emptyList();
295
+ java.util.List<#{child_type}> result = new java.util.ArrayList<>();
296
+ for (com.mendix.systemwideinterfaces.core.IMendixIdentifier id : ids) result.add(#{child_type}.load(context, id));
297
+ return result;
298
+ }
299
+ public final void set#{name}(java.util.List<#{child_type}> values) { set#{name}(getContext(), values); }
300
+ public final void set#{name}(com.mendix.systemwideinterfaces.core.IContext context, java.util.List<#{child_type}> values) {
301
+ java.util.List<com.mendix.systemwideinterfaces.core.IMendixIdentifier> ids = values == null ? null : values.stream()
302
+ .map(value -> value.getMendixObject().getId()).collect(java.util.stream.Collectors.toList());
303
+ getMendixObject().setValue(context, MemberNames.#{name}.toString(), ids);
304
+ }
305
+ JAVA
306
+ end
307
+
308
+ def association_name(association)
309
+ association['Name'] || association['UnqualifiedName'] || association['QualifiedName'].to_s.split('.').last
310
+ end
311
+
312
+ def association_qualified_name(unit, association)
313
+ association['QualifiedName'] || "#{unit.module_name}.#{association_name(association)}"
314
+ end
315
+
316
+ def association_child_type(unit, association)
317
+ qualified = association_child_qualified(unit, association)
318
+ unless qualified.empty?
319
+ return java_proxy_name(qualified) if @entities.key?(qualified)
320
+
321
+ return 'com.mendix.systemwideinterfaces.core.IEntityProxy'
322
+ end
323
+
324
+ 'com.mendix.systemwideinterfaces.core.IEntityProxy'
325
+ end
326
+
327
+ def association_child_qualified(unit, association)
328
+ qualified = association['Child'].to_s
329
+ return qualified unless qualified.empty?
330
+
331
+ child = entity_by_id(association['ChildPointer'])
332
+ child ? entity_qualified_name(unit, child) : ''
333
+ end
334
+
335
+ def reference_methods(name, child_type)
336
+ <<~JAVA
337
+ public final #{child_type} get#{name}() throws com.mendix.core.CoreException { return get#{name}(getContext()); }
338
+ public final #{child_type} get#{name}(com.mendix.systemwideinterfaces.core.IContext context) throws com.mendix.core.CoreException {
339
+ com.mendix.systemwideinterfaces.core.IMendixIdentifier id = getMendixObject().getValue(context, MemberNames.#{name}.toString());
340
+ return id == null ? null : #{child_type}.load(context, id);
341
+ }
342
+ public final void set#{name}(#{child_type} value) { set#{name}(getContext(), value); }
343
+ public final void set#{name}(com.mendix.systemwideinterfaces.core.IContext context, #{child_type} value) {
344
+ getMendixObject().setValue(context, MemberNames.#{name}.toString(), value == null ? null : value.getMendixObject().getId());
345
+ }
346
+ JAVA
347
+ end
348
+
349
+ def entity_by_id(id)
350
+ wanted = identifier(id)
351
+ @entities.values.map(&:last).find { identifier(_1['$ID']) == wanted }
352
+ end
353
+
354
+ def identifier(value)
355
+ value.respond_to?(:data) ? value.data : value.to_s
356
+ end
357
+
358
+ def attributes(entity) = array(entity['Attributes'])
359
+ def generalization(entity) = entity.dig('MaybeGeneralization', 'Generalization').to_s
360
+
361
+ def enumeration_units
362
+ source_units = @source.units_of('Enumerations$Enumeration')
363
+ system_units = @system_seed.package.documents.filter_map do |document|
364
+ next unless document['$Type'] == 'Enumerations$Enumeration'
365
+
366
+ SourceModel::Unit.new(
367
+ id: identifier(document['$ID']), container_id: SystemModelSeed::MODULE_ID,
368
+ containment: 'AllDocuments', document:, module_name: 'System'
369
+ )
370
+ end
371
+ source_units + system_units
372
+ end
373
+
374
+ def write_enum(unit)
375
+ names = array(unit.document['Values']).map { _1['Name'] }
376
+ name = document_name(unit.document)
377
+ source = <<~JAVA
378
+ // Generated natively by mxrb from the MPR model.
379
+ package #{java_package(unit.module_name)}.proxies;
380
+ public enum #{name} { #{names.join(', ')} }
381
+ JAVA
382
+ write_missing(proxy_path(unit.module_name, "#{name}.java"), source)
383
+ end
384
+
385
+ def document_name(document) = document['Name'] || document['UnqualifiedName']
386
+
387
+ def constant_modules = @source.units_of('Constants$Constant').map(&:module_name).uniq
388
+
389
+ def constants_referenced?(text, mod)
390
+ referenced?(text, "#{java_package(mod)}.proxies.constants.Constants")
391
+ end
392
+
393
+ def write_constants(mod)
394
+ units = @source.units_of('Constants$Constant').select { _1.module_name == mod }
395
+ methods = units.map do |unit|
396
+ type = CONSTANT_TYPE_MAP.fetch(unit.document.dig('Type', '$Type'), 'java.lang.Object')
397
+ name = unit.document['Name']
398
+ "public static #{type} get#{name}() { return (#{type}) " \
399
+ "com.mendix.core.Core.getConfiguration().getConstantValue(\"#{mod}.#{name}\"); }"
400
+ end.join("\n ")
401
+ source = <<~JAVA
402
+ // Generated natively by mxrb from the MPR model.
403
+ package #{java_package(mod)}.proxies.constants;
404
+ public final class Constants {
405
+ private Constants() {}
406
+ #{methods}
407
+ }
408
+ JAVA
409
+ write_missing(proxy_path(mod, 'constants', 'Constants.java'), source)
410
+ end
411
+
412
+ def microflow_modules = @source.units_of('Microflows$Microflow').map(&:module_name).uniq
413
+
414
+ def microflows_referenced?(text, mod)
415
+ referenced?(text, "#{java_package(mod)}.proxies.microflows.Microflows")
416
+ end
417
+
418
+ def write_microflows(mod, text)
419
+ units = @source.units_of('Microflows$Microflow').select { _1.module_name == mod }
420
+ selected = units.select { |unit| referenced_microflow?(text, unit.document['Name']) }
421
+ return false if selected.empty?
422
+
423
+ methods = selected.map { microflow_method(_1) }.join("\n")
424
+ source = <<~JAVA
425
+ // Generated natively by mxrb from the MPR model.
426
+ package #{java_package(mod)}.proxies.microflows;
427
+ public final class Microflows {
428
+ private Microflows() {}
429
+ #{methods}
430
+ }
431
+ JAVA
432
+ write_missing(proxy_path(mod, 'microflows', 'Microflows.java'), source)
433
+ end
434
+
435
+ def referenced_microflow?(text, name)
436
+ method = lower_camel(name)
437
+ text.match?(/\bMicroflows\.#{Regexp.escape(method)}\b/)
438
+ end
439
+
440
+ def microflow_method(unit)
441
+ parameters = microflow_parameters(unit.document)
442
+ declarations = parameters.map do |parameter|
443
+ "#{java_data_type(parameter['VariableType'])} _#{lower_camel(parameter['Name'])}"
444
+ end
445
+ arguments = parameters.map do |parameter|
446
+ ".withParam(\"#{parameter['Name']}\", _#{lower_camel(parameter['Name'])})"
447
+ end.join
448
+ return_type = java_data_type(unit.document['MicroflowReturnType'], return_type: true)
449
+ result = microflow_result(unit.document['MicroflowReturnType'])
450
+ <<~JAVA
451
+ public static #{return_type} #{lower_camel(unit.document['Name'])}(
452
+ com.mendix.systemwideinterfaces.core.IContext context#{declarations.empty? ? '' : ",\n #{declarations.join(",\n ")}"}) {
453
+ Object result = com.mendix.core.Core.microflowCall("#{unit.module_name}.#{unit.document['Name']}")#{arguments}.execute(context);
454
+ #{result}
455
+ }
456
+ JAVA
457
+ end
458
+
459
+ def microflow_parameters(document)
460
+ array(document.dig('ObjectCollection', 'Objects')).select do |object|
461
+ object['$Type'] == 'Microflows$MicroflowParameter'
462
+ end
463
+ end
464
+
465
+ def java_data_type(type, return_type: false)
466
+ case type&.fetch('$Type', nil)
467
+ when 'DataTypes$BooleanType' then return_type ? 'boolean' : 'java.lang.Boolean'
468
+ when 'DataTypes$IntegerType', 'DataTypes$LongType' then 'java.lang.Long'
469
+ when 'DataTypes$DecimalType' then 'java.math.BigDecimal'
470
+ when 'DataTypes$DateTimeType' then 'java.util.Date'
471
+ when 'DataTypes$StringType' then 'java.lang.String'
472
+ when 'DataTypes$ObjectType' then java_proxy_name(type['Entity'])
473
+ when 'DataTypes$VoidType', nil then 'void'
474
+ else 'java.lang.Object'
475
+ end
476
+ end
477
+
478
+ def microflow_result(type)
479
+ case type&.fetch('$Type', nil)
480
+ when 'DataTypes$BooleanType' then 'return (boolean) result;'
481
+ when 'DataTypes$ObjectType'
482
+ proxy = java_proxy_name(type['Entity'])
483
+ "return result == null ? null : #{proxy}.initialize(context, " \
484
+ '(com.mendix.systemwideinterfaces.core.IMendixObject) result);'
485
+ when 'DataTypes$VoidType', nil then 'return;'
486
+ else "return (#{java_data_type(type, return_type: true)}) result;"
487
+ end
488
+ end
489
+
490
+ def lower_camel(value)
491
+ value.to_s.sub(/\A./, &:downcase)
492
+ end
493
+
494
+ def proxy_path(mod, *parts)
495
+ File.join(@project_root, 'javasource', java_package(mod), 'proxies', *parts)
496
+ end
497
+
498
+ def write_missing(path, contents)
499
+ return false if File.exist?(path)
500
+
501
+ FileUtils.mkdir_p(File.dirname(path))
502
+ File.write(path, contents)
503
+ true
504
+ end
505
+ end
506
+ # rubocop:enable Metrics/AbcSize, Metrics/ClassLength, Metrics/CyclomaticComplexity
507
+ # rubocop:enable Metrics/MethodLength, Metrics/PerceivedComplexity
508
+ end
509
+ end