You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

StoredUserConfig.java 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * Copyright 2021 gitblit.com, Ingo Lafrenz
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.gitblit;
  17. import java.io.File;
  18. import java.io.FileWriter;
  19. import java.io.IOException;
  20. import java.io.PrintWriter;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.Objects;
  24. import java.util.SortedMap;
  25. import java.util.TreeMap;
  26. /**
  27. * Simple class with the only purpose to save the realm file (users.conf) in
  28. * a fast efficient manner. The JGit Config classes used previously caused
  29. * a massive CPU hog if the users file got bigger than about 30000 lines.
  30. *
  31. * @author Ingo Lafrenz
  32. *
  33. */
  34. public class StoredUserConfig {
  35. private final File realmFileCopy;
  36. private SortedMap<String, Section> sections = new TreeMap<>();
  37. public StoredUserConfig(File realmFileCopy) {
  38. this.realmFileCopy = realmFileCopy;
  39. }
  40. public void setString(final String section, final String subsection, String name, String value) {
  41. String key = generateKey(section, subsection);
  42. Section s = sections.get(key);
  43. if (s == null) {
  44. s = new Section(section, subsection);
  45. sections.put(key, s);
  46. }
  47. s.addEntry(name, value);
  48. }
  49. public void setBoolean(String section, String subsection, String name, boolean value) {
  50. setString(section, subsection, name, String.valueOf(value));
  51. }
  52. public void setStringList(String section, String subsection, String name, List<String> list) {
  53. for (String value : list) {
  54. setString(section, subsection, name, value);
  55. }
  56. }
  57. public void save() throws IOException {
  58. try (FileWriter fileWriter = new FileWriter(realmFileCopy);
  59. PrintWriter printWriter = new PrintWriter(fileWriter);) {
  60. for (Map.Entry<String,Section> entry : sections.entrySet()) {
  61. writeSection(printWriter, entry.getKey(), entry.getValue());
  62. }
  63. }
  64. }
  65. private static void writeSection(PrintWriter printWriter, String key, Section section) {
  66. if (section.getSubSection() == null) {
  67. printWriter.printf("[%s]\n", section.getName());
  68. }
  69. else {
  70. printWriter.printf("[%s \"%s\"]\n", section.getName(), section.getSubSection());
  71. }
  72. for (Entry entry : section.getEntries().values()) {
  73. writeEntry(printWriter, entry.getKey(), entry.getValue());
  74. }
  75. }
  76. private static void writeEntry(PrintWriter printWriter, String key, String value) {
  77. printWriter.printf("\t%s = %s\n", key, escape(value));
  78. }
  79. private static String escape(String value) {
  80. boolean quoteIt = false;
  81. StringBuilder fixedValue = new StringBuilder(value.length() + 20);
  82. for (char c : value.toCharArray()) {
  83. switch (c) {
  84. case '\n':
  85. fixedValue.append("\\n");
  86. break;
  87. case '\t':
  88. fixedValue.append("\\t");
  89. break;
  90. case '\b':
  91. fixedValue.append("\\b");
  92. break;
  93. case '\\':
  94. fixedValue.append("\\\\");
  95. break;
  96. case '"':
  97. fixedValue.append("\\\"");
  98. break;
  99. case ';':
  100. case '#':
  101. quoteIt = true;
  102. fixedValue.append(c);
  103. break;
  104. default:
  105. fixedValue.append(c);
  106. break;
  107. }
  108. }
  109. if (quoteIt) {
  110. fixedValue.insert(0,"\"");
  111. fixedValue.append("\"");
  112. }
  113. return fixedValue.toString();
  114. }
  115. private static String generateKey(String key, String subKey) {
  116. return "k:" + key + "s:" + (subKey == null ? "" : subKey);
  117. }
  118. private static class Section {
  119. private final String name;
  120. private final String subSection;
  121. private final SortedMap<String, Entry> entries = new TreeMap<>();
  122. public Section(String name, String subSection) {
  123. this.name = name;
  124. this.subSection = subSection;
  125. }
  126. public void addEntry(final String key, final String value) {
  127. entries.put(generateKey(key, value), new Entry(key, value));
  128. }
  129. public String getName() {
  130. return name;
  131. }
  132. public String getSubSection() {
  133. return subSection;
  134. }
  135. public SortedMap<String, Entry> getEntries() {
  136. return entries;
  137. }
  138. @Override
  139. public int hashCode() {
  140. return Objects.hash(name, subSection);
  141. }
  142. @Override
  143. public boolean equals(Object obj) {
  144. if (this == obj)
  145. return true;
  146. if (obj == null)
  147. return false;
  148. if (getClass() != obj.getClass())
  149. return false;
  150. Section other = (Section) obj;
  151. return Objects.equals(name, other.name) && Objects.equals(subSection, other.subSection);
  152. }
  153. @Override
  154. public String toString() {
  155. return String.format("Section [name=%s, subSection=%s]", name, subSection);
  156. }
  157. }
  158. private static class Entry {
  159. private final String key;
  160. private final String value;
  161. public Entry(String key, String value) {
  162. this.key = key;
  163. this.value = value;
  164. }
  165. public String getKey() {
  166. return key;
  167. }
  168. public String getValue() {
  169. return value;
  170. }
  171. @Override
  172. public int hashCode() {
  173. return Objects.hash(key, value);
  174. }
  175. @Override
  176. public boolean equals(Object obj) {
  177. if (this == obj)
  178. return true;
  179. if (obj == null)
  180. return false;
  181. if (getClass() != obj.getClass())
  182. return false;
  183. Entry other = (Entry) obj;
  184. return Objects.equals(key, other.key) && Objects.equals(value, other.value);
  185. }
  186. @Override
  187. public String toString() {
  188. return String.format("Entry [key=%s, value=%s]", key, value);
  189. }
  190. }
  191. }