View Javadoc

1   package org.appfuse.tool;
2   
3   import org.apache.commons.io.FileUtils;
4   import org.apache.maven.artifact.Artifact;
5   import org.apache.maven.plugin.MojoFailureException;
6   import org.apache.maven.plugin.logging.Log;
7   import org.apache.maven.plugin.logging.SystemStreamLog;
8   import org.apache.maven.project.MavenProject;
9   import org.apache.tools.ant.Project;
10  import org.apache.tools.ant.taskdefs.Copy;
11  import org.apache.tools.ant.taskdefs.Echo;
12  import org.apache.tools.ant.taskdefs.LoadFile;
13  import org.apache.tools.ant.taskdefs.Replace;
14  import org.apache.tools.ant.taskdefs.optional.ReplaceRegExp;
15  import org.apache.tools.ant.types.FileSet;
16  import org.appfuse.mojo.installer.AntUtils;
17  
18  import java.io.File;
19  import java.io.IOException;
20  import java.util.ArrayList;
21  
22  /**
23   * This class is responsible for installing generated CRUD artifacts into an AppFuse application.
24   *
25   * @author mraible
26   */
27  public class ArtifactInstaller {
28      private Log log;
29      static final String FILE_SEP = System.getProperty("file.separator");
30      Project antProject;
31      String pojoName;
32      String pojoNameLower;
33      String destinationDirectory;
34      String sourceDirectory;
35      MavenProject project;
36      boolean genericCore;
37      StringUtils util;
38  
39      public ArtifactInstaller(MavenProject project, String pojoName, String sourceDirectory, String destinationDirectory, boolean genericCore) {
40          this.project = project;
41          this.pojoName = pojoName;
42          this.pojoNameLower = pojoLowerCase(pojoName);
43          this.sourceDirectory = sourceDirectory;
44          this.destinationDirectory = destinationDirectory;
45          this.genericCore = genericCore;
46          this.util = new StringUtils();
47      }
48  
49      public void execute() {
50          antProject = AntUtils.createProject();
51  
52          boolean hasDbUnit = projectContainsPluginArtifact("dbunit");
53  
54          if (hasDbUnit) {
55              log("Installing sample data for DbUnit...");
56              installSampleData();
57          }
58  
59          // install dao and manager if jar (modular/core) or war w/o parent (basic)
60          if (project.getPackaging().equals("jar") ||
61              (project.getPackaging().equals("war") && project.getParentArtifact().getGroupId().contains("appfuse"))) {
62              copyGeneratedObjects(this.sourceDirectory, this.destinationDirectory, "**/model/**/*.java");
63              copyGeneratedObjects(this.sourceDirectory, this.destinationDirectory, "**/dao/**/*.java");
64              copyGeneratedObjects(this.sourceDirectory, this.destinationDirectory, "**/service/**/*.java");
65              if (genericCore) {
66                  log("Installing Spring bean definitions (genericCore == true)...");
67                  installGenericBeanDefinitions();
68              }
69              // only installs if iBATIS is configured as dao.framework
70              installiBATISFiles();
71          }
72  
73          if (project.getPackaging().equalsIgnoreCase("war")) {
74              copyGeneratedObjects(this.sourceDirectory, this.destinationDirectory, "**/webapp/**/*.java");
75  
76              String webFramework = project.getProperties().getProperty("web.framework");
77  
78              if ("jsf".equalsIgnoreCase(webFramework)) {
79                  log("Installing JSF views and configuring...");
80                  installJSFNavigationAndBeans();
81                  installJSFViews();
82              } else if ("struts".equalsIgnoreCase(webFramework)) {
83                  log("Installing Struts views and configuring...");
84                  installStrutsActionDefinitions();
85                  copyGeneratedObjects(sourceDirectory + "/src/main/resources",
86                          destinationDirectory + "/src/main/resources", "**/model/*.xml");
87                  copyGeneratedObjects(sourceDirectory + "/src/main/resources",
88                          destinationDirectory + "/src/main/resources", "**/webapp/action/*.xml");
89                  installStrutsViews();
90              } else if ("spring".equalsIgnoreCase(webFramework) || "spring-security".equalsIgnoreCase(webFramework)) {
91                  log("Installing Spring views...");
92                  installSpringValidation();
93                  installSpringViews();
94              } else if ("spring-freemarker".equalsIgnoreCase(webFramework)) {
95                  log("Installing Freemarker views...");
96                  installSpringFreemarkerViews();
97              } else if ("stripes".equalsIgnoreCase(webFramework)) {
98                  log("Installing Stripes views...");
99                  installStripesViews();
100             } else if ("tapestry".equalsIgnoreCase(webFramework)) {
101                 log("Installing Tapestry views...");
102                 installTapestryViews();
103             } else if ("wicket".equalsIgnoreCase(webFramework)) {
104                 log("Installing Wicket views...");
105                 installWicketViews();
106             }
107 
108             log("Installing i18n messages...");
109             installInternationalizationKeys(webFramework);
110 
111             if (!"tapestry".equalsIgnoreCase(webFramework)) {
112                 log("Installing menu...");
113                 installMenu();
114             }
115 
116             log("Installing UI tests...");
117             installUITests(webFramework);
118         }
119     }
120 
121     private boolean projectContainsPluginArtifact(String artifactId) {
122         for (Object artifact : project.getPluginArtifacts()) {
123             if (((Artifact) artifact).getArtifactId().contains(artifactId)) {
124                 return true;
125             }
126         }
127         return false;
128     }
129 
130     private boolean projectContainsArtifact(String artifactId) {
131         for (Object artifact : project.getArtifacts()) {
132             if (((Artifact) artifact).getArtifactId().contains(artifactId)) {
133                 return true;
134             }
135         }
136         return false;
137     }
138 
139     /**
140      * This method will copy files from the source directory to the destination directory based on
141      * the pattern.
142      *
143      * @param inSourceDirectory      The source directory to copy from.
144      * @param inDestinationDirectory The destination directory to copy to.
145      * @param inPattern              The file pattern to match to locate files to copy.
146      */
147     protected void copyGeneratedObjects(final String inSourceDirectory, final String inDestinationDirectory,
148                                         final String inPattern) {
149         Copy copyTask = (Copy) antProject.createTask("copy");
150 
151         FileSet fileSet = AntUtils.createFileset(inSourceDirectory, inPattern, new ArrayList());
152         log("Installing generated files (pattern: " + inPattern + ")...");
153         copyTask.setTodir(new File(inDestinationDirectory));
154         copyTask.addFileset(fileSet);
155         copyTask.execute();
156     }
157 
158     private String pojoLowerCase(String name) {
159         return name.substring(0, 1).toLowerCase() + name.substring(1);
160     }
161 
162     private String getPathToApplicationContext() {
163         if (project.getPackaging().equalsIgnoreCase("war")) {
164             return "/src/main/webapp/WEB-INF/applicationContext.xml";
165         } else { // if (project.getPackaging().equalsIgnoreCase("jar")) {
166             return "/src/main/resources/applicationContext.xml";
167         }
168     }
169 
170     /**
171      * Add sample-data.xml to project's sample-data.xml
172      */
173     private void installSampleData() {
174         createLoadFileTask("src/test/resources/" + pojoName + "-sample-data.xml", "sample.data").execute();
175         File existingFile = new File(destinationDirectory + "/src/test/resources/sample-data.xml");
176 
177         parseXMLFile(existingFile, null, "</dataset>", "sample.data");
178     }
179 
180     private void installiBATISFiles() {
181         if (project.getProperties().getProperty("dao.framework").equals("ibatis")) {
182             log("Installing iBATIS SQL Maps...");
183             createLoadFileTask("src/main/resources/" + pojoName + "-sql-map-config.xml", "sql.map.config").execute();
184             File sqlMapConfig = new File(destinationDirectory + "/src/main/resources/sql-map-config.xml");
185             parseXMLFile(sqlMapConfig, null, "</sqlMapConfig>", "sql.map.config");
186 
187             File sqlMapsDir = new File(destinationDirectory + "/src/main/resources/sqlmaps");
188             if (sqlMapsDir.exists()) {
189                 sqlMapsDir.mkdir();
190             }
191 
192             Copy copy = (Copy) antProject.createTask("copy");
193             copy.setFile(new File(sourceDirectory + "/src/main/resources/sqlmaps/" + pojoName + "SQL.xml"));
194             copy.setTodir(new File(destinationDirectory + "/src/main/resources/sqlmaps"));
195             copy.execute();
196 
197             // Add compass gps bean if it doesn't exist
198             File ctx = new File(destinationDirectory + "/src/main/webapp/WEB-INF/applicationContext.xml");
199             try {
200                 File appCtx = new File(destinationDirectory + "/src/main/webapp/WEB-INF/applicationContext.xml");
201                 String appCtxAsString = FileUtils.readFileToString(ctx);
202                 if (!appCtxAsString.contains("SqlMapClientGpsDevice")) {
203                     log("Adding compassGps bean to applicationContext.xml");
204                     createLoadFileTask("src/main/resources/compass-gps.xml", "compass.gps").execute();
205                     parseXMLFile(appCtx, null, "<!-- Add new DAOs here -->", "compass.gps");
206                 }
207 
208                 if (!appCtxAsString.contains("<value>get" + pojoName)) {
209                     // add value to list of select statement Ids
210                     createLoadFileTask("src/main/resources/" + pojoName + "-select-ids.xml", "select.ids").execute();
211                     parseXMLFile(appCtx, null, "<value>getUsers</value>", "select.ids");
212                 }
213             } catch (IOException e) {
214                 log("Failed to read project's applicationContext.xml!");
215                 e.printStackTrace();
216             }
217         }
218     }
219 
220     private void installGenericBeanDefinitions() {
221         createLoadFileTask("src/main/resources/" + pojoName + "-generic-beans.xml", "context.file").execute();
222         File generatedFile = new File(destinationDirectory + getPathToApplicationContext());
223 
224         parseXMLFile(generatedFile, pojoName + "Manager", "<!-- Add new Managers here -->", "context.file");
225     }
226 
227     private void installJSFNavigationAndBeans() {
228         createLoadFileTask("src/main/webapp/WEB-INF/" + pojoName + "-navigation.xml", "navigation.rules").execute();
229         File generatedFile = new File(destinationDirectory + "/src/main/webapp/WEB-INF/faces-config.xml");
230         parseXMLFile(generatedFile, pojoName + "-nav", "<!-- Add additional rules here -->", "navigation.rules");
231     }
232 
233     private void installSpringValidation() {
234         createLoadFileTask("src/main/webapp/WEB-INF/" + pojoName + "-validation.xml", "spring.validation").execute();
235         File generatedFile = new File(destinationDirectory + "/src/main/webapp/WEB-INF/validation.xml");
236 
237         parseXMLFile(generatedFile, pojoName, "    </formset>", "spring.validation");
238     }
239 
240     private void installStrutsActionDefinitions() {
241         createLoadFileTask("src/main/resources/" + pojoName + "-struts.xml", "struts.file").execute();
242         File existingFile = new File(destinationDirectory + "/src/main/resources/struts.xml");
243 
244         parseXMLFile(existingFile, pojoName + "Action", "<!-- Add additional actions here -->", "struts.file");
245     }
246 
247     // =================== Views ===================
248 
249     private void installJSFViews() {
250         Copy copy = (Copy) antProject.createTask("copy");
251         copy.setFile(new File(sourceDirectory + "/src/main/webapp/" + pojoName + "Form.xhtml"));
252         copy.setTofile(new File(destinationDirectory + "/src/main/webapp/" + pojoNameLower + "Form.xhtml"));
253         copy.execute();
254 
255         copy.setFile(new File(sourceDirectory + "/src/main/webapp/" + pojoName + "s.xhtml"));
256         copy.setTofile(new File(destinationDirectory + "/src/main/webapp/" + util.getPluralForWord(pojoNameLower) + ".xhtml"));
257         copy.execute();
258     }
259 
260     private void installSpringViews() {
261         Copy copy = (Copy) antProject.createTask("copy");
262         copy.setFile(new File(sourceDirectory + "/src/main/webapp/WEB-INF/pages/" + pojoName + "form.jsp"));
263         copy.setTofile(new File(destinationDirectory + "/src/main/webapp/WEB-INF/pages/" + pojoNameLower + "form.jsp"));
264         copy.execute();
265 
266         copy.setFile(new File(sourceDirectory + "/src/main/webapp/WEB-INF/pages/" + pojoName + "s.jsp"));
267         copy.setTofile(new File(destinationDirectory + "/src/main/webapp/WEB-INF/pages/" + util.getPluralForWord(pojoNameLower) + ".jsp"));
268         copy.execute();
269     }
270 
271     private void installSpringFreemarkerViews() {
272         Copy copy = (Copy) antProject.createTask("copy");
273         copy.setFile(new File(sourceDirectory + "/src/main/webapp/" + pojoName + "form.ftl"));
274         copy.setTofile(new File(destinationDirectory + "/src/main/webapp/" + pojoNameLower + "form.ftl"));
275         copy.execute();
276 
277         copy.setFile(new File(sourceDirectory + "/src/main/webapp/" + pojoName + "list.ftl"));
278         copy.setTofile(new File(destinationDirectory + "/src/main/webapp/" + util.getPluralForWord(pojoNameLower) + ".ftl"));
279         copy.execute();
280     }
281 
282     private void installStripesViews() {
283         Copy copy = (Copy) antProject.createTask("copy");
284         copy.setFile(new File(sourceDirectory + "/src/main/webapp/" + pojoName + "Form.jsp"));
285         copy.setTofile(new File(destinationDirectory + "/src/main/webapp/" + pojoNameLower + "Form.jsp"));
286         copy.execute();
287 
288         copy.setFile(new File(sourceDirectory + "/src/main/webapp/" + pojoName + "List.jsp"));
289         copy.setTofile(new File(destinationDirectory + "/src/main/webapp/" + pojoNameLower + "List.jsp"));
290         copy.execute();
291     }
292 
293     private void installStrutsViews() {
294         Copy copy = (Copy) antProject.createTask("copy");
295         copy.setFile(new File(sourceDirectory + "/src/main/webapp/WEB-INF/pages/" + pojoName + "Form.jsp"));
296         copy.setTofile(new File(destinationDirectory + "/src/main/webapp/WEB-INF/pages/" + pojoNameLower + "Form.jsp"));
297         copy.execute();
298 
299         copy.setFile(new File(sourceDirectory + "/src/main/webapp/WEB-INF/pages/" + pojoName + "List.jsp"));
300         copy.setTofile(new File(destinationDirectory + "/src/main/webapp/WEB-INF/pages/" + pojoNameLower + "List.jsp"));
301         copy.execute();
302     }
303 
304     private void installTapestryViews() {
305         Copy copy = (Copy) antProject.createTask("copy");
306         copy.setFile(new File(sourceDirectory + "/src/main/webapp/" + pojoName + "Form.tml"));
307         copy.setTodir(new File(destinationDirectory + "/src/main/webapp"));
308         copy.execute();
309 
310         copy.setFile(new File(sourceDirectory + "/src/main/webapp/" + pojoName + "List.tml"));
311         copy.execute();
312 
313         log("Installing menu...");
314         createLoadFileTask("src/main/webapp/" + pojoName + "-menu.tml", "tapestry-menu").execute();
315         File existingFile = new File(destinationDirectory + "/src/main/resources/" +
316                 project.getGroupId().replace(".", "/") + "/webapp/components/Layout.tml");
317         parseXMLFile(existingFile, pojoName, "<!-- Add new menu items here -->", "tapestry-menu");
318     }
319 
320     private void installWicketViews() {
321         copyGeneratedObjects(this.sourceDirectory, this.destinationDirectory, "**/pages/*.html");
322     }
323 
324     private boolean isAppFuse() {
325         return (project.getParent().getArtifactId().contains("appfuse-web") ||
326                 project.getParent().getParent().getGroupId().contains("appfuse"));
327     }
328 
329     // =================== End of Views ===================
330 
331     private void installMenu() {
332         boolean hasStrutsMenu;
333         File menuConfig = new File(destinationDirectory + "/src/main/webapp/WEB-INF/menu-config.xml");
334         hasStrutsMenu = menuConfig.exists();
335 
336         if (hasStrutsMenu) {
337             createLoadFileTask("src/main/webapp/common/" + pojoName + "-menu.jsp", "menu.jsp").execute();
338             File existingFile = new File(destinationDirectory + "/src/main/webapp/common/menu.jsp");
339 
340             parseXMLFile(existingFile, pojoName, "</ul>", "menu.jsp");
341 
342             createLoadFileTask("src/main/webapp/WEB-INF/" + pojoName + "-menu-config.xml", "menu.config").execute();
343             existingFile = new File(destinationDirectory + "/src/main/webapp/WEB-INF/menu-config.xml");
344 
345             parseXMLFile(existingFile, pojoName, "    </Menus>", "menu.config");
346         } else {
347             File freemarker = new File(destinationDirectory + "/src/main/webapp/decorators/default.ftl");
348             if (freemarker.exists()) {
349                 createLoadFileTask("src/main/webapp/common/" + pojoName + "-menu-light.ftl", "menu-light.jsp").execute();
350             } else {
351                 createLoadFileTask("src/main/webapp/common/" + pojoName + "-menu-light.jsp", "menu-light.jsp").execute();
352             }
353 
354             File existingFile = new File(destinationDirectory + "/src/main/webapp/decorators/default.jsp");
355             File jsfConfig = new File(destinationDirectory + "/src/main/webapp/WEB-INF/faces-config.xml");
356             if (jsfConfig.exists()) {
357                 existingFile = new File(destinationDirectory + "/src/main/webapp/layouts/default.xhtml");
358             }
359             if (freemarker.exists()) {
360                 existingFile = new File(destinationDirectory + "/src/main/webapp/decorators/default.ftl");
361             }
362 
363             parseXMLFile(existingFile, pojoName, "<!-- Add new menu items here -->", "menu-light.jsp");
364         }
365     }
366 
367     private void installInternationalizationKeys(String webFramework) {
368         createLoadFileTask("src/main/resources/" + pojoName + "-ApplicationResources.properties", "i18n.file").execute();
369         File existingFile = new File(destinationDirectory + "/src/main/resources/ApplicationResources.properties");
370 
371         // if ApplicationResources doesn't exist, assume appfuse-light and use messages instead
372         if (!existingFile.exists()) {
373             if ("wicket".equalsIgnoreCase(webFramework)) {
374                 existingFile = new File(destinationDirectory + "/src/main/java/" + project.getGroupId().replace(".", "/")
375                         + "/webapp/pages/AbstractWebPage.properties");
376             } else {
377                 existingFile = new File(destinationDirectory + "/src/main/resources/messages.properties");
378             }
379         }
380 
381         parsePropertiesFile(existingFile, pojoName);
382 
383         Echo echoTask = (Echo) antProject.createTask("echo");
384         echoTask.setFile(existingFile);
385         echoTask.setAppend(true);
386         echoTask.setMessage(antProject.getProperty("i18n.file"));
387         echoTask.execute();
388     }
389 
390     private void installUITests(String webFramework) {
391         // Gracefully handle when ui tests don't exist
392         boolean webTestsExist = new File("src/test/resources/" + "web-tests.xml").exists();
393         File existingFile = new File(destinationDirectory + "/src/test/resources/web-tests.xml");
394         if (webTestsExist && existingFile.exists()) {
395             createLoadFileTask("src/test/resources/" + pojoName + "-web-tests.xml", "web.tests").execute();
396             parseXMLFile(existingFile, pojoName, "</project>", "web.tests");
397 
398             // Add main target to run-all-tests target
399             Replace replace = (Replace) antProject.createTask("replace");
400             replace.setFile(existingFile);
401 
402             try {
403                 if (FileUtils.readFileToString(existingFile).contains("FileUpload")) {
404                     // todo: figure out how to fix the 2 lines below so they don't include pojoNameTest
405                     // multiple times on subsequent installs
406                     if ("wicket".equalsIgnoreCase(webFramework)) {
407                         replace.setToken(",DWR");
408                         replace.setValue(",DWR," + pojoName + "Tests");
409                     } else {
410                         replace.setToken(",FileUpload");
411                         replace.setValue(",FileUpload," + pojoName + "Tests");
412                     }
413                 } else {
414                     // AppFuse Light
415                     replace.setToken("depends=\"UserTests");
416                     replace.setValue("depends=\"UserTests," + pojoName + "Tests");
417                 }
418             } catch (IOException e) {
419                 e.printStackTrace();
420             }
421             replace.execute();
422 
423             // Delete any jWebUnit artifacts that may have been installed
424             File jwebunitTest = new File(destinationDirectory + "/src/test/java/" +
425                     project.getGroupId().replace(".", "/") + "/webapp/" + pojoName + "WebTest.java");
426             jwebunitTest.delete();
427         }
428     }
429 
430     /**
431      * This method will create an ANT based LoadFile task based on an infile and a property name.
432      * The property will be loaded with the infile for use later by the Replace task.
433      *
434      * @param inFile   The file to process
435      * @param propName the name to assign it to
436      * @return The ANT LoadFile task that loads a property with a file
437      */
438     protected LoadFile createLoadFileTask(String inFile, String propName) {
439         inFile = sourceDirectory + FILE_SEP + inFile;
440         LoadFile loadFileTask = (LoadFile) antProject.createTask("loadfile");
441         loadFileTask.init();
442         loadFileTask.setProperty(propName);
443         loadFileTask.setSrcFile(new File(inFile));
444 
445         return loadFileTask;
446     }
447 
448     private void parseXMLFile(File existingFile, String beanName, String tokenToReplace, String fileVariable) {
449         String nameInComment = beanName;
450         if (beanName == null) {
451             nameInComment = pojoName;
452         }
453         Replace replace1 = (Replace) antProject.createTask("replace");
454         replace1.setFile(existingFile);
455         replace1.setToken("<!--" + nameInComment + "-START-->");
456         replace1.setValue("REGULAR-START");
457         replace1.execute();
458 
459         Replace replace2 = (Replace) antProject.createTask("replace");
460         replace2.setFile(existingFile);
461         replace2.setToken("<!--" + nameInComment + "-END-->");
462         replace2.setValue("REGULAR-END");
463         replace2.execute();
464 
465         ReplaceRegExp regExpTask = (ReplaceRegExp) antProject.createTask("replaceregexp");
466         regExpTask.setFile(existingFile);
467         regExpTask.setMatch("REGULAR-START(?s:.)*REGULAR-END");
468         regExpTask.setReplace("");
469         regExpTask.setFlags("g");
470         regExpTask.execute();
471 
472         Replace replaceData = (Replace) antProject.createTask("replace");
473         replaceData.setFile(existingFile);
474         replaceData.setToken(tokenToReplace);
475         String stringWithProperLineEndings = adjustLineEndingsForOS(antProject.getProperty(fileVariable));
476         replaceData.setValue(stringWithProperLineEndings);
477         replaceData.execute();
478     }
479 
480     /**
481      * This file is the same as the method above, except for different comment placeholder formats.
482      * Yeah, I know, it's ugly.
483      *
484      * @param existingFile file to merge with in project
485      * @param beanName     name of placeholder string that goes in comment
486      */
487     private void parsePropertiesFile(File existingFile, String beanName) {
488         String nameInComment = beanName;
489         if (beanName == null) {
490             nameInComment = pojoName;
491         }
492 
493         Replace replace1 = (Replace) antProject.createTask("replace");
494         replace1.setFile(existingFile);
495         replace1.setToken("# -- " + nameInComment + "-START");
496         replace1.setValue("REGULAR-START");
497         replace1.execute();
498 
499         Replace replace2 = (Replace) antProject.createTask("replace");
500         replace2.setFile(existingFile);
501         replace2.setToken("# -- " + nameInComment + "-END");
502         replace2.setValue("REGULAR-END");
503         replace2.execute();
504 
505         ReplaceRegExp regExpTask = (ReplaceRegExp) antProject.createTask("replaceregexp");
506         regExpTask.setFile(existingFile);
507         regExpTask.setMatch("REGULAR-START(?s:.)*REGULAR-END");
508         regExpTask.setReplace("");
509         regExpTask.setFlags("g");
510         regExpTask.execute();
511     }
512 
513     private static String adjustLineEndingsForOS(String property) {
514         String os = System.getProperty("os.name");
515 
516         if (os.startsWith("Linux") || os.startsWith("Mac")) {
517             // remove the \r returns
518             property = property.replaceAll("\r", "");
519         } else if (os.startsWith("Windows")) {
520             // use windows line endings
521             property = property.replaceAll(">\n", ">\r\n");
522         }
523 
524         return property;
525     }
526 
527     private void log(String msg) {
528         getLog().info("[AppFuse] " + msg);
529     }
530 
531     public Log getLog() {
532         if (log == null) {
533             log = new SystemStreamLog();
534         }
535 
536         return log;
537     }
538 
539     public void setProject(MavenProject project) {
540         this.project = project;
541     }
542 
543     public void setGenericCore(boolean genericCore) {
544         this.genericCore = genericCore;
545     }
546 }