/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.kernel.util; import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader; import com.liferay.portal.kernel.io.unsync.UnsyncStringReader; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; /** * <p> * This is a rewrite of java.util.Properties that is not synchronized and * natively supports non-ASCII encodings. It can also be configured to be * "safe", allowing the values to have new line characters. When stored to a * given BufferedWriter, "safe" properties will replace all new line characters * with a _SAFE_NEWLINE_CHARACTER_. * </p> * * <p> * In its current form, this is not intended to replace java.util.Properties for * reading properties flat files. This class is not thread-safe. * </p> * * @author Alexander Chow */ public class UnicodeProperties extends HashMap<String, String> { public UnicodeProperties() { _safe = false; } public UnicodeProperties(boolean safe) { _safe = safe; } public void fastLoad(String props) { if (Validator.isNull(props)) { return; } int x = props.indexOf(CharPool.NEW_LINE); int y = 0; while (x != -1) { put(props.substring(y, x)); y = x; x = props.indexOf(CharPool.NEW_LINE, y + 1); } put(props.substring(y)); } public String getProperty(String key) { return get(key); } public String getProperty(String key, String defaultValue) { String value = get(key); if (value == null) { return defaultValue; } else { return value; } } public boolean isSafe() { return _safe; } public void load(String props) throws IOException { if (Validator.isNull(props)) { return; } try (UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(new UnsyncStringReader(props))) { String line = null; while ((line = unsyncBufferedReader.readLine()) != null) { put(line); } } } public void put(String line) { line = line.trim(); if (_isComment(line)) { return; } int pos = line.indexOf(CharPool.EQUAL); if (pos == -1) { _log.error("Invalid property on line " + line); } else { String value = line.substring(pos + 1).trim(); if (_safe) { value = _decode(value); } setProperty(line.substring(0, pos).trim(), value); } } @Override public String put(String key, String value) { if (key == null) { return null; } if (value == null) { return super.remove(key); } return super.put(key, value); } @Override public void putAll(Map<? extends String, ? extends String> map) { for (Map.Entry<? extends String, ? extends String> entry : map.entrySet()) { put(entry.getKey(), entry.getValue()); } } @Override public String remove(Object key) { if (key == null) { return null; } return super.remove(key); } public String setProperty(String key, String value) { return put(key, value); } /** * @deprecated As of 7.0.0, replaced by {@link #toString} */ @Deprecated public String toSortedString() { return toString(); } @Override public String toString() { StringBundler sb = new StringBundler(4 * size()); Map<String, String> treeMap = new TreeMap<>(this); for (Map.Entry<String, String> entry : treeMap.entrySet()) { String value = entry.getValue(); if (Validator.isNull(value)) { continue; } if (_safe) { value = _encode(value); } sb.append(entry.getKey()); sb.append(StringPool.EQUAL); sb.append(value); sb.append(StringPool.NEW_LINE); } return sb.toString(); } /** * @deprecated As of 7.0.0, with no direct replacement */ @Deprecated protected int getToStringLength() { return -1; } private static String _decode(String value) { return StringUtil.replace( value, _SAFE_NEWLINE_CHARACTER, StringPool.NEW_LINE); } private static String _encode(String value) { String encodedValue = StringUtil.replace( value, StringPool.RETURN_NEW_LINE, _SAFE_NEWLINE_CHARACTER); return StringUtil.replace( encodedValue, new char[] {CharPool.NEW_LINE, CharPool.RETURN}, new String[] {_SAFE_NEWLINE_CHARACTER, _SAFE_NEWLINE_CHARACTER}); } private boolean _isComment(String line) { if (line.isEmpty() || (line.charAt(0) == CharPool.POUND)) { return true; } return false; } private static final String _SAFE_NEWLINE_CHARACTER = "_SAFE_NEWLINE_CHARACTER_"; private static final Log _log = LogFactoryUtil.getLog( UnicodeProperties.class); private final boolean _safe; }