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