bml configuration files - great for permissions!

Discussion in 'Resources' started by codename_B, Aug 30, 2011.

Thread Status:
Not open for further replies.
  1. Offline

    codename_B

    Code:java
    1.  
    2. package de.bananaco.config;
    3.  
    4. import java.io.BufferedReader;
    5. import java.io.BufferedWriter;
    6. import java.io.DataInputStream;
    7. import java.io.DataOutputStream;
    8. import java.io.File;
    9. import java.io.FileInputStream;
    10. import java.io.FileOutputStream;
    11. import java.io.InputStreamReader;
    12. import java.io.OutputStreamWriter;
    13. import java.util.ArrayList;
    14. import java.util.Arrays;
    15. import java.util.HashMap;
    16. import java.util.HashSet;
    17. import java.util.List;
    18. import java.util.Map;
    19. import java.util.Set;
    20. import java.util.TreeMap;
    21.  
    22. public class Configuration extends ConfigurationNode {
    23. public static final String tab = "\t";
    24. private final File file;
    25. public Configuration(String string) {
    26. super(new HashMap<String,Object>());
    27. this.file = new File(string);
    28. }
    29.  
    30. public Configuration(File file) {
    31. super(new HashMap<String, Object>());
    32. this.file = file;
    33. }
    34. private String convert(List<String> input) {
    35. String output = "";
    36. for(int i=0; i<input.size(); i++) {
    37. String in = input.get(i);
    38. in = in.replaceAll(":", "");
    39. if(i==input.size()-1)
    40. output = output+in;
    41. else
    42. output = output+in+".";
    43. }
    44. return output;
    45. }
    46. public void load() {
    47. try {
    48. if(!file.exists()) {
    49. file.getAbsoluteFile().getParentFile().mkdirs();
    50. file.createNewFile();
    51. }
    52. clear();
    53. readFile();
    54. }
    55. catch (Exception e) {
    56. e.printStackTrace();
    57. }
    58. }
    59.  
    60. public void save() {
    61. try {
    62. if(!file.exists()) {
    63. file.getAbsoluteFile().getParentFile().mkdirs();
    64. file.createNewFile();
    65. }
    66. saveFile();
    67. load();
    68. }
    69. catch (Exception e) {
    70. e.printStackTrace();
    71. }
    72. }
    73. private int count(String input) {
    74. int i=0;
    75. while(input.startsWith(":")) {
    76. input = input.replaceFirst(":", "");
    77. i++;
    78. }
    79. return i;
    80. }
    81. private void saveFile() throws Exception {
    82. ArrayList<String> output = new ArrayList<String>();
    83. HashSet<String> comments = new HashSet<String>();
    84.  
    85. if(this.getComment("") != null)
    86. output.add(getAndRemoveComment(""));
    87. for(String key : getAll().keySet()) {
    88. String[] split = key.split("\\.");
    89. for(int i=0; i<split.length; i++) {
    90. String line = "";
    91. for(int p=0; p<=i; p++)
    92. line = (p==i)?line + split[p]:line + split[p] + ".";
    93.  
    94. String addition = split[i]+":";
    95. for(int p=0; p<i; p++)
    96. addition = ":"+addition;
    97. for(int p=0; p<i; p++)
    98. addition = "\t"+addition;
    99. String tabs = "";
    100. for(int p=0; p<i; p++)
    101. tabs = "\t"+tabs;
    102.  
    103. String comment = getComment(line);
    104.  
    105. if(!output.contains(addition)) {
    106. output.add(addition);
    107. if(comment != null && !comments.contains(line))
    108. output.add(tabs + comment);
    109. comments.add(line);
    110. }
    111. }
    112. String addition = "";
    113. for(int p=0; p<split.length; p++)
    114. addition = "\t"+addition;
    115. List<String> props = this.getStringList(key);
    116. for(String prop : props)
    117. output.add(addition+prop);
    118. }
    119. for(String line : output)
    120. bw.write(line+"\r");
    121. bw.flush();
    122. bw.close();
    123. output.clear();
    124. comments.clear();
    125. }
    126. private String strip(String line) {
    127. while(line.contains("\t"))
    128. line = line.replace("\t", "");
    129. return line;
    130. }
    131. private void readFile() throws Exception {
    132. ArrayList<String> lines = new ArrayList<String>();
    133. ArrayList<String> pLines = new ArrayList<String>();
    134. String line;
    135. int lastNotComment = 0;
    136. while((line = br.readLine()) != null)
    137. lines.add(strip(line));
    138. br.close();
    139. for(int i=0; i<lines.size(); i++) {
    140. line = lines.get(i);
    141. if(line.startsWith("#")) {
    142. this.comment(convert(pLines), line);
    143. }
    144. else if(line.endsWith(":") && !line.startsWith(":")) {
    145. pLines.clear();
    146. pLines.add(line);
    147. lastNotComment = i;
    148. }
    149. else if(line.endsWith(":")) {
    150. int thiscount = count(line);
    151. for(int p=pLines.size()-1; p>=thiscount; p--)
    152. pLines.remove(p);
    153. pLines.add(line);
    154. lastNotComment = i;
    155. }
    156. else if(!line.endsWith(":") && i>0 && lines.get(lastNotComment).endsWith(":")) {
    157. lastNotComment = i;
    158. ArrayList<String> props = new ArrayList<String>();
    159. for(int p=i; !lines.get(p).endsWith(":"); p++) {
    160. props.add(lines.get(p));
    161. if(p+1==lines.size())
    162. break;
    163. }
    164. this.setProperty(this.convert(pLines), props);
    165. }
    166. }
    167. lines.clear();
    168. pLines.clear();
    169. }
    170.  
    171. }
    172. class ConfigurationNode extends CommentNode {
    173. protected Map<String, Object> root;
    174.  
    175. protected ConfigurationNode(Map<String, Object> root) {
    176. super(new HashMap<String, String>());
    177. this.root = root;
    178. }
    179.  
    180. /**
    181.   * Gets all of the cofiguration values within the Node as
    182.   * a key value pair, with the key being the full path and the
    183.   * value being the Object that is at the path.
    184.   *
    185.   * @return A map of key value pairs with the path as the key and the object as the value
    186.   */
    187. public Map<String, Object> getAll() {
    188. return recursiveBuilder(root);
    189. }
    190.  
    191. /**
    192.   * A helper method for the getAll method that deals with the recursion
    193.   * involved in traversing the tree
    194.   *
    195.   * @param node The map for that node of the tree
    196.   * @return The fully pathed map for that point in the tree, with the path as the key
    197.   */
    198. @SuppressWarnings("unchecked")
    199. protected Map<String, Object> recursiveBuilder(Map<String, Object> node) {
    200. Map<String, Object> map = new TreeMap<String, Object>();
    201.  
    202. Set<String> keys = node.keySet();
    203. for( String k : keys ) {
    204. Object tmp = node.get(k);
    205. if( tmp instanceof Map<?,?> ) {
    206. Map<String, Object> rec = recursiveBuilder((Map <String,Object>) tmp);
    207.  
    208. Set<String> subkeys = rec.keySet();
    209. for( String sk : subkeys ) {
    210. map.put(k + "." + sk, rec.get(sk));
    211. }
    212. }
    213. else {
    214. map.put(k, tmp);
    215. }
    216. }
    217.  
    218. return map;
    219. }
    220.  
    221. /**
    222.   * Gets a property at a location. This will either return an Object
    223.   * or null, with null meaning that no configuration value exists at
    224.   * that location. This could potentially return a default value (not yet
    225.   * implemented) as defined by a plugin, if this is a plugin-tied
    226.   * configuration.
    227.   *
    228.   * @param path path to node (dot notation)
    229.   * @return object or null
    230.   */
    231. @SuppressWarnings("unchecked")
    232. public Object getProperty(String path) {
    233. if (!path.contains(".")) {
    234. Object val = root.get(path);
    235.  
    236. if (val == null) {
    237. return null;
    238. }
    239. return val;
    240. }
    241.  
    242. String[] parts = path.split("\\.");
    243. Map<String, Object> node = root;
    244.  
    245. for (int i = 0; i < parts.length; i++) {
    246. Object o = node.get(parts[i]);
    247.  
    248. if (o == null) {
    249. return null;
    250. }
    251.  
    252. if (i == parts.length - 1) {
    253. return o;
    254. }
    255.  
    256. try {
    257. node = (Map<String, Object>) o;
    258. } catch (ClassCastException e) {
    259. return null;
    260. }
    261. }
    262.  
    263. return null;
    264. }
    265.  
    266. /**
    267.   * Set the property at a location. This will override existing
    268.   * configuration data to have it conform to key/value mappings.
    269.   *
    270.   * @param path
    271.   * @param value
    272.   */
    273. public void setProperty(String path, String value) {
    274. setProperty(path,Arrays.asList(value));
    275. }
    276. @SuppressWarnings("unchecked")
    277. public void setProperty(String path, List<String> value) {
    278. if (!path.contains(".")) {
    279. root.put(path, value);
    280. return;
    281. }
    282.  
    283. String[] parts = path.split("\\.");
    284. Map<String, Object> node = root;
    285.  
    286. for (int i = 0; i < parts.length; i++) {
    287. Object o = node.get(parts[i]);
    288.  
    289. // Found our target!
    290. if (i == parts.length - 1) {
    291. node.put(parts[i], value);
    292. return;
    293. }
    294.  
    295. if (o == null || !(o instanceof Map)) {
    296. // This will override existing configuration data!
    297. o = new HashMap<String, Object>();
    298. node.put(parts[i], o);
    299. }
    300.  
    301. node = (Map<String, Object>) o;
    302. }
    303. }
    304.  
    305. /**
    306.   * Get a list of keys at a location. If the map at the particular location
    307.   * does not exist or it is not a map, null will be returned.
    308.   *
    309.   * @param path path to node (dot notation)
    310.   * @return list of keys
    311.   */
    312. @SuppressWarnings("unchecked")
    313. public List<String> getKeys(String path) {
    314. if (path == null) {
    315. return new ArrayList<String>(root.keySet());
    316. }
    317. Object o = getProperty(path);
    318. if (o == null) {
    319. return null;
    320. } else if (o instanceof Map) {
    321. return new ArrayList<String>(((Map<String, Object>) o).keySet());
    322. } else {
    323. return null;
    324. }
    325. }
    326.  
    327. /**
    328.   * Returns a list of all keys at the root path
    329.   *
    330.   * @return List of keys
    331.   */
    332. public List<String> getKeys() {
    333. return new ArrayList<String>(root.keySet());
    334. }
    335.  
    336. /**
    337.   * Gets a list of objects at a location. If the list is not defined,
    338.   * null will be returned. The node must be an actual list.
    339.   *
    340.   * @param path path to node (dot notation)
    341.   * @return boolean or default
    342.   */
    343. @SuppressWarnings("unchecked")
    344. public List<Object> getList(String path) {
    345. Object o = getProperty(path);
    346.  
    347. if (o == null) {
    348. return null;
    349. } else if (o instanceof List) {
    350. return (List<Object>) o;
    351. } else {
    352. return null;
    353. }
    354. }
    355.  
    356. /**
    357.   * Gets a list of strings. Non-valid entries will not be in the list.
    358.   * There will be no null slots. If the list is not defined, the
    359.   * default will be returned. 'null' can be passed for the default
    360.   * and an empty list will be returned instead. If an item in the list
    361.   * is not a string, it will be converted to a string. The node must be
    362.   * an actual list and not just a string.
    363.   *
    364.   * @param path path to node (dot notation)
    365.   * @param def default value or null for an empty list as default
    366.   * @return list of strings
    367.   */
    368. public List<String> getStringList(String path) {
    369. return getStringList(path, null);
    370. }
    371. public List<String> getStringList(String path, List<String> def) {
    372. List<Object> raw = getList(path);
    373.  
    374. if (raw == null) {
    375. return def != null ? def : new ArrayList<String>();
    376. }
    377.  
    378. List<String> list = new ArrayList<String>();
    379.  
    380. for (Object o : raw) {
    381. if (o == null) {
    382. continue;
    383. }
    384.  
    385. list.add(o.toString());
    386. }
    387.  
    388. return list;
    389. }
    390.  
    391. /**
    392.   * Gets a list of nodes. Non-valid entries will not be in the list.
    393.   * There will be no null slots. If the list is not defined, the
    394.   * default will be returned. 'null' can be passed for the default
    395.   * and an empty list will be returned instead. The node must be
    396.   * an actual node and cannot be just a boolean,
    397.   *
    398.   * @param path path to node (dot notation)
    399.   * @param def default value or null for an empty list as default
    400.   * @return list of integers
    401.   */
    402. @SuppressWarnings("unchecked")
    403. public List<ConfigurationNode> getNodeList(String path, List<ConfigurationNode> def) {
    404. List<Object> raw = getList(path);
    405.  
    406. if (raw == null) {
    407. return def != null ? def : new ArrayList<ConfigurationNode>();
    408. }
    409.  
    410. List<ConfigurationNode> list = new ArrayList<ConfigurationNode>();
    411.  
    412. for (Object o : raw) {
    413. if (o instanceof Map) {
    414. list.add(new ConfigurationNode((Map<String, Object>) o));
    415. }
    416. }
    417.  
    418. return list;
    419. }
    420.  
    421. /**
    422.   * Get a configuration node at a path. If the node doesn't exist or the
    423.   * path does not lead to a node, null will be returned. A node has
    424.   * key/value mappings.
    425.   *
    426.   * @param path
    427.   * @return node or null
    428.   */
    429. @SuppressWarnings("unchecked")
    430. public ConfigurationNode getNode(String path) {
    431. Object raw = getProperty(path);
    432.  
    433. if (raw instanceof Map) {
    434. return new ConfigurationNode((Map<String, Object>) raw);
    435. }
    436.  
    437. return null;
    438. }
    439.  
    440. /**
    441.   * Get a list of nodes at a location. If the map at the particular location
    442.   * does not exist or it is not a map, null will be returned.
    443.   *
    444.   * @param path path to node (dot notation)
    445.   * @return map of nodes
    446.   */
    447. @SuppressWarnings("unchecked")
    448. public Map<String, ConfigurationNode> getNodes(String path) {
    449. Object o = getProperty(path);
    450.  
    451. if (o == null) {
    452. return null;
    453. } else if (o instanceof Map) {
    454. Map<String, ConfigurationNode> nodes = new HashMap<String, ConfigurationNode>();
    455.  
    456. for (Map.Entry<String, Object> entry : ((Map<String, Object>) o).entrySet()) {
    457. if (entry.getValue() instanceof Map) {
    458. nodes.put(entry.getKey(), new ConfigurationNode((Map<String, Object>) entry.getValue()));
    459. }
    460. }
    461.  
    462. return nodes;
    463. } else {
    464. return null;
    465. }
    466. }
    467.  
    468. /**
    469.   * Remove the property at a location. This will override existing
    470.   * configuration data to have it conform to key/value mappings.
    471.   *
    472.   * @param path
    473.   */
    474. @SuppressWarnings("unchecked")
    475. public void removeProperty(String path) {
    476. if (!path.contains(".")) {
    477. root.remove(path);
    478. return;
    479. }
    480.  
    481. String[] parts = path.split("\\.");
    482. Map<String, Object> node = root;
    483.  
    484. for (int i = 0; i < parts.length; i++) {
    485. Object o = node.get(parts[i]);
    486.  
    487. // Found our target!
    488. if (i == parts.length - 1) {
    489. node.remove(parts[i]);
    490. return;
    491. }
    492.  
    493. node = (Map<String, Object>) o;
    494. }
    495. }
    496. }
    497. class CommentNode {
    498. public final Map<String, String> map;
    499. protected CommentNode(Map<String, String> map) {
    500. this.map = map;
    501. }
    502. public void clear() {
    503. map.clear();
    504. }
    505. public void comment(String node, String comment) {
    506. if(map.containsKey(node))
    507. map.put(node, map.get(node)+"\r#"+comment.replace("#", ""));
    508. else
    509. map.put(node, "#"+comment.replace("#", ""));
    510. }
    511. public String getAndRemoveComment(String node) {
    512. if(!map.containsKey(node))
    513. return null;
    514. String comment = map.get(node);
    515. map.remove(node);
    516. return comment;
    517. }
    518. public String getComment(String node) {
    519. if(!map.containsKey(node))
    520. return null;
    521. String comment = map.get(node);
    522. return comment;
    523. }
    524. }
    525. [/i][/i][/i][/i][/i][/i][/i]


    You use it similarly to bukkit's own Configuration but it only stores List<String>
    On the up side, it also supports commented configs, and comments that persist on load/save.
    It's also faster than bukkit's built in configuration.
     
  2. Offline

    captainawesome7

    Yay now I can make a plugin with BML :D
    How can you tell that it is faster than Bukkit's built in config?
    *Edit*
    Wait a minute, when you copy+paste the Java syntax block it includes the Line #s
    Code block pl0x?
    Jk I'm retarded.

    One problem. If I want to comment a file like "#Last Ran: *date/time here* how do I overwrite a comment already made. I tried config.comment("LastRan", sdf.format(cal.getTime())); but it doesn't work...

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 19, 2016
  3. I have two requests:
    1. Could you add something like boolean configExists() - this would be usefull to create a default config file if it doesn't exist.
    2. Could you make a bml library? So that other plugins can use the library instead of including the classfile.

    //EDIT: arrgh, sorry... -.-

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 19, 2016
  4. Offline

    codename_B

    Good point - I should make a way to clear comments. I'll work on it :)
     
  5. Offline

    captainawesome7

    Awesome. I'm definitely using BML for any plugin that requires storage of a String list
     
  6. Offline

    feildmaster

    I see you didn't use my cleaned up code. :p
     
  7. Offline

    codename_B

    Not till I clean it up :p
     
  8. Offline

    wwsean08

    this is going to make my life so much easier, thanks
     
  9. Offline

    codename_B

    You should use YAML instead, this was a failed project.
     
  10. Offline

    feildmaster

    Failed? What happened to it?
     
  11. Offline

    wwsean08

    Ok, good to know, the main reason I was gonna use this was because I saw it come up on the front page of resources lol.
     
  12. Offline

    codename_B

    The files themselves work fine, I was just ripped into for inventing a formatting language when YAML works just fine.
     
Thread Status:
Not open for further replies.

Share This Page