/*
* Copyright 2004-2012 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.mayaa.impl.standalone;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import org.seasar.mayaa.impl.util.IOUtil;
import org.seasar.mayaa.impl.util.IteratorUtil;
/**
* コンテキストルートからレンダリング対象のファイルを探し、レンダリングした結果を
* ファイルに書き出します。
* コンテキストパスはROOTの扱い(空文字列)になります。
*
* 必要な情報はbasePathとoutputPathです。
* basePathはWebアプリケーションでいうところのコンテキストルートで、レンダリング
* するファイルを探すルートフォルダです。
* 存在しない場合はIllegalArgumentExceptionが発生します。
* outputPathはレンダリング結果を出力する先のフォルダ名です。
* 存在しない場合は自動的に作成します。
*
* また、AutoPageBuilderと同様の形式でファイル名フィルタを指定できます。
* フィルタを指定しない場合は".html"の拡張子を持つファイルが対象になります。
* フィルタの指定方法は2パターンあり、セミコロン(";")で区切ることで複数指定できます。
* <ol>
* <li>"."で始まる英数字のみの文字列の場合は拡張子とみなし、一致するものを対象とします。
* (大文字小文字を区別しない)</li>
* <li>1以外の場合は正規表現とみなし、絶対パスがマッチするものを対象とします。</li>
* </ol>
*
* オプション一覧
* <dl>
* <dt>-v, --version</dt>
* <dd>バージョン番号を表示します。</dd>
* <dt>-h, --help</dt>
* <dd>ヘルプを表示します。</dd>
* <dt>-b, --base <コンテキストルートのパス名></dt>
* <dd>コンテキストルートにあたるbasePathを指定します。<strong>必須</strong>。</dd>
* <dt>-o, --output <出力先フォルダ名></dt>
* <dd>生成したファイルを出力する先outputPathを指定します。<strong>必須</strong>。</dd>
* <dt>-f, --filters <ファイル名フィルタ></dt>
* <dd>ファイル名フィルタを指定します。デフォルトは".html"。</dd>
* <dt>-a, --attributes <属性名と値のセット></dt>
* <dd>"name=value;name=value"の形で属性を指定します。applicationスコープの属性になります。</dd>
* <dt>-p, --property <ファイル名></dt>
* <dd>--attributesの代わりにプロパティファイルを使ってapplicationスコープの属性を指定します。</dd>
* </dl>
*
* @author Koji Suga (Gluegent Inc.)
*/
public class FileGenerator {
public static boolean generating = false;
/**
* メインメソッド。
*
* @param args コマンドライン引数
*/
public static void main(String[] args) {
generating = true;
Argument argument;
try {
argument = parse(args);
validate(argument);
} catch (IllegalArgumentException e) {
System.err.println(e.getMessage());
System.out.println();
printHelp();
return;
}
if (argument.isVersion()) {
printVersion();
return;
}
if (argument.isHelp()) {
printHelp();
return;
}
FileSearchRenderer renderer = new FileSearchRenderer();
renderer.init(
argument.getBasePath(),
argument.getOutputPath(),
argument.getFilters());
renderer.addAttributes(extractAttributes(argument));
renderer.start();
renderer.destroy();
}
/**
* コマンドライン引数をパースして返します。
*
* @param args コマンドライン引数
* @return コマンドライン引数オブジェクト
* @throws IllegalArgumentException 引数が不足している場合
*/
public static Argument parse(String[] args) {
Argument argument = new Argument();
Iterator it = IteratorUtil.toIterator(args);
while (it.hasNext()) {
String arg = (String) it.next();
if (arg.equals("-v") || arg.equals("--version")) {
argument.setVersion(true);
} else if (arg.equals("-h") || arg.equals("--help")) {
argument.setHelp(true);
} else if (arg.equals("-b") || arg.equals("--base")) {
if (it.hasNext() == false) {
throw new IllegalArgumentException("lack of argument \"base path\".");
}
argument.setBasePath((String) it.next());
} else if (arg.equals("-o") || arg.equals("--output")) {
if (it.hasNext() == false) {
throw new IllegalArgumentException("lack of argument \"output path\".");
}
argument.setOutputPath((String) it.next());
} else if (arg.equals("-f") || arg.equals("--filters")) {
if (it.hasNext() == false) {
throw new IllegalArgumentException("lack of argument \"filters\".");
}
argument.setFilters((String) it.next());
} else if (arg.equals("-a") || arg.equals("--attributes")) {
if (it.hasNext() == false) {
throw new IllegalArgumentException("lack of argument \"attributes\".");
}
argument.setAttributes((String) it.next());
} else if (arg.equals("-p") || arg.equals("--property")) {
if (it.hasNext() == false) {
throw new IllegalArgumentException("lack of argument \"property file path\".");
}
argument.setPropertyFilePath((String) it.next());
}
}
return argument;
}
/**
* 引数の妥当性を検証します。
*
* <ul>
* <li>basePathが指定されていること</li>
* <li>basePathのディレクトリが存在すること</li>
* <li>outputPathが指定されていること</li>
* <li>propertyが指定されているならファイルが存在すること</li>
* </ul>
*
* @param argument
*/
public static void validate(Argument argument) {
if (argument.isHelp() || argument.isVersion()) {
return;
}
if (argument.getBasePath() == null) {
throw new IllegalArgumentException(
"Please set base path (-b, --base).");
}
if (argument.getOutputPath() == null) {
throw new IllegalArgumentException(
"Please set output path (-o, --output).");
}
File base = new File(argument.getBasePath());
if (base.exists() == false) {
throw new IllegalArgumentException(
"base path \"" + base.getPath() + "\" is not exists.");
} else if (base.isDirectory() == false) {
throw new IllegalArgumentException(
"base path \"" + base.getPath() + "\" is not directory.");
}
if (argument.getPropertyFilePath() != null) {
File prop = new File(argument.getPropertyFilePath());
if (prop.exists() == false) {
throw new IllegalArgumentException(
"property file \"" + prop.getPath() + "\" is not exists.");
} else if (prop.isFile() == false) {
throw new IllegalArgumentException(
"property file \"" + prop.getPath() + "\" is not file.");
} else if (prop.canRead() == false) {
throw new IllegalArgumentException(
"property file \"" + prop.getPath() + "\" cannot read.");
}
}
}
/**
* --attributesと--propertyから属性情報を抽出してMapにして返します。
* ひとつもない場合はnullを返します。
* --attributesと--propertyとで同一名の属性を定義した場合、--attributes側が
* 優先されます。
*
* @param argument コマンドライン引数
* @return 属性のMapまたはnull
*/
public static Map extractAttributes(Argument argument) {
Map result = null;
if (argument.getAttributes() != null) {
result = new HashMap(10);
// name=value;name=value の形
String[] attributes = argument.getAttributes().split(";");
for (int i = 0; i < attributes.length; i++) {
String att = attributes[i];
int eqIndex = att.indexOf('=');
if (eqIndex > 0) {
result.put(
att.substring(0, eqIndex).trim(),
att.substring(eqIndex + 1).trim());
}
}
}
if (argument.getPropertyFilePath() != null) {
if (result == null) {
result = new HashMap(10);
}
// propertiesファイルから読み出す
FileInputStream is = null;
try {
is = new FileInputStream(argument.getPropertyFilePath());
Properties prop = new Properties();
prop.load(is);
for (Iterator keys = prop.keySet().iterator(); keys.hasNext();) {
String key = (String) keys.next();
if (result.containsKey(key) == false) {
result.put(key, prop.getProperty(key).trim());
}
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
IOUtil.close(is);
}
}
return result;
}
/**
* バージョン情報を表示します。
* jarのMANIFEST.MFにImplementation-Version属性があることを前提としています。
*/
protected static void printVersion() {
Package packageInfo = FileGenerator.class.getPackage();
System.out.print("Mayaa version: ");
if (packageInfo != null) {
System.out.println(packageInfo.getImplementationVersion());
} else {
System.out.println("undefined");
}
}
/**
* コマンドラインヘルプを表示します。
*/
protected static void printHelp() {
printVersion();
System.out.println("Usage: java -cp <CLASSPATH> org.seasar.mayaa.impl.standalone.FileGenerator <-options>");
System.out.println(" options:");
System.out.println(" -v, --version: show version no.");
System.out.println(" -h, --help : show this help message.");
System.out.println(" * -b, --base <base-path>");
System.out.println(" : set context root path.(required)");
System.out.println(" * -o, --output <output-path>");
System.out.println(" : set output root path.(required)");
System.out.println(" -f, --filters <filter-strings>");
System.out.println(" : set filters. (ex: \".html;.*foobar.*\")");
System.out.println(" -a, --attributes <attributes>");
System.out.println(" : set attributes of application scope.");
System.out.println(" (ex: \"name1=value1;name2=value2\"");
System.out.println(" -p, --property <property-file-path>");
System.out.println(" : set properties to attributes of application scope.");
System.out.println();
}
/**
* コマンドライン引数を扱いやすくするためのオブジェクト。
*
* @author Koji Suga (Gluegent Inc.)
*/
protected static class Argument {
private boolean _version = false;
private boolean _help = false;
private String _basePath;
private String _outputPath;
private String _filters;
private String _attributes;
private String _propertyFilePath;
/**
* @return the attributes
*/
public String getAttributes() {
return _attributes;
}
/**
* @param attributes the attributes to set
*/
public void setAttributes(String attributes) {
_attributes = attributes;
}
/**
* @return the basePath
*/
public String getBasePath() {
return _basePath;
}
/**
* @param basePath the basePath to set
*/
public void setBasePath(String basePath) {
_basePath = basePath;
}
/**
* @return the filters
*/
public String getFilters() {
return _filters;
}
/**
* @param filters the filters to set
*/
public void setFilters(String filters) {
_filters = filters;
}
/**
* @return the help
*/
public boolean isHelp() {
return _help;
}
/**
* @param help the help to set
*/
public void setHelp(boolean help) {
_help = help;
}
/**
* @return the outputPath
*/
public String getOutputPath() {
return _outputPath;
}
/**
* @param outputPath the outputPath to set
*/
public void setOutputPath(String outputPath) {
_outputPath = outputPath;
}
/**
* @return the propertyFilePath
*/
public String getPropertyFilePath() {
return _propertyFilePath;
}
/**
* @param propertyFilePath the propertyFilePath to set
*/
public void setPropertyFilePath(String propertyFilePath) {
_propertyFilePath = propertyFilePath;
}
/**
* @return the version
*/
public boolean isVersion() {
return _version;
}
/**
* @param version the version to set
*/
public void setVersion(boolean version) {
_version = version;
}
}
}