/** * Copyright 2006-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mybatis.generator.config; import static org.mybatis.generator.internal.util.StringUtility.composeFullyQualifiedTableName; import static org.mybatis.generator.internal.util.StringUtility.isTrue; import static org.mybatis.generator.internal.util.StringUtility.stringHasValue; import static org.mybatis.generator.internal.util.messages.Messages.getString; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.mybatis.generator.api.CommentGenerator; import org.mybatis.generator.api.ConnectionFactory; import org.mybatis.generator.api.GeneratedJavaFile; import org.mybatis.generator.api.GeneratedXmlFile; import org.mybatis.generator.api.JavaFormatter; import org.mybatis.generator.api.Plugin; import org.mybatis.generator.api.IntrospectedTable; import org.mybatis.generator.api.JavaTypeResolver; import org.mybatis.generator.api.ProgressCallback; import org.mybatis.generator.api.XmlFormatter; import org.mybatis.generator.api.dom.xml.Attribute; import org.mybatis.generator.api.dom.xml.XmlElement; import org.mybatis.generator.internal.JDBCConnectionFactory; import org.mybatis.generator.internal.ObjectFactory; import org.mybatis.generator.internal.PluginAggregator; import org.mybatis.generator.internal.db.DatabaseIntrospector; /** * The Class Context. * * @author Jeff Butler */ public class Context extends PropertyHolder { /** The id. */ private String id; /** The jdbc connection configuration. */ private JDBCConnectionConfiguration jdbcConnectionConfiguration; private ConnectionFactoryConfiguration connectionFactoryConfiguration; /** The sql map generator configuration. */ private SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration; /** The java type resolver configuration. */ private JavaTypeResolverConfiguration javaTypeResolverConfiguration; /** The java model generator configuration. */ private JavaModelGeneratorConfiguration javaModelGeneratorConfiguration; /** The java client generator configuration. */ private JavaClientGeneratorConfiguration javaClientGeneratorConfiguration; /** The table configurations. */ private ArrayList<TableConfiguration> tableConfigurations; /** The default model type. */ private ModelType defaultModelType; /** The beginning delimiter. */ private String beginningDelimiter = "\""; //$NON-NLS-1$ /** The ending delimiter. */ private String endingDelimiter = "\""; //$NON-NLS-1$ /** The comment generator configuration. */ private CommentGeneratorConfiguration commentGeneratorConfiguration; /** The comment generator. */ private CommentGenerator commentGenerator; /** The plugin aggregator. */ private PluginAggregator pluginAggregator; /** The plugin configurations. */ private List<PluginConfiguration> pluginConfigurations; /** The target runtime. */ private String targetRuntime; /** The introspected column impl. */ private String introspectedColumnImpl; /** The auto delimit keywords. */ private Boolean autoDelimitKeywords; /** The java formatter. */ private JavaFormatter javaFormatter; /** The xml formatter. */ private XmlFormatter xmlFormatter; /** * Constructs a Context object. * * @param defaultModelType * - may be null */ public Context(ModelType defaultModelType) { super(); if (defaultModelType == null) { this.defaultModelType = ModelType.CONDITIONAL; } else { this.defaultModelType = defaultModelType; } tableConfigurations = new ArrayList<TableConfiguration>(); pluginConfigurations = new ArrayList<PluginConfiguration>(); } /** * Adds the table configuration. * * @param tc * the tc */ public void addTableConfiguration(TableConfiguration tc) { tableConfigurations.add(tc); } /** * Gets the jdbc connection configuration. * * @return the jdbc connection configuration */ public JDBCConnectionConfiguration getJdbcConnectionConfiguration() { return jdbcConnectionConfiguration; } /** * Gets the java client generator configuration. * * @return the java client generator configuration */ public JavaClientGeneratorConfiguration getJavaClientGeneratorConfiguration() { return javaClientGeneratorConfiguration; } /** * Gets the java model generator configuration. * * @return the java model generator configuration */ public JavaModelGeneratorConfiguration getJavaModelGeneratorConfiguration() { return javaModelGeneratorConfiguration; } /** * Gets the java type resolver configuration. * * @return the java type resolver configuration */ public JavaTypeResolverConfiguration getJavaTypeResolverConfiguration() { return javaTypeResolverConfiguration; } /** * Gets the sql map generator configuration. * * @return the sql map generator configuration */ public SqlMapGeneratorConfiguration getSqlMapGeneratorConfiguration() { return sqlMapGeneratorConfiguration; } /** * Adds the plugin configuration. * * @param pluginConfiguration * the plugin configuration */ public void addPluginConfiguration( PluginConfiguration pluginConfiguration) { pluginConfigurations.add(pluginConfiguration); } /** * This method does a simple validate, it makes sure that all required fields have been filled in. It does not do * any more complex operations such as validating that database tables exist or validating that named columns exist * * @param errors * the errors */ public void validate(List<String> errors) { if (!stringHasValue(id)) { errors.add(getString("ValidationError.16")); //$NON-NLS-1$ } if (jdbcConnectionConfiguration == null && connectionFactoryConfiguration == null) { // must specify one errors.add(getString("ValidationError.10", id)); //$NON-NLS-1$ } else if (jdbcConnectionConfiguration != null && connectionFactoryConfiguration != null) { // must not specify both errors.add(getString("ValidationError.10", id)); //$NON-NLS-1$ } else if (jdbcConnectionConfiguration != null) { jdbcConnectionConfiguration.validate(errors); } else { connectionFactoryConfiguration.validate(errors); } if (javaModelGeneratorConfiguration == null) { errors.add(getString("ValidationError.8", id)); //$NON-NLS-1$ } else { javaModelGeneratorConfiguration.validate(errors, id); } if (javaClientGeneratorConfiguration != null) { javaClientGeneratorConfiguration.validate(errors, id); } IntrospectedTable it = null; try { it = ObjectFactory.createIntrospectedTableForValidation(this); } catch (Exception e) { errors.add(getString("ValidationError.25", id)); //$NON-NLS-1$ } if (it != null && it.requiresXMLGenerator()) { if (sqlMapGeneratorConfiguration == null) { errors.add(getString("ValidationError.9", id)); //$NON-NLS-1$ } else { sqlMapGeneratorConfiguration.validate(errors, id); } } if (tableConfigurations.size() == 0) { errors.add(getString("ValidationError.3", id)); //$NON-NLS-1$ } else { for (int i = 0; i < tableConfigurations.size(); i++) { TableConfiguration tc = tableConfigurations.get(i); tc.validate(errors, i); } } for (PluginConfiguration pluginConfiguration : pluginConfigurations) { pluginConfiguration.validate(errors, id); } } /** * Gets the id. * * @return the id */ public String getId() { return id; } /** * Sets the id. * * @param id * the new id */ public void setId(String id) { this.id = id; } /** * Sets the java client generator configuration. * * @param javaClientGeneratorConfiguration * the new java client generator configuration */ public void setJavaClientGeneratorConfiguration( JavaClientGeneratorConfiguration javaClientGeneratorConfiguration) { this.javaClientGeneratorConfiguration = javaClientGeneratorConfiguration; } /** * Sets the java model generator configuration. * * @param javaModelGeneratorConfiguration * the new java model generator configuration */ public void setJavaModelGeneratorConfiguration( JavaModelGeneratorConfiguration javaModelGeneratorConfiguration) { this.javaModelGeneratorConfiguration = javaModelGeneratorConfiguration; } /** * Sets the java type resolver configuration. * * @param javaTypeResolverConfiguration * the new java type resolver configuration */ public void setJavaTypeResolverConfiguration( JavaTypeResolverConfiguration javaTypeResolverConfiguration) { this.javaTypeResolverConfiguration = javaTypeResolverConfiguration; } /** * Sets the jdbc connection configuration. * * @param jdbcConnectionConfiguration * the new jdbc connection configuration */ public void setJdbcConnectionConfiguration( JDBCConnectionConfiguration jdbcConnectionConfiguration) { this.jdbcConnectionConfiguration = jdbcConnectionConfiguration; } /** * Sets the sql map generator configuration. * * @param sqlMapGeneratorConfiguration * the new sql map generator configuration */ public void setSqlMapGeneratorConfiguration( SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration) { this.sqlMapGeneratorConfiguration = sqlMapGeneratorConfiguration; } /** * Gets the default model type. * * @return the default model type */ public ModelType getDefaultModelType() { return defaultModelType; } /** * Builds an XmlElement representation of this context. Note that the XML * may not necessarily validate if the context is invalid. Call the * <code>validate</code> method to check validity of this context. * * @return the XML representation of this context */ public XmlElement toXmlElement() { XmlElement xmlElement = new XmlElement("context"); //$NON-NLS-1$ xmlElement.addAttribute(new Attribute("id", id)); //$NON-NLS-1$ if (defaultModelType != ModelType.CONDITIONAL) { xmlElement.addAttribute(new Attribute( "defaultModelType", defaultModelType.getModelType())); //$NON-NLS-1$ } if (stringHasValue(introspectedColumnImpl)) { xmlElement.addAttribute(new Attribute( "introspectedColumnImpl", introspectedColumnImpl)); //$NON-NLS-1$ } if (stringHasValue(targetRuntime)) { xmlElement.addAttribute(new Attribute( "targetRuntime", targetRuntime)); //$NON-NLS-1$ } addPropertyXmlElements(xmlElement); for (PluginConfiguration pluginConfiguration : pluginConfigurations) { xmlElement.addElement(pluginConfiguration.toXmlElement()); } if (commentGeneratorConfiguration != null) { xmlElement.addElement(commentGeneratorConfiguration.toXmlElement()); } if (jdbcConnectionConfiguration != null) { xmlElement.addElement(jdbcConnectionConfiguration.toXmlElement()); } if (connectionFactoryConfiguration != null) { xmlElement.addElement(connectionFactoryConfiguration.toXmlElement()); } if (javaTypeResolverConfiguration != null) { xmlElement.addElement(javaTypeResolverConfiguration.toXmlElement()); } if (javaModelGeneratorConfiguration != null) { xmlElement.addElement(javaModelGeneratorConfiguration .toXmlElement()); } if (sqlMapGeneratorConfiguration != null) { xmlElement.addElement(sqlMapGeneratorConfiguration.toXmlElement()); } if (javaClientGeneratorConfiguration != null) { xmlElement.addElement(javaClientGeneratorConfiguration.toXmlElement()); } for (TableConfiguration tableConfiguration : tableConfigurations) { xmlElement.addElement(tableConfiguration.toXmlElement()); } return xmlElement; } /** * Gets the table configurations. * * @return the table configurations */ public List<TableConfiguration> getTableConfigurations() { return tableConfigurations; } /** * Gets the beginning delimiter. * * @return the beginning delimiter */ public String getBeginningDelimiter() { return beginningDelimiter; } /** * Gets the ending delimiter. * * @return the ending delimiter */ public String getEndingDelimiter() { return endingDelimiter; } /* (non-Javadoc) * @see org.mybatis.generator.config.PropertyHolder#addProperty(java.lang.String, java.lang.String) */ @Override public void addProperty(String name, String value) { super.addProperty(name, value); if (PropertyRegistry.CONTEXT_BEGINNING_DELIMITER.equals(name)) { beginningDelimiter = value; } else if (PropertyRegistry.CONTEXT_ENDING_DELIMITER.equals(name)) { endingDelimiter = value; } else if (PropertyRegistry.CONTEXT_AUTO_DELIMIT_KEYWORDS.equals(name) && stringHasValue(value)) { autoDelimitKeywords = isTrue(value); } } /** * Gets the comment generator. * * @return the comment generator */ public CommentGenerator getCommentGenerator() { if (commentGenerator == null) { commentGenerator = ObjectFactory.createCommentGenerator(this); } return commentGenerator; } /** * Gets the java formatter. * * @return the java formatter */ public JavaFormatter getJavaFormatter() { if (javaFormatter == null) { javaFormatter = ObjectFactory.createJavaFormatter(this); } return javaFormatter; } /** * Gets the xml formatter. * * @return the xml formatter */ public XmlFormatter getXmlFormatter() { if (xmlFormatter == null) { xmlFormatter = ObjectFactory.createXmlFormatter(this); } return xmlFormatter; } /** * Gets the comment generator configuration. * * @return the comment generator configuration */ public CommentGeneratorConfiguration getCommentGeneratorConfiguration() { return commentGeneratorConfiguration; } /** * Sets the comment generator configuration. * * @param commentGeneratorConfiguration * the new comment generator configuration */ public void setCommentGeneratorConfiguration( CommentGeneratorConfiguration commentGeneratorConfiguration) { this.commentGeneratorConfiguration = commentGeneratorConfiguration; } /** * Gets the plugins. * * @return the plugins */ public Plugin getPlugins() { return pluginAggregator; } /** * Gets the target runtime. * * @return the target runtime */ public String getTargetRuntime() { return targetRuntime; } /** * Sets the target runtime. * * @param targetRuntime * the new target runtime */ public void setTargetRuntime(String targetRuntime) { this.targetRuntime = targetRuntime; } /** * Gets the introspected column impl. * * @return the introspected column impl */ public String getIntrospectedColumnImpl() { return introspectedColumnImpl; } /** * Sets the introspected column impl. * * @param introspectedColumnImpl * the new introspected column impl */ public void setIntrospectedColumnImpl(String introspectedColumnImpl) { this.introspectedColumnImpl = introspectedColumnImpl; } // methods related to code generation. // // Methods should be called in this order: // // 1. getIntrospectionSteps() // 2. introspectTables() // 3. getGenerationSteps() // 4. generateFiles() // /** The introspected tables. */ private List<IntrospectedTable> introspectedTables; /** * Gets the introspection steps. * * @return the introspection steps */ public int getIntrospectionSteps() { int steps = 0; steps++; // connect to database // for each table: // // 1. Create introspected table implementation steps += tableConfigurations.size() * 1; return steps; } /** * Introspect tables based on the configuration specified in the * constructor. This method is long running. * * @param callback * a progress callback if progress information is desired, or * <code>null</code> * @param warnings * any warning generated from this method will be added to the * List. Warnings are always Strings. * @param fullyQualifiedTableNames * a set of table names to generate. The elements of the set must * be Strings that exactly match what's specified in the * configuration. For example, if table name = "foo" and schema = * "bar", then the fully qualified table name is "foo.bar". If * the Set is null or empty, then all tables in the configuration * will be used for code generation. * * @throws SQLException * if some error arises while introspecting the specified * database tables. * @throws InterruptedException * if the progress callback reports a cancel */ public void introspectTables(ProgressCallback callback, List<String> warnings, Set<String> fullyQualifiedTableNames) throws SQLException, InterruptedException { introspectedTables = new ArrayList<IntrospectedTable>(); JavaTypeResolver javaTypeResolver = ObjectFactory .createJavaTypeResolver(this, warnings); Connection connection = null; try { callback.startTask(getString("Progress.0")); //$NON-NLS-1$ connection = getConnection(); DatabaseIntrospector databaseIntrospector = new DatabaseIntrospector( this, connection.getMetaData(), javaTypeResolver, warnings); for (TableConfiguration tc : tableConfigurations) { String tableName = composeFullyQualifiedTableName(tc.getCatalog(), tc .getSchema(), tc.getTableName(), '.'); if (fullyQualifiedTableNames != null && fullyQualifiedTableNames.size() > 0 && !fullyQualifiedTableNames.contains(tableName)) { continue; } if (!tc.areAnyStatementsEnabled()) { warnings.add(getString("Warning.0", tableName)); //$NON-NLS-1$ continue; } callback.startTask(getString("Progress.1", tableName)); //$NON-NLS-1$ List<IntrospectedTable> tables = databaseIntrospector .introspectTables(tc); if (tables != null) { introspectedTables.addAll(tables); } callback.checkCancel(); } } finally { closeConnection(connection); } } /** * Gets the generation steps. * * @return the generation steps */ public int getGenerationSteps() { int steps = 0; if (introspectedTables != null) { for (IntrospectedTable introspectedTable : introspectedTables) { steps += introspectedTable.getGenerationSteps(); } } return steps; } /** * Generate files. * * @param callback * the callback * @param generatedJavaFiles * the generated java files * @param generatedXmlFiles * the generated xml files * @param warnings * the warnings * @throws InterruptedException * the interrupted exception */ public void generateFiles(ProgressCallback callback, List<GeneratedJavaFile> generatedJavaFiles, List<GeneratedXmlFile> generatedXmlFiles, List<String> warnings) throws InterruptedException { pluginAggregator = new PluginAggregator(); for (PluginConfiguration pluginConfiguration : pluginConfigurations) { Plugin plugin = ObjectFactory.createPlugin(this, pluginConfiguration); if (plugin.validate(warnings)) { pluginAggregator.addPlugin(plugin); } else { warnings.add(getString("Warning.24", //$NON-NLS-1$ pluginConfiguration.getConfigurationType(), id)); } } if (introspectedTables != null) { for (IntrospectedTable introspectedTable : introspectedTables) { callback.checkCancel(); introspectedTable.initialize(); introspectedTable.calculateGenerators(warnings, callback); generatedJavaFiles.addAll(introspectedTable .getGeneratedJavaFiles()); generatedXmlFiles.addAll(introspectedTable .getGeneratedXmlFiles()); generatedJavaFiles.addAll(pluginAggregator .contextGenerateAdditionalJavaFiles(introspectedTable)); generatedXmlFiles.addAll(pluginAggregator .contextGenerateAdditionalXmlFiles(introspectedTable)); } } generatedJavaFiles.addAll(pluginAggregator .contextGenerateAdditionalJavaFiles()); generatedXmlFiles.addAll(pluginAggregator .contextGenerateAdditionalXmlFiles()); } /** * Gets the connection. * * @return the connection * @throws SQLException * the SQL exception */ private Connection getConnection() throws SQLException { ConnectionFactory connectionFactory; if (jdbcConnectionConfiguration != null) { connectionFactory = new JDBCConnectionFactory(jdbcConnectionConfiguration); } else { connectionFactory = ObjectFactory.createConnectionFactory(this); } return connectionFactory.getConnection(); } /** * Close connection. * * @param connection * the connection */ private void closeConnection(Connection connection) { if (connection != null) { try { connection.close(); } catch (SQLException e) { // ignore } } } /** * Auto delimit keywords. * * @return true, if successful */ public boolean autoDelimitKeywords() { return autoDelimitKeywords != null && autoDelimitKeywords.booleanValue(); } public ConnectionFactoryConfiguration getConnectionFactoryConfiguration() { return connectionFactoryConfiguration; } public void setConnectionFactoryConfiguration(ConnectionFactoryConfiguration connectionFactoryConfiguration) { this.connectionFactoryConfiguration = connectionFactoryConfiguration; } }