/*
* Copyright 2004-2015 the Seasar Foundation and the Others.
*
* 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.seasar.extension.jdbc.gen.internal.generator;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.Locale;
import org.seasar.extension.jdbc.gen.generator.GenerationContext;
import org.seasar.extension.jdbc.gen.generator.Generator;
import org.seasar.extension.jdbc.gen.internal.exception.TemplateRuntimeException;
import org.seasar.extension.jdbc.gen.internal.util.CloseableUtil;
import org.seasar.extension.jdbc.gen.internal.util.DeleteEmptyFileWriter;
import org.seasar.framework.exception.IORuntimeException;
import org.seasar.framework.log.Logger;
import org.seasar.framework.util.FileOutputStreamUtil;
import freemarker.cache.FileTemplateLoader;
import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
/**
* {@link Generator}の実装クラスです。
* <p>
* テンプレートエンジンのFreeMarkerを利用します。
* <p>
*
* @author taedium
*/
public class GeneratorImpl implements Generator {
/** ロガー */
protected static Logger logger = Logger.getLogger(GeneratorImpl.class);
/** デフォルトのテンプレートディレクトリの名前 */
protected static String DEFAULT_TEMPLATE_DIR_NAME = "org/seasar/extension/jdbc/gen/internal/generator/tempaltes";
/** FreeMarkerの設定 */
protected Configuration configuration;
/**
* インスタンスを構築します。
*
* @param configuration
* FreeMarkerの設定
*/
public GeneratorImpl(Configuration configuration) {
if (configuration == null) {
throw new NullPointerException("configuration");
}
this.configuration = configuration;
}
/**
* インスタンスを構築します。
*
* @param templateFileEncoding
* テンプレートファイルのエンコーディング
* @param templateFilePrimaryDir
* テンプレートファイルを格納したプライマリディレクトリ、プライマリディレクトリを使用しない場合{@code null}
*/
public GeneratorImpl(String templateFileEncoding,
File templateFilePrimaryDir) {
if (templateFileEncoding == null) {
throw new NullPointerException("templateFileEncoding");
}
this.configuration = new Configuration();
configuration.setObjectWrapper(new DefaultObjectWrapper());
configuration.setSharedVariable("include", new IncludeDirective());
configuration.setSharedVariable("currentDate", new OnDemandDateModel());
configuration.setEncoding(Locale.getDefault(), templateFileEncoding);
configuration.setNumberFormat("0.#####");
configuration
.setTemplateLoader(createTemplateLoader(templateFilePrimaryDir));
}
/**
* {@link TemplateLoader}を作成します。
*
* @param templateFilePrimaryDir
* テンプレートファイルを格納したプライマリディレクトリ、プライマリディレクトリを使用しない場合{@code null}
* @return {@link TemplateLoader}
*/
protected TemplateLoader createTemplateLoader(File templateFilePrimaryDir) {
TemplateLoader primary = null;
if (templateFilePrimaryDir != null) {
try {
primary = new FileTemplateLoader(templateFilePrimaryDir);
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
TemplateLoader secondary = new ResourceTemplateLoader(
DEFAULT_TEMPLATE_DIR_NAME);
if (primary == null) {
return secondary;
}
return new MultiTemplateLoader(new TemplateLoader[] { primary,
secondary });
}
public void generate(GenerationContext context) {
boolean exists = exists(context.getFile());
if (!context.isOverwrite() && exists) {
return;
}
File dir = context.getFile().getParentFile();
if (dir != null) {
mkdirs(dir);
}
Writer writer = openWriter(context);
try {
Template template = getTemplate(context.getTemplateName());
process(template, context.getModel(), writer);
} finally {
CloseableUtil.close(writer);
}
if (writer instanceof DeleteEmptyFileWriter) {
if (((DeleteEmptyFileWriter) writer).isDeleted()) {
return;
}
}
if (exists) {
logger.log("DS2JDBCGen0009", new Object[] { context.getFile()
.getPath() });
} else {
logger.log("DS2JDBCGen0002", new Object[] { context.getFile()
.getPath() });
}
}
/**
* {@code file}が存在する場合に{@code true}を返します。
*
* @param file
* ファイル
* @return {@code file}が存在する場合は{@code true}、そうでない場合は{@code false}
*/
protected boolean exists(File file) {
return file.exists();
}
/**
* ディレクトリを生成します。
*
* @param dir
* ディレクトリ
*/
protected void mkdirs(File dir) {
dir.mkdirs();
}
/**
* {@link Writer}を開きます。
*
* @param context
* コンテキスト
* @return {@link Writer}
*/
protected Writer openWriter(GenerationContext context) {
Charset charset = Charset.forName(context.getEncoding());
FileOutputStream fos = FileOutputStreamUtil.create(context.getFile());
OutputStreamWriter osw = new OutputStreamWriter(fos, charset);
BufferedWriter bw = new BufferedWriter(osw);
return new DeleteEmptyFileWriter(bw, context.getFile());
}
/**
* テンプレートを取得します。
*
* @param name
* テンプレートの名前
* @return テンプレート
*/
protected Template getTemplate(String name) {
try {
return configuration.getTemplate(name);
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
/**
* テンプレートを処理します。
*
* @param template
* テンプレート
* @param dataModel
* データモデル
* @param writer
* ライタ
*/
protected void process(Template template, Object dataModel, Writer writer) {
try {
template.process(dataModel, writer);
} catch (IOException e) {
throw new IORuntimeException(e);
} catch (TemplateException e) {
throw new TemplateRuntimeException(e);
}
}
}