/**
* 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;
}
}