All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dbflute.helper.mapstring.MapListString Maven / Gradle / Ivy

There is a newer version: 1.2.8
Show newest version
/*
 * Copyright 2014-2019 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.dbflute.helper.mapstring;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.dbflute.exception.MapListStringDuplicateEntryException;
import org.dbflute.exception.MapListStringParseFailureException;
import org.dbflute.helper.message.ExceptionMessageBuilder;

/**
 * The string for map and list.
 * 
 * e.g. map-string
 *   map:{key1=value1;key2=list:{value21;value22;value23};key3=map:{key31=value31}}
 * 
 * e.g. list-string
 *   list:{key1=value1;key2=list:{value21;value22;value23};key3=map:{key31=value31}}
 * 
* @author jflute */ public class MapListString { // this code was written when jflute was very young // (the code has small modifications only after created) // =================================================================================== // Definition // ========== /** The default mark of map value. */ public static final String DEFAULT_MAP_MARK = "map:"; /** The default mark of list value. */ public static final String DEFAULT_LIST_MARK = "list:"; /** The default control mark of start-brace. */ public static final String DEFAULT_START_BRACE = "{"; /** The default control mark of end-brace. */ public static final String DEFAULT_END_BRACE = "}"; /** The default control mark of delimiter. */ public static final String DEFAULT_DELIMITER = ";"; /** The default control mark of equal. */ public static final String DEFAULT_EQUAL = "="; /** The escape character for control marks. */ protected static final String ESCAPE_CHAR = "\\"; /** The temporary mark of escaped escape character. */ protected static final String ESCAPED_ESCAPE_MARK = "$$df:escapedEscape$$"; // =================================================================================== // Attribute // ========= // ----------------------------------------------------- // Component // --------- /** The mark of map. (NotNull: but changeable) */ protected String _mapMark; /** The mark of list. (NotNull: but changeable) */ protected String _listMark; /** The control mark of start brace. (NotNull: but changeable) */ protected String _startBrace; /** The control mark of end brace. (NotNull: but changeable) */ protected String _endBrace; /** The control mark of delimiter. (NotNull: but changeable) */ protected String _delimiter; /** The control mark of equal for map-string. (NotNull: but changeable) */ protected String _equal; /** The escape character for control marks. (NotNull) */ protected final String _escapeChar; // ----------------------------------------------------- // Temporary // --------- /** The string of top (full) string as temporary variable for generation. (NullAllowed: depends on process) */ protected String _topString; /** The string of remainder as temporary variable for generation. (NullAllowed: depends on process) */ protected String _remainderString; // ----------------------------------------------------- // Option // ------ /** Does it check duplicate entry of map for generation? */ protected boolean _checkDuplicateEntry; /** Does it print as one-liner for building? */ protected boolean _printOneLiner; // =================================================================================== // Constructor // =========== /** * Constructor setting as default.
* You can change marks by setters after creation. */ public MapListString() { _mapMark = DEFAULT_MAP_MARK; _listMark = DEFAULT_LIST_MARK; _startBrace = DEFAULT_START_BRACE; _endBrace = DEFAULT_END_BRACE; _delimiter = DEFAULT_DELIMITER; _equal = DEFAULT_EQUAL; _escapeChar = ESCAPE_CHAR; // fixed for now } // =================================================================================== // Build String // ============ /** * Build map-string from the map object. * @param map The map object that has string keys. (NotNull) * @return The string as map expression. (NotNull) */ public String buildMapString(Map map) { final StringBuilder sb = new StringBuilder(); @SuppressWarnings("unchecked") final Map casted = (Map) map; final boolean printOneLiner = isPrintOneLiner(); doBuildMapString(sb, casted, printOneLiner, "", printOneLiner ? "" : " "); return sb.toString(); } protected void doBuildMapString(StringBuilder sb, Map map, boolean printOneLiner, String preIndent, String curIndent) { sb.append(_mapMark).append(_startBrace); if (!map.isEmpty()) { int index = 0; for (Entry entry : map.entrySet()) { final String key = entry.getKey(); final Object value = entry.getValue(); if (printOneLiner) { if (index > 0) { sb.append(" ").append(_delimiter); } } else { sb.append(ln()).append(curIndent).append(_delimiter); } sb.append(" ").append(escapeControlMark(key)).append(" ").append(_equal).append(" "); if (value instanceof Map) { @SuppressWarnings("unchecked") final Map valueMap = (Map) value; final String nextIndent = printOneLiner ? "" : calculateNextIndent(preIndent, curIndent); doBuildMapString(sb, valueMap, printOneLiner, curIndent, nextIndent); } else if (value instanceof List) { @SuppressWarnings("unchecked") final List valueList = (List) value; final String nextIndent = printOneLiner ? "" : calculateNextIndent(preIndent, curIndent); doBuildListString(sb, valueList, printOneLiner, curIndent, nextIndent); } else { sb.append(escapeControlMark(value)); } ++index; } if (printOneLiner) { sb.append(" "); } else { sb.append(ln()).append(preIndent); } } sb.append(_endBrace); } /** * Build list-string from the list object. * @param list The list object that has object elements. (NotNull) * @return The string as list expression. (NotNull) */ public String buildListString(List list) { final StringBuilder sb = new StringBuilder(); @SuppressWarnings("unchecked") final List casted = (List) list; final boolean printOneLiner = isPrintOneLiner(); doBuildListString(sb, casted, printOneLiner, "", printOneLiner ? "" : " "); return sb.toString(); } protected void doBuildListString(StringBuilder sb, List list, boolean printOneLiner, String preIndent, String curIndent) { sb.append(_listMark).append(_startBrace); if (!list.isEmpty()) { int index = 0; for (Object value : list) { if (printOneLiner) { if (index > 0) { sb.append(" ").append(_delimiter); } } else { sb.append(ln()).append(curIndent).append(_delimiter); } sb.append(" "); if (value instanceof Map) { @SuppressWarnings("unchecked") final Map valueMap = (Map) value; final String nextIndent = printOneLiner ? "" : calculateNextIndent(preIndent, curIndent); doBuildMapString(sb, valueMap, printOneLiner, curIndent, nextIndent); } else if (value instanceof List) { @SuppressWarnings("unchecked") final List valueList = (List) value; final String nextIndent = printOneLiner ? "" : calculateNextIndent(preIndent, curIndent); doBuildListString(sb, valueList, printOneLiner, curIndent, nextIndent); } else { sb.append(escapeControlMark(value)); } ++index; } if (printOneLiner) { sb.append(" "); } else { sb.append(ln()).append(preIndent); } } sb.append(_endBrace); } protected String calculateNextIndent(String preIndent, String curIndent) { final StringBuilder sb = new StringBuilder(); sb.append(curIndent); final int indentLength = curIndent.length() - preIndent.length(); for (int i = 0; i < indentLength; i++) { sb.append(" "); } return sb.toString(); } // =================================================================================== // Generate Object // =============== /** * Generate map object from the map-string. * @param mapString The string as map expression. (NotNull) * @return The generated map. (NotNull) */ public Map generateMap(String mapString) { assertMapString(mapString); _topString = mapString; _remainderString = mapString; removeBothSideSpaceAndTabAndNewLine(); removePrefixMapMarkAndStartBrace(); final Map generatedMap = newStringObjectMap(); parseRemainderMapString(generatedMap); if (!"".equals(_remainderString)) { throwMapStringUnneededStringFoundException(mapString, generatedMap); } return generatedMap; } protected void throwMapStringUnneededStringFoundException(String mapString, Map generatedMap) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Final remainderString should be empty string but ..."); br.addItem("Remainder String"); br.addElement(_remainderString); br.addItem("Map String"); br.addElement(mapString); br.addItem("Generated Map"); br.addElement(generatedMap); prepareControlMarkMessage(br); final String msg = br.buildExceptionMessage(); throw new MapListStringParseFailureException(msg); } /** * Generate map object from list-string. * @param listString The string as list expression. (NotNull) * @return The generated list. (NotNull) */ public List generateList(String listString) { assertListString(listString); _topString = listString; _remainderString = listString; removeBothSideSpaceAndTabAndNewLine(); removePrefixListMarkAndStartBrace(); final List generatedList = newObjectList(); parseRemainderListString(generatedList); if (!"".equals(_remainderString)) { throwListStringUnneededStringFoundException(listString, generatedList); } return generatedList; } protected void throwListStringUnneededStringFoundException(String listString, List generatedList) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Final remainderString should be empty string but ..."); br.addItem("Remainder String"); br.addElement(_remainderString); br.addItem("List String"); br.addElement(listString); br.addItem("Generated List"); br.addElement(generatedList); prepareControlMarkMessage(br); final String msg = br.buildExceptionMessage(); throw new MapListStringParseFailureException(msg); } // =================================================================================== // Parse // ===== /** * Parse the current remainder string as map. * @param currentMap The current map made by parse process. (NotNull) */ protected void parseRemainderMapString(final Map currentMap) { while (true) { if (initializeAtLoopBeginning()) { return; } // *** now, _remainderString should starts with the key of the map *** final int equalIndex = indexOfEqual(); assertMapStringEqualIndex(_remainderString, equalIndex, _topString, currentMap); final String mapKey = _remainderString.substring(0, equalIndex).trim(); removePrefixTargetIndexPlus(equalIndex, _equal.length()); removeBothSideSpaceAndTabAndNewLine(); // *** now, _remainderString should starts with the value of the map *** if (isStartsWithMapPrefix(_remainderString)) { removePrefixMapMarkAndStartBrace(); parseRemainderMapString(setupNestMap(currentMap, mapKey)); if (closeAfterParseNestMapList()) { return; } continue; } if (isStartsWithListPrefix(_remainderString)) { removePrefixListMarkAndStartBrace(); parseRemainderListString(setupNestList(currentMap, mapKey)); if (closeAfterParseNestMapList()) { return; } continue; } final int delimiterIndex = indexOfDelimiter(); final int endBraceIndex = indexOfEndBrace(); assertMapStringEndBraceIndex(_remainderString, endBraceIndex, _topString, currentMap); if (delimiterIndex >= 0 && delimiterIndex < endBraceIndex) { // delimiter exists // e.g. value1 ; key2=value2} final String mapValue = _remainderString.substring(0, delimiterIndex); registerToMap(currentMap, filterMapListKey(mapKey), filterMapListValue(mapValue)); // because the map element continues since the delimiter, // skip the delimiter and continue the loop removePrefixTargetIndexPlus(delimiterIndex, _delimiter.length()); continue; } // e.g. value1} ; key2=value2} final String mapValue = _remainderString.substring(0, endBraceIndex); registerToMap(currentMap, filterMapListKey(mapKey), filterMapListValue(mapValue)); // analyzing map is over, so close and return. closeByEndBraceIndex(endBraceIndex); return; } } /** * Parse remainder list string. * @param currentList current list. */ protected void parseRemainderListString(final List currentList) { while (true) { if (initializeAtLoopBeginning()) { return; } // *** now, _remainderString should starts with the value of the list *** if (isStartsWithMapPrefix(_remainderString)) { removePrefixMapMarkAndStartBrace(); parseRemainderMapString(setupNestMap(currentList)); if (closeAfterParseNestMapList()) { return; } continue; } if (isStartsWithListPrefix(_remainderString)) { removePrefixListMarkAndStartBrace(); parseRemainderListString(setupNestList(currentList)); if (closeAfterParseNestMapList()) { return; } continue; } final int delimiterIndex = indexOfDelimiter(); final int endBraceIndex = indexOfEndBrace(); assertListStringEndBraceIndex(_remainderString, endBraceIndex, _topString, currentList); if (delimiterIndex >= 0 && delimiterIndex < endBraceIndex) { // delimiter exists // e.g. value1 ; value2 ; value3} final String listValue = _remainderString.substring(0, delimiterIndex); currentList.add(filterMapListValue(listValue)); // because the list element continues since the delimiter, // skip the delimiter and continue the loop. removePrefixTargetIndexPlus(delimiterIndex, _delimiter.length()); continue; } // e.g. value1}, value2, } final String listValue = _remainderString.substring(0, endBraceIndex); currentList.add(filterMapListValue(listValue)); // analyzing list is over, so close and return closeByEndBraceIndex(endBraceIndex); return; } } /** * Initialize at loop beginning. * @return Is is end? */ protected boolean initializeAtLoopBeginning() { // remove prefix delimiter (result string is always trimmed) removePrefixAllDelimiter(); if (_remainderString.equals("")) { // analyzing is over return true; } if (isStartsWithEndBrace(_remainderString)) { // analyzing current map is over removePrefixEndBrace(); return true; } return false; } /** * Close after parse nest map list. * @return Is is closed? */ protected boolean closeAfterParseNestMapList() { if (isStartsWithEndBrace(_remainderString)) { removePrefixEndBrace(); return true; } return false; } /** * Close by end-brace index. * @param endBraceIndex The index of end-brace. (NotMinus) */ protected void closeByEndBraceIndex(int endBraceIndex) { _remainderString = _remainderString.substring(endBraceIndex); removePrefixEndBrace(); } protected int indexOfStartBrace() { return findIndexOfControlMark(_remainderString, _startBrace); } protected int indexOfEndBrace() { return findIndexOfControlMark(_remainderString, _endBrace); } protected int indexOfDelimiter() { return findIndexOfControlMark(_remainderString, _delimiter); } protected int indexOfEqual() { return findIndexOfControlMark(_remainderString, _equal); } protected int findIndexOfControlMark(String remainderString, String controlMark) { String current = remainderString; if (isEscapeCharEscape()) { final String escapedEscapeChar = toEscapedMark(_escapeChar); current = replace(current, escapedEscapeChar, buildLengthSpace(escapedEscapeChar)); } int baseIndex = 0; while (true) { final int index = current.indexOf(controlMark); if (index < 0) { // not found return index; } if (index > 0) { final String lastChar = current.substring(index - 1, index); if (_escapeChar.equals(lastChar)) { // escaped final int nextIndex = index + _escapeChar.length(); baseIndex = baseIndex + nextIndex; current = current.substring(nextIndex); continue; } } return baseIndex + index; // found } } protected String buildLengthSpace(String value) { final StringBuilder sb = new StringBuilder(); for (int i = 0; i < value.length(); i++) { sb.append(" "); } return sb.toString(); } // =================================================================================== // Remove // ====== /** * Remove prefix map-mark and start-brace. */ protected void removePrefixMapMarkAndStartBrace() { removePrefix(_mapMark + _startBrace); } /** * Remove prefix list-mark and start-brace. */ protected void removePrefixListMarkAndStartBrace() { removePrefix(_listMark + _startBrace); } /** * Remove prefix delimiter. */ protected void removePrefixDelimiter() { removePrefix(_delimiter); } /** * Remove prefix end-brace. */ protected void removePrefixEndBrace() { removePrefix(_endBrace); } /** * Remove prefix as mark. * @param prefixString The string for prefix. (NotNull) */ protected void removePrefix(String prefixString) { if (_remainderString == null) { final String notice = "The remainderString should not be null."; throwMapListStringPrefixFailureException(notice, prefixString, _topString); } if (prefixString == null) { final String notice = "The prefixString should not be null."; throwMapListStringPrefixFailureException(notice, prefixString, _topString); } removeBothSideSpaceAndTabAndNewLine(); // deep (or unneeded?) check if (_remainderString.length() < prefixString.length()) { final String notice = "The remainderString length shuold be greater than the prefixString length."; throwMapListStringPrefixFailureException(notice, prefixString, _topString); } if (!_remainderString.startsWith(prefixString)) { final String notice = "The remainderString shuold start with the prefixString."; throwMapListStringPrefixFailureException(notice, prefixString, _topString); } _remainderString = _remainderString.substring(prefixString.length()); removeBothSideSpaceAndTabAndNewLine(); } protected void throwMapListStringPrefixFailureException(String notice, String prefixString, String mapString) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice(notice); br.addItem("Remainder String"); br.addElement(_remainderString); br.addItem("Prefix String"); br.addElement(prefixString); br.addItem("MapList String"); br.addElement(mapString); prepareControlMarkMessage(br); final String msg = br.buildExceptionMessage(); throw new MapListStringParseFailureException(msg); } /** * Remove prefix and all delimiters. */ protected void removePrefixAllDelimiter() { removeBothSideSpaceAndTabAndNewLine(); while (true) { if (!isStartsWithDelimiter(_remainderString)) { break; } if (isStartsWithDelimiter(_remainderString)) { removePrefixDelimiter(); removeBothSideSpaceAndTabAndNewLine(); } } } /** * Remove both side space and tab and new-line. */ protected void removeBothSideSpaceAndTabAndNewLine() { _remainderString = _remainderString.trim(); } /** * Remove prefix by the index and plus count. * @param index The base index. (NotMinus) * @param plusCount The plus count for index. (NotMinus) */ protected void removePrefixTargetIndexPlus(int index, int plusCount) { _remainderString = _remainderString.substring(index + plusCount); } // =================================================================================== // Filter // ====== protected String filterMapListKey(String value) { if (value == null) { return null; } value = value.trim(); value = unescapeControlMark(value); return (("".equals(value) || "null".equals(value)) ? null : value); } protected String filterMapListValue(String value) { if (value == null) { return null; } value = value.trim(); value = unescapeControlMark(value); return (("".equals(value) || "null".equals(value)) ? null : value); } // =================================================================================== // Determination // ============= /** * Does it start with the map-prefix? * @param targetString The target string to determine. (NotNull) * @return The determination, true or false. */ protected boolean isStartsWithMapPrefix(String targetString) { if (targetString == null) { String msg = "The argument 'targetString' should not be null."; throw new IllegalArgumentException(msg); } targetString = targetString.trim(); return targetString.startsWith(getMapPrefix()); } protected String getMapPrefix() { return _mapMark + _startBrace; } /** * Does it start with the list-prefix? * @param targetString The target-string to determine. (NotNull) * @return The determination, true or false. */ protected boolean isStartsWithListPrefix(String targetString) { if (targetString == null) { String msg = "The argument 'targetString' should not be null."; throw new IllegalArgumentException(msg); } targetString = targetString.trim(); return targetString.startsWith(_listMark + _startBrace); } protected String getListPrefix() { return _listMark + _startBrace; } /** * Does it start with the delimiter? * @param targetString The target string to determine. (NotNull) * @return The determination, true or false. */ protected boolean isStartsWithDelimiter(String targetString) { if (targetString == null) { String msg = "The argument 'targetString' should not be null."; throw new IllegalArgumentException(msg); } targetString = targetString.trim(); return targetString.startsWith(_delimiter); } /** * Does it start with end-brace? * @param targetString The target string to determine. (NotNull) * @return The determination, true or false. */ protected boolean isStartsWithEndBrace(String targetString) { if (targetString == null) { String msg = "The argument 'targetString' should not be null."; throw new IllegalArgumentException(msg); } targetString = targetString.trim(); return targetString.startsWith(_endBrace); } /** * Does it end with end-brace? * @param targetString The target string to determine. (NotNull) * @return The determination, true or false. */ protected boolean isEndsWithEndBrace(String targetString) { if (targetString == null) { String msg = "The argument 'targetString' should not be null."; throw new IllegalArgumentException(msg); } targetString = targetString.trim(); return targetString.endsWith(_endBrace); } // =================================================================================== // Setup MapList // ============= /** * Set up new-created nest map as element of the current map. * @param currentMap the current map to set up. (NotNull) * @param mapKey The key of nest map. (NotNull) * @return The new-created nest map. (NotNull) */ protected Map setupNestMap(Map currentMap, String mapKey) { final Map nestMap = newStringObjectMap(); registerToMap(currentMap, filterMapListKey(mapKey), nestMap); return nestMap; } /** * Set up new-created nest map as element of the current list. * @param currentList the current list to set up. (NotNull) * @return The new-created nest map. (NotNull) */ protected Map setupNestMap(List currentList) { final Map nestMap = newStringObjectMap(); currentList.add(nestMap); return nestMap; } /** * Set up new-created nest list as element of the current map. * @param currentMap the current map to set up. (NotNull) * @param mapKey The key of nest map. (NotNull) * @return The new-created nest list. (NotNull) */ protected List setupNestList(Map currentMap, String mapKey) { final List nestList = newObjectList(); registerToMap(currentMap, filterMapListKey(mapKey), nestList); return nestList; } /** * Set up new-created nest list as element of the current list. * @param currentList the current map to set up. (NotNull) * @return The new-created nest list. (NotNull) */ protected List setupNestList(List currentList) { final List nestList = newObjectList(); currentList.add(nestList); return nestList; } /** * New string-object map. * @return The new-created map. (NotNull) */ protected Map newStringObjectMap() { return new LinkedHashMap(); } /** * New object-type list. * @return The new-created list. (NotNull) */ protected List newObjectList() { return new ArrayList(); } // =================================================================================== // Map Registration // ================ protected void registerToMap(Map currentMap, String key, Object element) { doCheckDuplicateEntryIfNeeds(currentMap, key, element); currentMap.put(key, element); } protected void doCheckDuplicateEntryIfNeeds(Map currentMap, String key, Object element) { if (isCheckDuplicateEntry()) { if (currentMap.containsKey(key)) { throwMapStringDuplicateEntryFoundException(currentMap, key, element); } } } protected void throwMapStringDuplicateEntryFoundException(Map currentMap, String key, Object element) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Duplicate entry in the map string."); br.addItem("MapList String"); br.addElement(_topString); br.addItem("Already Registered Entry"); br.addElement(key); br.addElement(currentMap.get(key)); br.addItem("New Duplicate Entry"); br.addElement(key); if (element instanceof Map) { // might be lazy registered so might be empty (then not show) final Map map = (Map) element; if (!map.isEmpty()) { br.addElement(map); } } else { br.addElement(element); } prepareControlMarkMessage(br); final String msg = br.buildExceptionMessage(); throw new MapListStringDuplicateEntryException(msg); } // =================================================================================== // Escape // ====== /** * Escape control marks as plain string in the value. * @param value The value, might contain control marks. (NullAllowed: if null, return null) * @return The escaped string of the value. (NullAllowed: when the value is null) */ public String escapeControlMark(Object value) { // public for tools if (value == null) { return null; } String filtered = value.toString(); if (isEscapeCharEscape()) { filtered = replace(filtered, _escapeChar, toEscapedMark(_escapeChar)); } filtered = replace(filtered, _startBrace, toEscapedMark(_startBrace)); filtered = replace(filtered, _endBrace, toEscapedMark(_endBrace)); filtered = replace(filtered, _delimiter, toEscapedMark(_delimiter)); filtered = replace(filtered, _equal, toEscapedMark(_equal)); return filtered; } /** * Un-escape control marks as plain string in the value. * @param value The value, might contain escaped control marks. (NullAllowed: if null, return null) * @return The un-escaped string of the value. (NullAllowed: when the value is null) */ public String unescapeControlMark(String value) { // public for tools if (value == null) { return null; } String filtered = value; final String escapedEscapeMark = ESCAPED_ESCAPE_MARK; if (isEscapeCharEscape()) { filtered = replace(filtered, toEscapedMark(_escapeChar), escapedEscapeMark); } filtered = replace(filtered, toEscapedMark(_startBrace), _startBrace); filtered = replace(filtered, toEscapedMark(_endBrace), _endBrace); filtered = replace(filtered, toEscapedMark(_delimiter), _delimiter); filtered = replace(filtered, toEscapedMark(_equal), _equal); if (isEscapeCharEscape()) { filtered = replace(filtered, escapedEscapeMark, _escapeChar); } return filtered; } protected String toEscapedMark(String mark) { return _escapeChar + mark; } protected boolean isEscapeCharEscape() { // escape for escape char is unsupported (unneeded) // so fixedly returns false // // compatibility is treated as important here // o "\\n = \n" in convertValueMap.dfprop can directly work // o plain "\" is can directly work // // [specification] // escape char without control mark is treated as plain value // e.g. "a\b\c" // // previous escape char of control mark is always treated as escape char // e.g. "\;" // // if any spaces between the escape char and the control mark exist, // the escape char is plain value, e.g. "\ ;" // return false; } // =================================================================================== // Assert Helper // ============= protected void assertMapString(String mapString) { if (mapString == null) { final String notice = "The map string should not be null."; throwMapStringBasicFailureException(notice, mapString); } mapString = mapString.trim(); if (!isStartsWithMapPrefix(mapString)) { final String notice = "The map string should start with '" + getMapPrefix() + "'."; throwMapStringBasicFailureException(notice, mapString); } if (!isEndsWithEndBrace(mapString)) { final String notice = "The map string should end with '" + _endBrace + "'."; throwMapStringBasicFailureException(notice, mapString); } final int startBraceCount = getControlMarkCount(mapString, _startBrace); final int endBraceCount = getControlMarkCount(mapString, _endBrace); if (startBraceCount != endBraceCount) { throwMapStringDifferentCountBracesException(mapString, startBraceCount, endBraceCount); } } protected void throwMapStringBasicFailureException(String notice, String mapString) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice(notice); br.addItem("Remainder String"); br.addElement(_remainderString); br.addItem("Map String"); br.addElement(mapString); prepareControlMarkMessage(br); final String msg = br.buildExceptionMessage(); throw new MapListStringParseFailureException(msg); } protected void throwMapStringDifferentCountBracesException(String mapString, int startCount, int endCount) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Different count between start braces and end braces."); br.addItem("Advice"); br.addElement("Make sure braces on your map-list string."); br.addElement("For example:"); br.addElement(" (o): map:{ foo = bar }"); br.addElement(" (o): map:{ foo = map:{ bar = qux } }"); br.addElement(" (x): map:{ foo = "); br.addElement(" (x): map:{ foo = map:{ }"); br.addElement(""); br.addElement("map-list string can escape control marks"); br.addElement("so pay attention to last char of value like this:"); br.addElement(" (x): map:{ foo = C:\\foo\\bar\\} // last '}' escaped by escape char"); br.addElement(" (o): map:{ foo = C:\\foo\\bar\\ } // space helps you at the case"); br.addItem("Map String"); br.addElement(mapString); br.addItem("Brace Count"); br.addElement("start: " + startCount); br.addElement("end: " + endCount); prepareControlMarkMessage(br); final String msg = br.buildExceptionMessage(); throw new MapListStringParseFailureException(msg); } protected void assertListString(String listString) { if (listString == null) { final String notice = "The list string should not be null."; throwListStringBasicFailureException(notice, listString); } listString = listString.trim(); if (!isStartsWithListPrefix(listString)) { final String notice = "The list string should start with '" + getListPrefix() + "'."; throwListStringBasicFailureException(notice, listString); } if (!isEndsWithEndBrace(listString)) { final String notice = "The list string should end with '" + _endBrace + "'."; throwListStringBasicFailureException(notice, listString); } final int startBraceCount = getControlMarkCount(listString, _startBrace); final int endBraceCount = getControlMarkCount(listString, _endBrace); if (startBraceCount != endBraceCount) { throwListStringDifferentCountBracesException(listString, startBraceCount, endBraceCount); } } protected void throwListStringBasicFailureException(String notice, String listString) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice(notice); br.addItem("Remainder String"); br.addElement(_remainderString); br.addItem("List String"); br.addElement(listString); prepareControlMarkMessage(br); final String msg = br.buildExceptionMessage(); throw new MapListStringParseFailureException(msg); } protected void throwListStringDifferentCountBracesException(String listString, int startCount, int endCount) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Different count between start braces and end braces."); br.addItem("List String"); br.addElement(listString); br.addItem("Brace Count"); br.addElement("Start: " + startCount); br.addElement("End: " + endCount); prepareControlMarkMessage(br); final String msg = br.buildExceptionMessage(); throw new MapListStringParseFailureException(msg); } protected int getControlMarkCount(String targetString, String controlMark) { int result = 0; String current = targetString; while (true) { final int index = findIndexOfControlMark(current, controlMark); if (index < 0) { break; } result++; current = current.substring(index + controlMark.length()); } if (result == 0) { result = -1; } return result; } protected void assertMapStringEqualIndex(String remainderString, int equalIndex, String mapString, Map currentMap) { if (remainderString == null) { final String notice = "The remainderString should not be null:"; throwMapStringEqualFailureException(notice, remainderString, equalIndex, mapString, currentMap); } if (equalIndex < 0) { final String notice = "Not found the equal mark in the map."; throwMapStringEqualFailureException(notice, remainderString, equalIndex, mapString, currentMap); } // deep (or unneeded?) check (written by younger jflute) if (remainderString.length() < equalIndex) { final String notice = "The remainderString length should be greater than equalIndex:"; throwMapStringEqualFailureException(notice, remainderString, equalIndex, mapString, currentMap); } final String extractedMark = remainderString.substring(equalIndex, equalIndex + _equal.length()); if (!extractedMark.equals(_equal)) { final String notice = "The remainderString should have equal mark at equalIndex:"; throwMapStringEqualFailureException(notice, remainderString, equalIndex, mapString, currentMap); } } protected void throwMapStringEqualFailureException(String notice, String remainderMapString, int equalIndex, String mapString, Map currentMap) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice(notice); br.addItem("Remainder String"); br.addElement(remainderMapString); br.addItem("Equal Index"); br.addElement(equalIndex); br.addItem("Whole Map String"); br.addElement(mapString); br.addItem("Making Map"); br.addElement(currentMap); prepareControlMarkMessage(br); final String msg = br.buildExceptionMessage(); throw new MapListStringParseFailureException(msg); } protected void assertMapStringEndBraceIndex(String remainderString, int endBraceIndex, String mapString, Map currentMap) { if (remainderString == null) { final String notice = "The remainderString should not be null:"; throwMapStringEndBraceFailureException(notice, remainderString, endBraceIndex, mapString, currentMap); } if (endBraceIndex < 0) { final String notice = "Not found the end brace."; throwMapStringEndBraceFailureException(notice, remainderString, endBraceIndex, mapString, currentMap); } // deep (or unneeded?) check (written by younger jflute) if (remainderString.length() < endBraceIndex) { final String notice = "The remainderString length should be greater than endMarkIndex:"; throwMapStringEndBraceFailureException(notice, remainderString, endBraceIndex, mapString, currentMap); } final String extractedMark = remainderString.substring(endBraceIndex, endBraceIndex + _endBrace.length()); if (!extractedMark.equals(_endBrace)) { final String notice = "The remainderString should have end brace at the endMarkIndex:"; throwMapStringEndBraceFailureException(notice, remainderString, endBraceIndex, mapString, currentMap); } } protected void assertListStringEndBraceIndex(String remainderString, int endBraceIndex, String listString, List currentList) { if (remainderString == null) { final String notice = "The remainderString should not be null:"; throwListStringEndBraceFailureException(notice, remainderString, endBraceIndex, listString, currentList); } if (endBraceIndex < 0) { final String notice = "Not found the end brace."; throwListStringEndBraceFailureException(notice, remainderString, endBraceIndex, listString, currentList); } // deep (or unneeded?) check (written by younger jflute) if (remainderString.length() < endBraceIndex) { final String notice = "The remainderString length should be greater than endMarkIndex:"; throwListStringEndBraceFailureException(notice, remainderString, endBraceIndex, listString, currentList); } final String extractedMark = remainderString.substring(endBraceIndex, endBraceIndex + _endBrace.length()); if (!extractedMark.equals(_endBrace)) { final String notice = "The remainderString should have end brace at the endMarkIndex:"; throwListStringEndBraceFailureException(notice, remainderString, endBraceIndex, listString, currentList); } } protected void throwMapStringEndBraceFailureException(String notice, String remainderMapString, int equalIndex, String mapString, Map currentMap) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice(notice); br.addItem("Remainder Map String"); br.addElement(remainderMapString); br.addItem("EndBrace Index"); br.addElement(equalIndex); br.addItem("Whole Map String"); br.addElement(mapString); br.addItem("Making Map"); br.addElement(currentMap); prepareControlMarkMessage(br); final String msg = br.buildExceptionMessage(); throw new MapListStringParseFailureException(msg); } protected void throwListStringEndBraceFailureException(String notice, String remainderMapString, int equalIndex, String listString, List currentList) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice(notice); br.addItem("Remainder List String"); br.addElement(remainderMapString); br.addItem("EndBrace Index"); br.addElement(equalIndex); br.addItem("Whole List String"); br.addElement(listString); br.addItem("Making List"); br.addElement(currentList); prepareControlMarkMessage(br); final String msg = br.buildExceptionMessage(); throw new MapListStringParseFailureException(msg); } protected void prepareControlMarkMessage(final ExceptionMessageBuilder br) { br.addItem("Control Marks"); br.addElement(_startBrace + " " + _endBrace + " " + _delimiter + " " + _equal); } // =================================================================================== // General Helper // ============== protected String replace(String str, String fromStr, String toStr) { StringBuilder sb = null; // lazy load int pos = 0; int pos2 = 0; do { pos = str.indexOf(fromStr, pos2); if (pos2 == 0 && pos < 0) { // first loop and not found return str; // without creating StringBuilder } if (sb == null) { sb = new StringBuilder(); } if (pos == 0) { sb.append(toStr); pos2 = fromStr.length(); } else if (pos > 0) { sb.append(str.substring(pos2, pos)); sb.append(toStr); pos2 = pos + fromStr.length(); } else { // (pos < 0) second or after loop only sb.append(str.substring(pos2)); return sb.toString(); } } while (true); } protected String ln() { return "\n"; } // =================================================================================== // Accessor // ======== public void setMapMark(String mapMark) { _mapMark = mapMark; } public void setListMark(String listMark) { _listMark = listMark; } public void setStartBrace(String startBrace) { _startBrace = startBrace; } public void setEndBrace(String endBrace) { _endBrace = endBrace; } public void setDelimiter(String delimiter) { _delimiter = delimiter; } public void setEqual(String equal) { _equal = equal; } // ----------------------------------------------------- // Option // ------ /** * Check duplicate entry of map for generation. (throws exception if found) * @return this; */ public MapListString checkDuplicateEntry() { _checkDuplicateEntry = true; return this; } public boolean isCheckDuplicateEntry() { return _checkDuplicateEntry; } /** * Print as one liner for building. * @return this; */ public MapListString printOneLiner() { _printOneLiner = true; return this; } public boolean isPrintOneLiner() { return _printOneLiner; } }