View Javadoc
1   /*
2    *    Copyright 2006-2023 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       https://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.mybatis.generator.config.xml;
17  
18  import static org.mybatis.generator.internal.util.StringUtility.isTrue;
19  import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;
20  import static org.mybatis.generator.internal.util.messages.Messages.getString;
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.net.URL;
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.Properties;
28  
29  import org.mybatis.generator.config.ColumnOverride;
30  import org.mybatis.generator.config.ColumnRenamingRule;
31  import org.mybatis.generator.config.CommentGeneratorConfiguration;
32  import org.mybatis.generator.config.Configuration;
33  import org.mybatis.generator.config.ConnectionFactoryConfiguration;
34  import org.mybatis.generator.config.Context;
35  import org.mybatis.generator.config.DomainObjectRenamingRule;
36  import org.mybatis.generator.config.GeneratedKey;
37  import org.mybatis.generator.config.IgnoredColumn;
38  import org.mybatis.generator.config.IgnoredColumnException;
39  import org.mybatis.generator.config.IgnoredColumnPattern;
40  import org.mybatis.generator.config.JDBCConnectionConfiguration;
41  import org.mybatis.generator.config.JavaClientGeneratorConfiguration;
42  import org.mybatis.generator.config.JavaModelGeneratorConfiguration;
43  import org.mybatis.generator.config.JavaTypeResolverConfiguration;
44  import org.mybatis.generator.config.ModelType;
45  import org.mybatis.generator.config.PluginConfiguration;
46  import org.mybatis.generator.config.PropertyHolder;
47  import org.mybatis.generator.config.SqlMapGeneratorConfiguration;
48  import org.mybatis.generator.config.TableConfiguration;
49  import org.mybatis.generator.exception.XMLParserException;
50  import org.mybatis.generator.internal.ObjectFactory;
51  import org.w3c.dom.Element;
52  import org.w3c.dom.NamedNodeMap;
53  import org.w3c.dom.Node;
54  import org.w3c.dom.NodeList;
55  
56  /**
57   * This class parses configuration files into the new Configuration API.
58   *
59   * @author Jeff Butler
60   */
61  public class MyBatisGeneratorConfigurationParser {
62      private final Properties extraProperties;
63      private final Properties configurationProperties;
64  
65      public MyBatisGeneratorConfigurationParser(Properties extraProperties) {
66          super();
67          if (extraProperties == null) {
68              this.extraProperties = new Properties();
69          } else {
70              this.extraProperties = extraProperties;
71          }
72          configurationProperties = new Properties();
73      }
74  
75      public Configuration parseConfiguration(Element rootNode)
76              throws XMLParserException {
77  
78          Configuration configuration = new Configuration();
79  
80          NodeList nodeList = rootNode.getChildNodes();
81          for (int i = 0; i < nodeList.getLength(); i++) {
82              Node childNode = nodeList.item(i);
83  
84              if (childNode.getNodeType() != Node.ELEMENT_NODE) {
85                  continue;
86              }
87  
88              if ("properties".equals(childNode.getNodeName())) { //$NON-NLS-1$
89                  parseProperties(childNode);
90              } else if ("classPathEntry".equals(childNode.getNodeName())) { //$NON-NLS-1$
91                  parseClassPathEntry(configuration, childNode);
92              } else if ("context".equals(childNode.getNodeName())) { //$NON-NLS-1$
93                  parseContext(configuration, childNode);
94              }
95          }
96  
97          return configuration;
98      }
99  
100     protected void parseProperties(Node node)
101             throws XMLParserException {
102         Properties attributes = parseAttributes(node);
103         String resource = attributes.getProperty("resource"); //$NON-NLS-1$
104         String url = attributes.getProperty("url"); //$NON-NLS-1$
105 
106         if (!stringHasValue(resource)
107                 && !stringHasValue(url)) {
108             throw new XMLParserException(getString("RuntimeError.14")); //$NON-NLS-1$
109         }
110 
111         if (stringHasValue(resource)
112                 && stringHasValue(url)) {
113             throw new XMLParserException(getString("RuntimeError.14")); //$NON-NLS-1$
114         }
115 
116         URL resourceUrl;
117 
118         try {
119             if (stringHasValue(resource)) {
120                 resourceUrl = ObjectFactory.getResource(resource);
121                 if (resourceUrl == null) {
122                     throw new XMLParserException(getString(
123                             "RuntimeError.15", resource)); //$NON-NLS-1$
124                 }
125             } else {
126                 resourceUrl = new URL(url);
127             }
128 
129             InputStream inputStream = resourceUrl.openConnection()
130                     .getInputStream();
131 
132             configurationProperties.load(inputStream);
133             inputStream.close();
134         } catch (IOException e) {
135             if (stringHasValue(resource)) {
136                 throw new XMLParserException(getString(
137                         "RuntimeError.16", resource)); //$NON-NLS-1$
138             } else {
139                 throw new XMLParserException(getString(
140                         "RuntimeError.17", url)); //$NON-NLS-1$
141             }
142         }
143     }
144 
145     private void parseContext(Configuration configuration, Node node) {
146 
147         Properties attributes = parseAttributes(node);
148         String defaultModelType = attributes.getProperty("defaultModelType"); //$NON-NLS-1$
149         String targetRuntime = attributes.getProperty("targetRuntime"); //$NON-NLS-1$
150         String introspectedColumnImpl = attributes
151                 .getProperty("introspectedColumnImpl"); //$NON-NLS-1$
152         String id = attributes.getProperty("id"); //$NON-NLS-1$
153 
154         ModelType mt = defaultModelType == null ? null : ModelType
155                 .getModelType(defaultModelType);
156 
157         Context context = new Context(mt);
158         context.setId(id);
159         if (stringHasValue(introspectedColumnImpl)) {
160             context.setIntrospectedColumnImpl(introspectedColumnImpl);
161         }
162         if (stringHasValue(targetRuntime)) {
163             context.setTargetRuntime(targetRuntime);
164         }
165 
166         configuration.addContext(context);
167 
168         NodeList nodeList = node.getChildNodes();
169         for (int i = 0; i < nodeList.getLength(); i++) {
170             Node childNode = nodeList.item(i);
171 
172             if (childNode.getNodeType() != Node.ELEMENT_NODE) {
173                 continue;
174             }
175 
176             if ("property".equals(childNode.getNodeName())) { //$NON-NLS-1$
177                 parseProperty(context, childNode);
178             } else if ("plugin".equals(childNode.getNodeName())) { //$NON-NLS-1$
179                 parsePlugin(context, childNode);
180             } else if ("commentGenerator".equals(childNode.getNodeName())) { //$NON-NLS-1$
181                 parseCommentGenerator(context, childNode);
182             } else if ("jdbcConnection".equals(childNode.getNodeName())) { //$NON-NLS-1$
183                 parseJdbcConnection(context, childNode);
184             } else if ("connectionFactory".equals(childNode.getNodeName())) { //$NON-NLS-1$
185                 parseConnectionFactory(context, childNode);
186             } else if ("javaModelGenerator".equals(childNode.getNodeName())) { //$NON-NLS-1$
187                 parseJavaModelGenerator(context, childNode);
188             } else if ("javaTypeResolver".equals(childNode.getNodeName())) { //$NON-NLS-1$
189                 parseJavaTypeResolver(context, childNode);
190             } else if ("sqlMapGenerator".equals(childNode.getNodeName())) { //$NON-NLS-1$
191                 parseSqlMapGenerator(context, childNode);
192             } else if ("javaClientGenerator".equals(childNode.getNodeName())) { //$NON-NLS-1$
193                 parseJavaClientGenerator(context, childNode);
194             } else if ("table".equals(childNode.getNodeName())) { //$NON-NLS-1$
195                 parseTable(context, childNode);
196             }
197         }
198     }
199 
200     protected void parseSqlMapGenerator(Context context, Node node) {
201         SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration = new SqlMapGeneratorConfiguration();
202 
203         context.setSqlMapGeneratorConfiguration(sqlMapGeneratorConfiguration);
204 
205         Properties attributes = parseAttributes(node);
206         String targetPackage = attributes.getProperty("targetPackage"); //$NON-NLS-1$
207         String targetProject = attributes.getProperty("targetProject"); //$NON-NLS-1$
208 
209         sqlMapGeneratorConfiguration.setTargetPackage(targetPackage);
210         sqlMapGeneratorConfiguration.setTargetProject(targetProject);
211 
212         NodeList nodeList = node.getChildNodes();
213         for (int i = 0; i < nodeList.getLength(); i++) {
214             Node childNode = nodeList.item(i);
215 
216             if (childNode.getNodeType() != Node.ELEMENT_NODE) {
217                 continue;
218             }
219 
220             if ("property".equals(childNode.getNodeName())) { //$NON-NLS-1$
221                 parseProperty(sqlMapGeneratorConfiguration, childNode);
222             }
223         }
224     }
225 
226     protected void parseTable(Context context, Node node) {
227         TableConfiguration tc = new TableConfiguration(context);
228         context.addTableConfiguration(tc);
229 
230         Properties attributes = parseAttributes(node);
231 
232         String catalog = attributes.getProperty("catalog"); //$NON-NLS-1$
233         if (stringHasValue(catalog)) {
234             tc.setCatalog(catalog);
235         }
236 
237         String schema = attributes.getProperty("schema"); //$NON-NLS-1$
238         if (stringHasValue(schema)) {
239             tc.setSchema(schema);
240         }
241 
242         String tableName = attributes.getProperty("tableName"); //$NON-NLS-1$
243         if (stringHasValue(tableName)) {
244             tc.setTableName(tableName);
245         }
246 
247         String domainObjectName = attributes.getProperty("domainObjectName"); //$NON-NLS-1$
248         if (stringHasValue(domainObjectName)) {
249             tc.setDomainObjectName(domainObjectName);
250         }
251 
252         String alias = attributes.getProperty("alias"); //$NON-NLS-1$
253         if (stringHasValue(alias)) {
254             tc.setAlias(alias);
255         }
256 
257         String enableInsert = attributes.getProperty("enableInsert"); //$NON-NLS-1$
258         if (stringHasValue(enableInsert)) {
259             tc.setInsertStatementEnabled(isTrue(enableInsert));
260         }
261 
262         String enableSelectByPrimaryKey = attributes
263                 .getProperty("enableSelectByPrimaryKey"); //$NON-NLS-1$
264         if (stringHasValue(enableSelectByPrimaryKey)) {
265             tc.setSelectByPrimaryKeyStatementEnabled(
266                     isTrue(enableSelectByPrimaryKey));
267         }
268 
269         String enableSelectByExample = attributes
270                 .getProperty("enableSelectByExample"); //$NON-NLS-1$
271         if (stringHasValue(enableSelectByExample)) {
272             tc.setSelectByExampleStatementEnabled(
273                     isTrue(enableSelectByExample));
274         }
275 
276         String enableUpdateByPrimaryKey = attributes
277                 .getProperty("enableUpdateByPrimaryKey"); //$NON-NLS-1$
278         if (stringHasValue(enableUpdateByPrimaryKey)) {
279             tc.setUpdateByPrimaryKeyStatementEnabled(
280                     isTrue(enableUpdateByPrimaryKey));
281         }
282 
283         String enableDeleteByPrimaryKey = attributes
284                 .getProperty("enableDeleteByPrimaryKey"); //$NON-NLS-1$
285         if (stringHasValue(enableDeleteByPrimaryKey)) {
286             tc.setDeleteByPrimaryKeyStatementEnabled(
287                     isTrue(enableDeleteByPrimaryKey));
288         }
289 
290         String enableDeleteByExample = attributes
291                 .getProperty("enableDeleteByExample"); //$NON-NLS-1$
292         if (stringHasValue(enableDeleteByExample)) {
293             tc.setDeleteByExampleStatementEnabled(
294                     isTrue(enableDeleteByExample));
295         }
296 
297         String enableCountByExample = attributes
298                 .getProperty("enableCountByExample"); //$NON-NLS-1$
299         if (stringHasValue(enableCountByExample)) {
300             tc.setCountByExampleStatementEnabled(
301                     isTrue(enableCountByExample));
302         }
303 
304         String enableUpdateByExample = attributes
305                 .getProperty("enableUpdateByExample"); //$NON-NLS-1$
306         if (stringHasValue(enableUpdateByExample)) {
307             tc.setUpdateByExampleStatementEnabled(
308                     isTrue(enableUpdateByExample));
309         }
310 
311         String selectByPrimaryKeyQueryId = attributes
312                 .getProperty("selectByPrimaryKeyQueryId"); //$NON-NLS-1$
313         if (stringHasValue(selectByPrimaryKeyQueryId)) {
314             tc.setSelectByPrimaryKeyQueryId(selectByPrimaryKeyQueryId);
315         }
316 
317         String selectByExampleQueryId = attributes
318                 .getProperty("selectByExampleQueryId"); //$NON-NLS-1$
319         if (stringHasValue(selectByExampleQueryId)) {
320             tc.setSelectByExampleQueryId(selectByExampleQueryId);
321         }
322 
323         String modelType = attributes.getProperty("modelType"); //$NON-NLS-1$
324         if (stringHasValue(modelType)) {
325             tc.setConfiguredModelType(modelType);
326         }
327 
328         String escapeWildcards = attributes.getProperty("escapeWildcards"); //$NON-NLS-1$
329         if (stringHasValue(escapeWildcards)) {
330             tc.setWildcardEscapingEnabled(isTrue(escapeWildcards));
331         }
332 
333         String delimitIdentifiers = attributes
334                 .getProperty("delimitIdentifiers"); //$NON-NLS-1$
335         if (stringHasValue(delimitIdentifiers)) {
336             tc.setDelimitIdentifiers(isTrue(delimitIdentifiers));
337         }
338 
339         String delimitAllColumns = attributes.getProperty("delimitAllColumns"); //$NON-NLS-1$
340         if (stringHasValue(delimitAllColumns)) {
341             tc.setAllColumnDelimitingEnabled(isTrue(delimitAllColumns));
342         }
343 
344         String mapperName = attributes.getProperty("mapperName"); //$NON-NLS-1$
345         if (stringHasValue(mapperName)) {
346             tc.setMapperName(mapperName);
347         }
348 
349         String sqlProviderName = attributes.getProperty("sqlProviderName"); //$NON-NLS-1$
350         if (stringHasValue(sqlProviderName)) {
351             tc.setSqlProviderName(sqlProviderName);
352         }
353 
354         NodeList nodeList = node.getChildNodes();
355         for (int i = 0; i < nodeList.getLength(); i++) {
356             Node childNode = nodeList.item(i);
357 
358             if (childNode.getNodeType() != Node.ELEMENT_NODE) {
359                 continue;
360             }
361 
362             if ("property".equals(childNode.getNodeName())) { //$NON-NLS-1$
363                 parseProperty(tc, childNode);
364             } else if ("columnOverride".equals(childNode.getNodeName())) { //$NON-NLS-1$
365                 parseColumnOverride(tc, childNode);
366             } else if ("ignoreColumn".equals(childNode.getNodeName())) { //$NON-NLS-1$
367                 parseIgnoreColumn(tc, childNode);
368             } else if ("ignoreColumnsByRegex".equals(childNode.getNodeName())) { //$NON-NLS-1$
369                 parseIgnoreColumnByRegex(tc, childNode);
370             } else if ("generatedKey".equals(childNode.getNodeName())) { //$NON-NLS-1$
371                 parseGeneratedKey(tc, childNode);
372             } else if ("domainObjectRenamingRule".equals(childNode.getNodeName())) { //$NON-NLS-1$
373                 parseDomainObjectRenamingRule(tc, childNode);
374             } else if ("columnRenamingRule".equals(childNode.getNodeName())) { //$NON-NLS-1$
375                 parseColumnRenamingRule(tc, childNode);
376             }
377         }
378     }
379 
380     private void parseColumnOverride(TableConfiguration tc, Node node) {
381         Properties attributes = parseAttributes(node);
382         String column = attributes.getProperty("column"); //$NON-NLS-1$
383 
384         ColumnOverride co = new ColumnOverride(column);
385 
386         String property = attributes.getProperty("property"); //$NON-NLS-1$
387         if (stringHasValue(property)) {
388             co.setJavaProperty(property);
389         }
390 
391         String javaType = attributes.getProperty("javaType"); //$NON-NLS-1$
392         if (stringHasValue(javaType)) {
393             co.setJavaType(javaType);
394         }
395 
396         String jdbcType = attributes.getProperty("jdbcType"); //$NON-NLS-1$
397         if (stringHasValue(jdbcType)) {
398             co.setJdbcType(jdbcType);
399         }
400 
401         String typeHandler = attributes.getProperty("typeHandler"); //$NON-NLS-1$
402         if (stringHasValue(typeHandler)) {
403             co.setTypeHandler(typeHandler);
404         }
405 
406         String delimitedColumnName = attributes
407                 .getProperty("delimitedColumnName"); //$NON-NLS-1$
408         if (stringHasValue(delimitedColumnName)) {
409             co.setColumnNameDelimited(isTrue(delimitedColumnName));
410         }
411 
412         String isGeneratedAlways = attributes.getProperty("isGeneratedAlways"); //$NON-NLS-1$
413         if (stringHasValue(isGeneratedAlways)) {
414             co.setGeneratedAlways(Boolean.parseBoolean(isGeneratedAlways));
415         }
416 
417         NodeList nodeList = node.getChildNodes();
418         for (int i = 0; i < nodeList.getLength(); i++) {
419             Node childNode = nodeList.item(i);
420 
421             if (childNode.getNodeType() != Node.ELEMENT_NODE) {
422                 continue;
423             }
424 
425             if ("property".equals(childNode.getNodeName())) { //$NON-NLS-1$
426                 parseProperty(co, childNode);
427             }
428         }
429 
430         tc.addColumnOverride(co);
431     }
432 
433     private void parseGeneratedKey(TableConfiguration tc, Node node) {
434         Properties attributes = parseAttributes(node);
435 
436         String column = attributes.getProperty("column"); //$NON-NLS-1$
437         boolean identity = isTrue(attributes
438                 .getProperty("identity")); //$NON-NLS-1$
439         String sqlStatement = attributes.getProperty("sqlStatement"); //$NON-NLS-1$
440         String type = attributes.getProperty("type"); //$NON-NLS-1$
441 
442         GeneratedKey gk = new GeneratedKey(column, sqlStatement, identity, type);
443 
444         tc.setGeneratedKey(gk);
445     }
446 
447     private void parseIgnoreColumn(TableConfiguration tc, Node node) {
448         Properties attributes = parseAttributes(node);
449         String column = attributes.getProperty("column"); //$NON-NLS-1$
450         String delimitedColumnName = attributes
451                 .getProperty("delimitedColumnName"); //$NON-NLS-1$
452 
453         IgnoredColumn ic = new IgnoredColumn(column);
454 
455         if (stringHasValue(delimitedColumnName)) {
456             ic.setColumnNameDelimited(isTrue(delimitedColumnName));
457         }
458 
459         tc.addIgnoredColumn(ic);
460     }
461 
462     private void parseIgnoreColumnByRegex(TableConfiguration tc, Node node) {
463         Properties attributes = parseAttributes(node);
464         String pattern = attributes.getProperty("pattern"); //$NON-NLS-1$
465 
466         IgnoredColumnPattern icPattern = new IgnoredColumnPattern(pattern);
467 
468         NodeList nodeList = node.getChildNodes();
469         for (int i = 0; i < nodeList.getLength(); i++) {
470             Node childNode = nodeList.item(i);
471 
472             if (childNode.getNodeType() != Node.ELEMENT_NODE) {
473                 continue;
474             }
475 
476             if ("except".equals(childNode.getNodeName())) { //$NON-NLS-1$
477                 parseException(icPattern, childNode);
478             }
479         }
480 
481         tc.addIgnoredColumnPattern(icPattern);
482     }
483 
484     private void parseException(IgnoredColumnPattern icPattern, Node node) {
485         Properties attributes = parseAttributes(node);
486         String column = attributes.getProperty("column"); //$NON-NLS-1$
487         String delimitedColumnName = attributes
488                 .getProperty("delimitedColumnName"); //$NON-NLS-1$
489 
490         IgnoredColumnException exception = new IgnoredColumnException(column);
491 
492         if (stringHasValue(delimitedColumnName)) {
493             exception.setColumnNameDelimited(isTrue(delimitedColumnName));
494         }
495 
496         icPattern.addException(exception);
497     }
498 
499     private void parseDomainObjectRenamingRule(TableConfiguration tc, Node node) {
500         Properties attributes = parseAttributes(node);
501         String searchString = attributes.getProperty("searchString"); //$NON-NLS-1$
502         String replaceString = attributes.getProperty("replaceString"); //$NON-NLS-1$
503 
504         DomainObjectRenamingRule dorr = new DomainObjectRenamingRule();
505 
506         dorr.setSearchString(searchString);
507 
508         if (stringHasValue(replaceString)) {
509             dorr.setReplaceString(replaceString);
510         }
511 
512         tc.setDomainObjectRenamingRule(dorr);
513     }
514 
515     private void parseColumnRenamingRule(TableConfiguration tc, Node node) {
516         Properties attributes = parseAttributes(node);
517         String searchString = attributes.getProperty("searchString"); //$NON-NLS-1$
518         String replaceString = attributes.getProperty("replaceString"); //$NON-NLS-1$
519 
520         ColumnRenamingRule crr = new ColumnRenamingRule();
521 
522         crr.setSearchString(searchString);
523 
524         if (stringHasValue(replaceString)) {
525             crr.setReplaceString(replaceString);
526         }
527 
528         tc.setColumnRenamingRule(crr);
529     }
530 
531     protected void parseJavaTypeResolver(Context context, Node node) {
532         JavaTypeResolverConfiguration javaTypeResolverConfiguration = new JavaTypeResolverConfiguration();
533 
534         context.setJavaTypeResolverConfiguration(javaTypeResolverConfiguration);
535 
536         Properties attributes = parseAttributes(node);
537         String type = attributes.getProperty("type"); //$NON-NLS-1$
538 
539         if (stringHasValue(type)) {
540             javaTypeResolverConfiguration.setConfigurationType(type);
541         }
542 
543         NodeList nodeList = node.getChildNodes();
544         for (int i = 0; i < nodeList.getLength(); i++) {
545             Node childNode = nodeList.item(i);
546 
547             if (childNode.getNodeType() != Node.ELEMENT_NODE) {
548                 continue;
549             }
550 
551             if ("property".equals(childNode.getNodeName())) { //$NON-NLS-1$
552                 parseProperty(javaTypeResolverConfiguration, childNode);
553             }
554         }
555     }
556 
557     private void parsePlugin(Context context, Node node) {
558         PluginConfiguration pluginConfiguration = new PluginConfiguration();
559 
560         context.addPluginConfiguration(pluginConfiguration);
561 
562         Properties attributes = parseAttributes(node);
563         String type = attributes.getProperty("type"); //$NON-NLS-1$
564 
565         pluginConfiguration.setConfigurationType(type);
566 
567         NodeList nodeList = node.getChildNodes();
568         for (int i = 0; i < nodeList.getLength(); i++) {
569             Node childNode = nodeList.item(i);
570 
571             if (childNode.getNodeType() != Node.ELEMENT_NODE) {
572                 continue;
573             }
574 
575             if ("property".equals(childNode.getNodeName())) { //$NON-NLS-1$
576                 parseProperty(pluginConfiguration, childNode);
577             }
578         }
579     }
580 
581     protected void parseJavaModelGenerator(Context context, Node node) {
582         JavaModelGeneratorConfiguration javaModelGeneratorConfiguration = new JavaModelGeneratorConfiguration();
583 
584         context
585                 .setJavaModelGeneratorConfiguration(javaModelGeneratorConfiguration);
586 
587         Properties attributes = parseAttributes(node);
588         String targetPackage = attributes.getProperty("targetPackage"); //$NON-NLS-1$
589         String targetProject = attributes.getProperty("targetProject"); //$NON-NLS-1$
590 
591         javaModelGeneratorConfiguration.setTargetPackage(targetPackage);
592         javaModelGeneratorConfiguration.setTargetProject(targetProject);
593 
594         NodeList nodeList = node.getChildNodes();
595         for (int i = 0; i < nodeList.getLength(); i++) {
596             Node childNode = nodeList.item(i);
597 
598             if (childNode.getNodeType() != Node.ELEMENT_NODE) {
599                 continue;
600             }
601 
602             if ("property".equals(childNode.getNodeName())) { //$NON-NLS-1$
603                 parseProperty(javaModelGeneratorConfiguration, childNode);
604             }
605         }
606     }
607 
608     private void parseJavaClientGenerator(Context context, Node node) {
609         JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = new JavaClientGeneratorConfiguration();
610 
611         context.setJavaClientGeneratorConfiguration(javaClientGeneratorConfiguration);
612 
613         Properties attributes = parseAttributes(node);
614         String type = attributes.getProperty("type"); //$NON-NLS-1$
615         String targetPackage = attributes.getProperty("targetPackage"); //$NON-NLS-1$
616         String targetProject = attributes.getProperty("targetProject"); //$NON-NLS-1$
617 
618         javaClientGeneratorConfiguration.setConfigurationType(type);
619         javaClientGeneratorConfiguration.setTargetPackage(targetPackage);
620         javaClientGeneratorConfiguration.setTargetProject(targetProject);
621 
622         NodeList nodeList = node.getChildNodes();
623         for (int i = 0; i < nodeList.getLength(); i++) {
624             Node childNode = nodeList.item(i);
625 
626             if (childNode.getNodeType() != Node.ELEMENT_NODE) {
627                 continue;
628             }
629 
630             if ("property".equals(childNode.getNodeName())) { //$NON-NLS-1$
631                 parseProperty(javaClientGeneratorConfiguration, childNode);
632             }
633         }
634     }
635 
636     protected void parseJdbcConnection(Context context, Node node) {
637         JDBCConnectionConfiguration jdbcConnectionConfiguration = new JDBCConnectionConfiguration();
638 
639         context.setJdbcConnectionConfiguration(jdbcConnectionConfiguration);
640 
641         Properties attributes = parseAttributes(node);
642         String driverClass = attributes.getProperty("driverClass"); //$NON-NLS-1$
643         String connectionURL = attributes.getProperty("connectionURL"); //$NON-NLS-1$
644 
645         jdbcConnectionConfiguration.setDriverClass(driverClass);
646         jdbcConnectionConfiguration.setConnectionURL(connectionURL);
647 
648         String userId = attributes.getProperty("userId"); //$NON-NLS-1$
649         if (stringHasValue(userId)) {
650             jdbcConnectionConfiguration.setUserId(userId);
651         }
652 
653         String password = attributes.getProperty("password"); //$NON-NLS-1$
654         if (stringHasValue(password)) {
655             jdbcConnectionConfiguration.setPassword(password);
656         }
657 
658         NodeList nodeList = node.getChildNodes();
659         for (int i = 0; i < nodeList.getLength(); i++) {
660             Node childNode = nodeList.item(i);
661 
662             if (childNode.getNodeType() != Node.ELEMENT_NODE) {
663                 continue;
664             }
665 
666             if ("property".equals(childNode.getNodeName())) { //$NON-NLS-1$
667                 parseProperty(jdbcConnectionConfiguration, childNode);
668             }
669         }
670     }
671 
672     protected void parseClassPathEntry(Configuration configuration, Node node) {
673         Properties attributes = parseAttributes(node);
674 
675         configuration.addClasspathEntry(attributes.getProperty("location")); //$NON-NLS-1$
676     }
677 
678     protected void parseProperty(PropertyHolder propertyHolder, Node node) {
679         Properties attributes = parseAttributes(node);
680 
681         String name = attributes.getProperty("name"); //$NON-NLS-1$
682         String value = attributes.getProperty("value"); //$NON-NLS-1$
683 
684         propertyHolder.addProperty(name, value);
685     }
686 
687     protected Properties parseAttributes(Node node) {
688         Properties attributes = new Properties();
689         NamedNodeMap nnm = node.getAttributes();
690         for (int i = 0; i < nnm.getLength(); i++) {
691             Node attribute = nnm.item(i);
692             String value = parsePropertyTokens(attribute.getNodeValue());
693             attributes.put(attribute.getNodeName(), value);
694         }
695 
696         return attributes;
697     }
698 
699     String parsePropertyTokens(String s) {
700         final String OPEN = "${"; //$NON-NLS-1$
701         final String CLOSE = "}"; //$NON-NLS-1$
702         int currentIndex = 0;
703 
704         List<String> answer = new ArrayList<>();
705 
706         int markerStartIndex = s.indexOf(OPEN);
707         if (markerStartIndex < 0) {
708             // no parameter markers
709             answer.add(s);
710             currentIndex = s.length();
711         }
712 
713         while (markerStartIndex > -1) {
714             if (markerStartIndex > currentIndex) {
715                 // add the characters before the next parameter marker
716                 answer.add(s.substring(currentIndex, markerStartIndex));
717                 currentIndex = markerStartIndex;
718             }
719 
720             int markerEndIndex = s.indexOf(CLOSE, currentIndex);
721             int nestedStartIndex = s.indexOf(OPEN, markerStartIndex + OPEN.length());
722             while (nestedStartIndex > -1 && markerEndIndex > -1 && nestedStartIndex < markerEndIndex) {
723                 nestedStartIndex = s.indexOf(OPEN, nestedStartIndex + OPEN.length());
724                 markerEndIndex = s.indexOf(CLOSE, markerEndIndex + CLOSE.length());
725             }
726 
727             if (markerEndIndex < 0) {
728                 // no closing delimiter, just move to the end of the string
729                 answer.add(s.substring(markerStartIndex));
730                 currentIndex = s.length();
731                 break;
732             }
733 
734             // we have a valid property marker...
735             String property = s.substring(markerStartIndex + OPEN.length(), markerEndIndex);
736             String propertyValue = resolveProperty(parsePropertyTokens(property));
737             if (propertyValue == null) {
738                 // add the property marker back into the stream
739                 answer.add(s.substring(markerStartIndex, markerEndIndex + 1));
740             } else {
741                 answer.add(propertyValue);
742             }
743 
744             currentIndex = markerEndIndex + CLOSE.length();
745             markerStartIndex = s.indexOf(OPEN, currentIndex);
746         }
747 
748         if (currentIndex < s.length()) {
749             answer.add(s.substring(currentIndex));
750         }
751 
752         return String.join("", answer);
753     }
754 
755     protected void parseCommentGenerator(Context context, Node node) {
756         CommentGeneratorConfiguration commentGeneratorConfiguration = new CommentGeneratorConfiguration();
757 
758         context.setCommentGeneratorConfiguration(commentGeneratorConfiguration);
759 
760         Properties attributes = parseAttributes(node);
761         String type = attributes.getProperty("type"); //$NON-NLS-1$
762 
763         if (stringHasValue(type)) {
764             commentGeneratorConfiguration.setConfigurationType(type);
765         }
766 
767         NodeList nodeList = node.getChildNodes();
768         for (int i = 0; i < nodeList.getLength(); i++) {
769             Node childNode = nodeList.item(i);
770 
771             if (childNode.getNodeType() != Node.ELEMENT_NODE) {
772                 continue;
773             }
774 
775             if ("property".equals(childNode.getNodeName())) { //$NON-NLS-1$
776                 parseProperty(commentGeneratorConfiguration, childNode);
777             }
778         }
779     }
780 
781     protected void parseConnectionFactory(Context context, Node node) {
782         ConnectionFactoryConfiguration connectionFactoryConfiguration = new ConnectionFactoryConfiguration();
783 
784         context.setConnectionFactoryConfiguration(connectionFactoryConfiguration);
785 
786         Properties attributes = parseAttributes(node);
787         String type = attributes.getProperty("type"); //$NON-NLS-1$
788 
789         if (stringHasValue(type)) {
790             connectionFactoryConfiguration.setConfigurationType(type);
791         }
792 
793         NodeList nodeList = node.getChildNodes();
794         for (int i = 0; i < nodeList.getLength(); i++) {
795             Node childNode = nodeList.item(i);
796 
797             if (childNode.getNodeType() != Node.ELEMENT_NODE) {
798                 continue;
799             }
800 
801             if ("property".equals(childNode.getNodeName())) { //$NON-NLS-1$
802                 parseProperty(connectionFactoryConfiguration, childNode);
803             }
804         }
805     }
806 
807     /**
808      * This method resolve a property from one of the three sources: system properties,
809      * properties loaded from the &lt;properties&gt; configuration element, and
810      * "extra" properties that may be supplied by the Maven or Ant environments.
811      *
812      * <p>If there is a name collision, system properties take precedence, followed by
813      * configuration properties, followed by extra properties.
814      *
815      * @param key property key
816      * @return the resolved property.  This method will return null if the property is
817      *     undefined in any of the sources.
818      */
819     private String resolveProperty(String key) {
820         String property = System.getProperty(key);
821 
822         if (property == null) {
823             property = configurationProperties.getProperty(key);
824         }
825 
826         if (property == null) {
827             property = extraProperties.getProperty(key);
828         }
829 
830         return property;
831     }
832 }