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.api;
17  
18  import static org.mybatis.generator.internal.util.StringUtility.composeFullyQualifiedTableName;
19  import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;
20  
21  import java.util.Objects;
22  import java.util.regex.Matcher;
23  import java.util.regex.Pattern;
24  
25  import org.mybatis.generator.config.Context;
26  import org.mybatis.generator.config.DomainObjectRenamingRule;
27  import org.mybatis.generator.internal.util.JavaBeansUtil;
28  
29  public class FullyQualifiedTable {
30  
31      private final String introspectedCatalog;
32      private final String introspectedSchema;
33      private final String introspectedTableName;
34      private final String runtimeCatalog;
35      private final String runtimeSchema;
36      private final String runtimeTableName;
37      private String domainObjectName;
38      private String domainObjectSubPackage;
39      private final String alias;
40      private final boolean ignoreQualifiersAtRuntime;
41      private final String beginningDelimiter;
42      private final String endingDelimiter;
43      private final DomainObjectRenamingRule domainObjectRenamingRule;
44  
45      /**
46       * This object is used to hold information related to the table itself, not the columns in the
47       * table.
48       *
49       * @param introspectedCatalog
50       *            the actual catalog of the table as returned from DatabaseMetaData. This value
51       *            should only be set if the user configured a catalog. Otherwise the
52       *            DatabaseMetaData is reporting some database default that we don't want in the
53       *            generated code.
54       * @param introspectedSchema
55       *            the actual schema of the table as returned from DatabaseMetaData. This value
56       *            should only be set if the user configured a schema. Otherwise the
57       *            DatabaseMetaData is reporting some database default that we don't want in the
58       *            generated code.
59       * @param introspectedTableName
60       *            the actual table name as returned from DatabaseMetaData
61       * @param domainObjectName
62       *            the configured domain object name for this table. If nothing is configured, we'll build the domain
63       *            object named based on the tableName or runtimeTableName.
64       * @param alias
65       *            a configured alias for the table. This alias will be added to the table name in the SQL
66       * @param ignoreQualifiersAtRuntime
67       *            if true, then the catalog and schema qualifiers will be ignored when composing fully qualified names
68       *            in the generated SQL. This is used, for example, when the user needs to specify a specific schema for
69       *            generating code but does not want the schema in the generated SQL
70       * @param runtimeCatalog
71       *            this is used to "rename" the catalog in the generated SQL. This is useful, for example, when
72       *            generating code against one catalog that should run with a different catalog.
73       * @param runtimeSchema
74       *            this is used to "rename" the schema in the generated SQL. This is useful, for example, when generating
75       *            code against one schema that should run with a different schema.
76       * @param runtimeTableName
77       *            this is used to "rename" the table in the generated SQL. This is useful, for example, when generating
78       *            code to run with an Oracle synonym. The user would have to specify the actual table name and schema
79       *            for generation, but would want to use the synonym name in the generated SQL
80       * @param delimitIdentifiers
81       *            if true, then the table identifiers will be delimited at runtime. The delimiter characters are
82       *            obtained from the Context.
83       * @param domainObjectRenamingRule
84       *            If domainObjectName is not configured, we'll build the domain object named based on the tableName
85       *            or runtimeTableName.
86       *            And then we use the domain object renaming rule to generate the final domain object name.
87       * @param context
88       *            the context
89       */
90      public FullyQualifiedTable(String introspectedCatalog,
91              String introspectedSchema, String introspectedTableName,
92              String domainObjectName, String alias,
93              boolean ignoreQualifiersAtRuntime, String runtimeCatalog,
94              String runtimeSchema, String runtimeTableName,
95              boolean delimitIdentifiers, DomainObjectRenamingRule domainObjectRenamingRule,
96              Context context) {
97          super();
98          this.introspectedCatalog = introspectedCatalog;
99          this.introspectedSchema = introspectedSchema;
100         this.introspectedTableName = introspectedTableName;
101         this.ignoreQualifiersAtRuntime = ignoreQualifiersAtRuntime;
102         this.runtimeCatalog = runtimeCatalog;
103         this.runtimeSchema = runtimeSchema;
104         this.runtimeTableName = runtimeTableName;
105         this.domainObjectRenamingRule = domainObjectRenamingRule;
106 
107         if (stringHasValue(domainObjectName)) {
108             int index = domainObjectName.lastIndexOf('.');
109             if (index == -1) {
110                 this.domainObjectName = domainObjectName;
111             } else {
112                 this.domainObjectName = domainObjectName.substring(index + 1);
113                 this.domainObjectSubPackage = domainObjectName.substring(0, index);
114             }
115         }
116 
117         if (alias == null) {
118             this.alias = null;
119         } else {
120             this.alias = alias.trim();
121         }
122 
123         beginningDelimiter = delimitIdentifiers ? context
124                 .getBeginningDelimiter() : ""; //$NON-NLS-1$
125         endingDelimiter = delimitIdentifiers ? context.getEndingDelimiter()
126                 : ""; //$NON-NLS-1$
127     }
128 
129     public String getIntrospectedCatalog() {
130         return introspectedCatalog;
131     }
132 
133     public String getIntrospectedSchema() {
134         return introspectedSchema;
135     }
136 
137     public String getIntrospectedTableName() {
138         return introspectedTableName;
139     }
140 
141     public String getFullyQualifiedTableNameAtRuntime() {
142         StringBuilder localCatalog = new StringBuilder();
143         if (!ignoreQualifiersAtRuntime) {
144             if (stringHasValue(runtimeCatalog)) {
145                 localCatalog.append(runtimeCatalog);
146             } else if (stringHasValue(introspectedCatalog)) {
147                 localCatalog.append(introspectedCatalog);
148             }
149         }
150         if (localCatalog.length() > 0) {
151             addDelimiters(localCatalog);
152         }
153 
154         StringBuilder localSchema = new StringBuilder();
155         if (!ignoreQualifiersAtRuntime) {
156             if (stringHasValue(runtimeSchema)) {
157                 localSchema.append(runtimeSchema);
158             } else if (stringHasValue(introspectedSchema)) {
159                 localSchema.append(introspectedSchema);
160             }
161         }
162         if (localSchema.length() > 0) {
163             addDelimiters(localSchema);
164         }
165 
166         StringBuilder localTableName = new StringBuilder();
167         if (stringHasValue(runtimeTableName)) {
168             localTableName.append(runtimeTableName);
169         } else {
170             localTableName.append(introspectedTableName);
171         }
172         addDelimiters(localTableName);
173 
174         return composeFullyQualifiedTableName(localCatalog
175                 .toString(), localSchema.toString(), localTableName.toString(),
176                 '.');
177     }
178 
179     public String getAliasedFullyQualifiedTableNameAtRuntime() {
180         StringBuilder sb = new StringBuilder();
181 
182         sb.append(getFullyQualifiedTableNameAtRuntime());
183 
184         if (stringHasValue(alias)) {
185             sb.append(' ');
186             sb.append(alias);
187         }
188 
189         return sb.toString();
190     }
191 
192     public String getDomainObjectName() {
193         if (stringHasValue(domainObjectName)) {
194             return domainObjectName;
195         }
196 
197         String finalDomainObjectName;
198         if (stringHasValue(runtimeTableName)) {
199             finalDomainObjectName = JavaBeansUtil.getCamelCaseString(runtimeTableName, true);
200         } else {
201             finalDomainObjectName = JavaBeansUtil.getCamelCaseString(introspectedTableName, true);
202         }
203 
204         if (domainObjectRenamingRule != null) {
205             Pattern pattern = Pattern.compile(domainObjectRenamingRule.getSearchString());
206             String replaceString = domainObjectRenamingRule.getReplaceString();
207             replaceString = replaceString == null ? "" : replaceString; //$NON-NLS-1$
208             Matcher matcher = pattern.matcher(finalDomainObjectName);
209             finalDomainObjectName = JavaBeansUtil.getFirstCharacterUppercase(matcher.replaceAll(replaceString));
210         }
211         return finalDomainObjectName;
212     }
213 
214     @Override
215     public boolean equals(Object obj) {
216         if (this == obj) {
217             return true;
218         }
219 
220         if (!(obj instanceof FullyQualifiedTable)) {
221             return false;
222         }
223 
224         FullyQualifiedTable other = (FullyQualifiedTable) obj;
225 
226         return Objects.equals(this.introspectedTableName, other.introspectedTableName)
227                 && Objects.equals(this.introspectedCatalog, other.introspectedCatalog)
228                 && Objects.equals(this.introspectedSchema, other.introspectedSchema);
229     }
230 
231     @Override
232     public int hashCode() {
233         return Objects.hash(introspectedTableName, introspectedCatalog, introspectedCatalog);
234     }
235 
236     @Override
237     public String toString() {
238         return composeFullyQualifiedTableName(
239                 introspectedCatalog, introspectedSchema, introspectedTableName,
240                 '.');
241     }
242 
243     public String getAlias() {
244         return alias;
245     }
246 
247     /**
248      * Calculates a Java package fragment based on the table catalog and schema.
249      * If qualifiers are ignored, then this method will return an empty string.
250      *
251      * <p>This method is used for determining the sub package for Java client and
252      * SQL map (XML) objects.  It ignores any sub-package added to the
253      * domain object name in the table configuration.
254      *
255      * @param isSubPackagesEnabled
256      *            the is sub packages enabled
257      * @return the subpackage for this table
258      */
259     public String getSubPackageForClientOrSqlMap(boolean isSubPackagesEnabled) {
260         StringBuilder sb = new StringBuilder();
261         if (!ignoreQualifiersAtRuntime && isSubPackagesEnabled) {
262             if (stringHasValue(runtimeCatalog)) {
263                 sb.append('.');
264                 sb.append(runtimeCatalog.toLowerCase());
265             } else if (stringHasValue(introspectedCatalog)) {
266                 sb.append('.');
267                 sb.append(introspectedCatalog.toLowerCase());
268             }
269 
270             if (stringHasValue(runtimeSchema)) {
271                 sb.append('.');
272                 sb.append(runtimeSchema.toLowerCase());
273             } else if (stringHasValue(introspectedSchema)) {
274                 sb.append('.');
275                 sb.append(introspectedSchema.toLowerCase());
276             }
277         }
278 
279         // TODO - strip characters that are not valid in package names
280         return sb.toString();
281     }
282 
283     /**
284      * Calculates a Java package fragment based on the table catalog and schema.
285      * If qualifiers are ignored, then this method will return an empty string.
286      *
287      * <p>This method is used for determining the sub package for Java model objects only.
288      * It takes into account the possibility that a sub-package was added to the
289      * domain object name in the table configuration.
290      *
291      * @param isSubPackagesEnabled
292      *            the is sub packages enabled
293      * @return the subpackage for this table
294      */
295     public String getSubPackageForModel(boolean isSubPackagesEnabled) {
296         StringBuilder sb = new StringBuilder();
297         sb.append(getSubPackageForClientOrSqlMap(isSubPackagesEnabled));
298 
299         if (stringHasValue(domainObjectSubPackage)) {
300             sb.append('.');
301             sb.append(domainObjectSubPackage);
302         }
303 
304         return sb.toString();
305     }
306 
307     private void addDelimiters(StringBuilder sb) {
308         if (stringHasValue(beginningDelimiter)) {
309             sb.insert(0, beginningDelimiter);
310         }
311 
312         if (stringHasValue(endingDelimiter)) {
313             sb.append(endingDelimiter);
314         }
315     }
316 
317     public String getDomainObjectSubPackage() {
318         return domainObjectSubPackage;
319     }
320 }