/*
* 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.argtype;
import java.util.ArrayList;
import java.util.Collection;
import org.seasar.extension.jdbc.gen.internal.util.ArgumentUtil;
import org.seasar.framework.util.StringUtil;
import static org.seasar.extension.jdbc.gen.internal.argtype.CollectionType.TokenType.*;
/**
* {@link Collection}を扱う{@link ArgumentType}の実装クラスです。
*
* @author taedium
* @param <T>
* コレクションの要素の型
*/
public class CollectionType<T> implements ArgumentType<Collection<? extends T>> {
/** 開き角括弧 */
protected static String OPEN_BRACKET = "[";
/** 閉じ角括弧 */
protected static String CLOSE_BRACKET = "]";
/** コレクションの要素に対応する{@link ArgumentType} */
protected ArgumentType<T> argumentType;
/**
* インスタンスを構築します。
*
* @param argumentType
* 引数の型
*/
public CollectionType(ArgumentType<T> argumentType) {
this.argumentType = argumentType;
}
public Collection<? extends T> toObject(String value) {
if (StringUtil.isEmpty(value)) {
return null;
}
Collection<T> collection = createCollection();
String s = StringUtil.ltrim(value, OPEN_BRACKET);
s = StringUtil.rtrim(s, CLOSE_BRACKET);
Tokenizer tokenizer = new Tokenizer(s);
nextTokenLoop: for (;;) {
switch (tokenizer.nextToken()) {
case QUOTED_VALUE:
case VALUE:
String token = tokenizer.getToken();
collection.add(argumentType.toObject(token));
break;
case END:
break nextTokenLoop;
}
}
return collection;
}
/**
* コレクション型のインスタンスを作成します。
*
* @return コレクション型のインスタンス
*/
protected Collection<T> createCollection() {
return new ArrayList<T>();
}
public String toText(Collection<? extends T> value) {
if (value == null) {
return "";
}
StringBuilder buf = new StringBuilder();
buf.append(OPEN_BRACKET);
for (T o : value) {
buf.append(argumentType.toText(o));
buf.append(",");
}
if (value.size() > 0) {
buf.setLength(buf.length() - 1);
}
buf.append(CLOSE_BRACKET);
return buf.toString();
}
/**
* トークンのタイプです。
*
* @author taedium
*/
protected static enum TokenType {
/** クォートされた値 */
QUOTED_VALUE,
/** クォートされていない値 */
VALUE,
/** 区切り文字 */
DELIMITER,
/** トークンの最後 */
END
}
/**
* リストの引数の値を区切るクラスです。
*
* @author taedium
*/
protected static class Tokenizer {
/** 区切り文字 */
protected char delimiter = ArgumentUtil.DELIMITER_CHAR;
/** 引用句 */
protected char quote = ArgumentUtil.QUOTE_CHAR;
/** 値 */
protected String value;
/** 長さ */
protected int length;
/** 位置 */
protected int pos;
/** 次の位置 */
protected int nextPos;
/** トークン */
protected String token;
/** トークンのタイプ */
protected TokenType type;
/**
* インスタンスを構築します。
*
* @param value
* 値
*/
protected Tokenizer(String value) {
this.value = value;
this.length = value.length();
peek(0);
}
/**
* 次のトークンを前もって調べます。
*
* @param index
* インデックス
*/
protected void peek(int index) {
if (index < length) {
char c = value.charAt(index);
if (c == delimiter) {
type = DELIMITER;
pos = index;
nextPos = index + 1;
} else if (c == quote) {
type = QUOTED_VALUE;
pos = index;
nextPos = index + 1;
} else {
type = VALUE;
pos = index;
nextPos = index;
}
} else {
type = TokenType.END;
}
}
/**
* 次のトークンを返します。
*
* @return 次のトークン
*/
protected TokenType nextToken() {
switch (type) {
case QUOTED_VALUE:
for (int i = nextPos; i < length; i++) {
char c = value.charAt(i);
if (c == quote) {
i++;
if (i >= length) {
token = value.substring(pos, i);
type = END;
return QUOTED_VALUE;
} else if (value.charAt(i) == delimiter) {
token = value.substring(pos, i);
peek(i);
return QUOTED_VALUE;
}
}
}
token = value.substring(pos, length);
type = END;
return QUOTED_VALUE;
case VALUE:
for (int i = nextPos; i < length; i++) {
char c = value.charAt(i);
if (c == delimiter) {
token = value.substring(pos, i);
peek(i);
return VALUE;
}
}
token = value.substring(pos, length);
type = END;
return QUOTED_VALUE;
case DELIMITER:
token = value.substring(pos, nextPos);
peek(nextPos);
return DELIMITER;
case END:
token = null;
return END;
}
throw new IllegalStateException("type");
}
/**
* トークンを返します。
*
* @return トークン
*/
protected String getToken() {
return token;
}
}
}